11


6

SQLのORDER BYの遅さ

`ORDER BY`は一般的にかなり遅いというのは本当ですか? 私は、WHERE句が非常に単純なSQL文をいくつか実行しようとしていますが、その後、VARCHAR(50)インデックス付きカラムに対してORDER BYを試みています。

表示上の理由でアルファベット順にソートする必要があります。 私は、データベースを使って自分のためにそれを実行することが最も効率的であると考えました。

この時点で、私はどちらかを探しています

  • SQLクエリを最適化する

  • 結果セットをコードでソートする

これが私が実行しようとしている実際のクエリです。

// B.SYNTAX is a TEXT/CLOB field
// Indexes on NAME, MODULENAME. PREVIOUS is a CHAR(1) with no index
"SELECT A.NAME, B.SYNTAX, B.DESCRIPTION, A.RATE1, A.RATE2,
A.RATE3, A.STARTDATE, A.ENDDATE, A.HIDE, A.CATEGORYNAME
FROM A, B WHERE A.MODULENAME='"+loadedModuleName+"'
AND A.NAME = B.NAME AND (A.PREVIOUS<>'N' OR A.PREVIOUS IS NULL)
ORDER BY A.NAME"

テーブルAのサイズは約2000行、Bは約500行です。

私たちは複数のデータベースをサポートしているので、データベース固有の最適化はあまりできないことにも言及する必要があります。 また、アプリケーションは顧客サイトに配置されます。

何百ものレコードが返されることを期待しています(1000未満)。

あなたならどうしますか? 任意のヒントは大歓迎です。 ありがとう。

14 Answer


8


インデックス付きフィールドでの並べ替えは、インデックス順にデータを取得できるため、遅くはなりません。 データベース構造(DDL)と実際のクエリに関する情報を提供して、他の人が見られるようにすることをお勧めします。

可能であれば、コードのソートではなくSQLのソートを使用してください。

*更新:*わかりました、いくつかのこと。 1つ目は、各クエリを一意にし、オプティマイザを台無しにするため、 "loadedModuleName"構文を使用しないでください。 パラメータを使用してください。 第二に、あなたのOrder by句はそれがテーブルAかBかについて曖昧です - これを明示的にしてインデックス付きのテーブルを選択してください(両方ともインデックスを持っていてもそれを明示的にしてください)。 最後に、あなたの "Previous"フィールドはchar(1)であってもインデックスをつけることができます。 最後の推奨インデックス、テスト速度以外はすべて実行し、それでもまだ遅い場合は、インデックスを探してもう一度確認します。

  • UPDATE *それでは、1000レコード未満を返すことになりますが、テーブルの合計サイズはいくらですか?

*更新*ああ、男、私は前にこれをキャッチしなかったのは残念です。 SQL Serverに正しく配置する場合は、クエリは次のようになります。

A.ANAME、B.SYNTAX、B.DESCRIPTION、A.RATE1、A.RATE2、A.RATE3、A.STARTDATE、A.ENDDATE、A.HIDE、A.CATEGORYNAMEをTable1 Aから選択して、Table2 Bを(A.に)結合します。 Name = B.Name)WHERE([email protected])AND(A.PREVIOUS <> 'N'またはA.PREVIOUSがNULL)ORNAME BY A.NAME

これを試してみてください。そうすれば、あなたは非常にスピードアップすることを保証するでしょう。


6


データベースが `+ ORDER BY `式に対応するインデックスを見つけることができれば、 ` ORDER BY +`は一般的に遅くありません。

ただし、SQLステートメントには、「+ SELECT TOP n +」のように、データベースが結果を返す前にテーブル全体をスキャンすることを強制する他のものが含まれている場合があります


3


あなたのフィルタがこのように見えるなら:

WHERE col1 = @value1
      AND col2 = @value2
      AND col3 = @value3
ORDER BY
      col4

、その後、 `(col1、col2、col3、col4)`にインデックスを作成する必要があります。

オプティマイザーは、最初の3つの値でフィルターをかけるためと4番目の値で並べ替えるための両方に索引を使用します。

そのようなインデックスがない場合は、次のいずれかが起こります。

  1. オプティマイザはインデックスを使用して、「+ WHERE 」条件でフィルタリングします。 しかし、それでも残りの行を「 ORDER +」する必要があります。

  2. オプティマイザーはインデックスを使用して値を「+ ORDER +」しますが、すべての値 それらを除外するには、検討する必要があります。

  3. オプティマイザーはインデックスをまったく使用しないため、2つの「ALL 値をフィルターで除外するために調べる必要があります」および1「残りのすべての行を順序付ける必要がある」がtrueです。


2


  • UPDATE *:あなたが投稿したクエリとして、最良の選択肢はそのクエリを良いと考えることであると思います:

  • 数行では、誰が作業をするのか気にしないでください。 その後、 あなたは `+ ORDER BY +`を使用しています。

  • 多くの行では、クライアントに仕事を任せないでください:RDMBSそれは サーバーのメモリとCPUを増やしてください。

'' '' '

あなたが考慮しなければならない注文のためのヒントは以下のとおりです。

  • `+ ORDER BY +`は、SQLクエリでソートを保証する* ONLY *方法です。

  • ソートの* best * _worker_は、いずれの場合でもデータベースです:確認してください この!

  • 返される行の濃度を最小にするようにしてください。

  • クエリに従ってインデックスを作成します。 順序付けられた列を置くことを意味します インデックスの最後。

  • 照会が速い場合は、索引付けを避けます。

  • インデックスがソートされていると考えることができます。 テーブルのみで、適切なインデックスがある場合、ソートのコストはゼロに近くなります。

インデックスに関するその他の経験則については、https://stackoverflow.com/questions/687986/what-are-some-best-practises-and-rules-of-thumb-for-creating-database-indexes/688006#688006を参照してください。 [この他のSO質問]。


1


遅くなるべきではありません。 クエリとデータベースの構造を最適化します(少なくともSQL Serverの場合はインデックスと統計)。 クエリには、この遅延の原因となる `+ ORDER BY +`以外の何かがあるのでしょうか?

SELECT A.NAME, B.SYNTAX, B.DESCRIPTION, A.RATE1, A.RATE2, A.RATE3,
       A.STARTDATE, A.ENDDATE, A.HIDE, A.CATEGORYNAME
FROM Table1 A JOIN Table2 B on A.Name = B.Name
WHERE A.MODULENAME = @ModuleName AND A.PREVIOUS<>'N' OR A.PREVIOUS IS NULL
ORDER BY A.NAME

オプション1

ほんの少しの単純な列(2〜4)を照会している場合は、それらを索引に含めることもできます。 こうすればあなたの質問はより速く動く。 また、そのインデックス列の並べ替え順序がクエリの並べ替え順序と一致していることも確認してください。

// if your query looks like this:
SELECT [Name], [Title], [Count] ORDER BY [COUNT]

// you can create an index on [Name], [Title], [Count]

オプション3

`+ view `を作成し、それを ` schema `にバインドします。 次に、その「 view +」からデータをクエリします。

オプション3

`+ SQL Server 2005 +`を使用してoboveする場合、* SQL Server Profiler *でクエリを実行することもできます。これを最適化するためにテーブルに適用できる最適なインデックスと統計を推奨します特定のクエリのパフォーマンス。

オプション4

インデックスと統計を再構築してみてください。

オプション5

あなたは別のハードドライブ上の別々のファイルグループにあなたのインデックス/テーブルを入れてみることができます。


1


表示するのに十分な行を選択しない場合、返される行の数を「+ LIMIT 」または「 TOP 」で制限しない限り、「 ORDER BY +」句が知覚可能な時間を要することは考えられません。

もっと情報が必要です。 何DBMS? クエリプランはどのようなものですか? 「+ ORDER BY +」がある場合とない場合のクエリプランを見ましたか? どのような違いがありますか?

'' '' '

編集:

SELECT A.NAME, B.SYNTAX, B.DESCRIPTION, A.RATE1, A.RATE2,
A.RATE3, A.STARTDATE, A.ENDDATE, A.HIDE, A.CATEGORYNAME
FROM A, B
WHERE A.MODULENAME='"+loadedModuleName+"'
  AND A.NAME = B.NAME
  AND (A.PREVIOUS<>'N' OR A.PREVIOUS IS NULL)
ORDER BY NAME

+ NAME +`は `+ primary key +`ですか? `+ NAME +`に `+ index +`がありますか? それ自体で、あるいは他の分野と一緒に? どんな順序で? 1つのloadedModuleNameに対して何行が返されますか? +遅さは「 `+ A.PREVIOUS <> 'N’またはA.PREVIOUS IS NULL」+から来ると思われます。+(NOT A.PREVIOUS = 'N')`を使用してみてください少し。 + ` ORDER BY +`を使用して、または使用せずにクエリの時間を計り、タイミングがまったく異なるかどうかを確認します。 あってはいけません。

'' '' '

編集:

`+ NAME `が ` A `または ` B `で一意でない場合、すべての ` A.NAME `インスタンスが ` B.NAME +`で相互結合されると、結合は部分的に弾道的になります。 50 A行と50 B行が一致すると、結果は2500行になりますが、これは意図したものとは異なる場合があります。


1


特にその列にインデックスがある場合、 `+ ORDER BY +`は特に遅くありません。 特に、その列にクラスター化インデックスがある場合、データは既に並べ替えられています。

ページング( + TOP +`または `+ ROW_NUMBER +)などを使用して支援することもできます。


1


多くのクエリエディタは、最初の50人程度がデータベースから戻ってきた後に結果を表示することに注意してください。

ORDER BYを追加すると、すべての結果をデータベースで待機することになります。これにより、クエリの実際の速度がわかります。

そのような場合、元のクエリとORDERされたクエリは同じ速度です。あなたのエディタは最初の50行程度の行をすばやく取得できるため、最初の1つが速いと考えることにだまされました。


1


私は昨夜、より生産的なタイプのデータベース(開発者のデータベースではありません)でパフォーマンステストをいくつか行いました。これが私が見つけたものです:

テーブルAの合計行数:13000

テーブルBの合計行数:5000

結合クエリによって返された行:5000

ORDER BY句と組み合わせて使用​​した場合の所要時間:約5.422秒

ORDER BY句を使用していない場合の所要時間:〜5.345秒。

そのため、ORDER BYが大きな違いを生むことはありませんでした。 (数ミリ秒を追加しても大丈夫です)。

また、B.SYNTAXの値をすべてNULLに設定してテストしたところ、大量のデータを転送してもネットワークの待ち時間が発生しないことを確認しました。

今、私はSELECT節からB.SYNTAXを削除しました、そして、問い合わせはたった0.8秒かかりました!

そのため、CLOB列全体がボトルネックになっているようです。 これは、このクエリを高速化するための解決策が得られたことを意味するわけではありませんが、少なくともソートアルゴリズムの作成に時間を費やすことはありません。

回答してくれたすべての人に感謝します。 私はかなりのことを学びました、そしてそれは私にいくつかの異なることを試してみるように導きました。


0


「並び順」はそれ自体が遅いということを言うのは公正な声明ではありません。 あなたはそれら自身の実装、そしてデータ型とインデックス体系に関して考慮すべき多くのRDBMを持っています。 しかし、サーバー側よりもクライアント側で速くソートすることができるのではないかと思いますが、サーバー側でソートするのが正しいことを言っているわけではありません。