私のテーブル(SQL Server 2008)には100万以上のレコードがあり、日時でレコードを並べ替えようとすると1秒かかりますが、ID(int)で並べ替えると約0.1秒しかかかりません。
効率を上げる方法はありますか? (私はすでに日時列をインデックスに追加しました)
id
による順序付けは、おそらくクラスター化インデックススキャンを使用しますが、datetime
による順序付けは、並べ替えまたはインデックスルックアップのいずれかを使用します。
これらの方法はどちらも、クラスター化インデックススキャンよりも低速です。
テーブルがid
でクラスター化されている場合、基本的にはすでにソートされていることを意味します。レコードは、ページをid
の順序でリンクするリンクリストを持つB+Tree
に含まれています。エンジンは、リンクリストをトラバースして、id
で並べ替えられたレコードを取得する必要があります。
id
sが順番に挿入された場合、これは、行の物理的な順序が論理的な順序と一致し、クラスター化インデックスのスキャンがさらに高速になることを意味します。
レコードをdatetime
で並べ替える場合は、次の2つのオプションがあります。
datetime
のインデックスを使用します。インデックスはディスクの別のスペースに保存されます。つまり、エンジンはネストされたループでインデックスページとテーブルページの間を行き来する必要があります。それももっと遅いです。順序を改善するために、datetime
に個別のカバーインデックスを作成できます。
CREATE INDEX ix_mytable_datetime ON mytable (datetime) INCLUDE (field1, field2, …)
、クエリで使用するすべての列をそのインデックスに含めます。
このインデックスはテーブルのシャドウコピーに似ていますが、データは異なる順序で並べ替えられています。
これにより、キールックアップを取り除くことができ(インデックスにはすべてのデータが含まれているため)、datetime
による順序付けがid
の順序付けと同じくらい速くなります。
更新:
この問題に関する新しいブログ投稿:
ORDER BYを尊重するには、エンジンには2つの選択肢があります。
最初のオプションは高速で、2番目のオプションは低速です。問題は、使用するために、インデックスがcoveringインデックスでなければならないことです。つまり、SELECTプロジェクションリストのすべての列と、WHERE句で使用されるすべての列が含まれます(少なくとも)。インデックスがカバーしていない場合、エンジンは、必要な列の値を取得するために、各行のクラスター化インデックス(つまり「テーブル」)を検索する必要があります。この値の一定のルックアップはコストがかかり、エンジンが(当然のことながら)クラスター化インデックスをスキャンして結果をソートする方が効率的であると判断する転換点があり、事実上、非クラスター化インデックスは無視されます。詳細については、 転換点クエリの回答 を参照してください。
次の3つのクエリについて考えてみます。
_SELECT dateColumn FROM table ORDER BY dateColumn
SELECT * FROM table ORDER BY dateColumn
SELECT someColumn FROM table ORDER BY dateColumn
_
1つ目は、dateColumnで非クラスター化インデックスを使用することです。ただし、2つ目は、dateColumnのインデックスを使用せず、100万行の代わりにスキャンと並べ替えを選択する可能性があります。一方、3番目のクエリは、Table(dateColumn) INCLUDE (someColumn)
のインデックスの恩恵を受けることができます。
このトピックは、MSDNで広く取り上げられています。 インデックスデザインの基本 、 一般的なインデックスデザインガイドライン 、 非クラスター化インデックスデザインガイドライン または ハウツー)を参照してください。 :SQLインデックスの最適化 。
最終的に、テーブルデザインの最も重要な選択は、使用するクラスター化インデックスです。ほとんどの場合、主キー(通常は自動インクリメントされたID)はクラスター化インデックスとして残されます。これは、特定のOLTPロードのみに役立つ決定です。
そして最後に、かなり明白な質問です。なぜ世界で100万行を注文するのでしょうか。表示できないかもしれませんね。ユースケースについてもう少し説明すると、より良い答えを見つけるのに役立つ場合があります。
日時を新しいインデックスに追加しますが、IDに追加してもあまり役に立ちません。
Int列にはインデックスがありますが、datetime列にはインデックスがない可能性がありますか?実行計画を見てください。
datatimeをintとして格納する場合でも、データを格納または取得するたびに変換に時間がかかる場合があります。 (IPアドレスなどのスタッフを保存し、シーク時間を短縮するために使用される一般的な手法)
サーバーが日時をどのように格納するかをサーバーにチェックインする必要があります。サーバーがすでにintまたはbigintとして格納している場合は、何も変更されません。
日時フィールドに多数の個別の値が含まれていて、それらの値がほとんど変更されない場合は、日時フィールドにクラスター化インデックスを定義します。これにより、実際のデータが日時値で並べ替えられます。クラスター化インデックスの使用については、 http://msdn.Microsoft.com/en-us/library/aa933131(SQL.80).aspx を参照してください。
ただし、これにより、非クラスター化インデックスの使用に追いやられるため、int検索が遅くなります。
DateTimeフィールドを「the」インデックスまたは排他的インデックスに追加しましたか?別のフィールドとDateTimeで選択をフィルタリングしますか、それともこれだけでフィルタリングしますか?
パフォーマンスを最適化するには、フィルタリングするすべてのフィールドを含むインデックスが必要です。