ストレージの順序と結果の順序


8

これは、主キーで指定されたソート順から派生した質問ですが、ソートはSELECTで実行されます。

@Catcallは、ストレージの順序(クラスター化インデックス)と出力の順序についてこれを述べています。

多くの人々は、クラスター化インデックスが出力のソート順を保証すると信じています。しかし、それはそうではありません。ディスク上のストレージの順序を保証します。 たとえば、このブログ投稿をご覧ください。

Hugo Kornelisによるブログ投稿を読みましたが、インデックスがSQLサーバーが特定の順序でレコードを読み取ることを保証するものではないことを理解しています。しかし、自分のシナリオではこれを想定できないことを受け入れるのに苦労していますか?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

私の元のクエリはこれでした:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

しかし、私はこれも使用できることをお勧めします(説明については以下をお読みください):

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

ご覧のとおり、テーブルの行は小さく(16バイト)、クラスター化されたインデックスは1つしかありません。私のシナリオでは、テーブルは現時点で100.000.000レコードで構成されています(これはおそらく10倍に増加します)。

データベースサーバーがこのテーブルにクエリを実行するとき、行を見つける方法は2つあります。主キーを探し、それによって値を読み取り、descに返します。日付順、またはテーブル全体をスキャンする必要があります。私の結論は、これらすべてのレコードに対する全テーブルスキャンは非常に遅くなり、データベースサーバーは常に主キーを介してテーブルをシークし、それによってソートされた値を返すということです。Date DESC


2
なぜこの仮定をそれほどひどく信頼できるようにしたいのですか?あなただけ入れていないのはなぜORDER BYそこに、あなたが知っている、あなたがそれに頼ることができます。ここ#3を参照してください
アーロンバートランド

2つの理由から、好奇心とORDER BY節がパフォーマンスに大きな影響を与えるためです(詳細については、他の質問をお読みください)。私は今のところ機能する解決策を持っていますが、トラフィックが増加したときに、それが保持されません。
m__

1
ORDER BYなしで表示されている注文に依存している場合、ORDER BYはパフォーマンスヒットにはなりません。それは私には意味がありません。
アーロンバートランド

4
唯一のものという保証はセットの順序を結果がORDER BYクエリでWHERE句。これは、SQL ServerOracleMySQL、およびその他の考えられるすべてのRDBMSに当てはまります。他のことを試してみてください。あなたは突然のFAILに備えています。
Nick Chammas

回答:


15

私はあなたがすべき理由を説明してみましょうではない、なぜあなたがすべき、それを行う決してあなたがそう指定しない限り、SQL-製品は、特定の順序で結果セットを返すことを前提としない、どんな指標-クラスタ化または非クラスタ化、B-木やRツリー、kdツリー、フラクタルツリー、またはDBMSが使用しているその他のエキゾチックなインデックス。


元のクエリは、SensorValuesテーブルを検索し、3つの条件に一致する行を見つけ、それらの行をDate降順に並べ替え、それらの最初の行のみを保持し、最後に- SensorValue列のみを選択して返すようにDBMSに指示します。

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

これらは、DBMSに指定した非常に特定の順序であり、クエリを実行するたびに結果が同じになる可能性があります(条件に一致し、同じ行が複数ある場合は、一致しない可能性があります)最大ですDateが異なりSensorValueますが、会話の残りの部分では、そのような行がテーブルに存在しないと仮定します)。

このクエリを実行するために、DBMSはこれを行う必要がありますか?上記で説明したとおりの方法ですか?いいえ、もちろん違います。あなたはそれを知っています。テーブルを読み取るのではなく、インデックスから読み取ることができます。または、より良い(速い)と思われる場合は、2つのインデックスを使用する場合があります。または3つ。または、キャッシュされた結果(SQL Serverではなく他のDBMSキャッシュクエリ結果)を使用する場合もあります。または、並列実行を1回使用し、次に実行するときではありません。または...(実行および実行計画に影響を与えるその他の機能を追加します)。

ただし、行が挿入、削除、または更新されない限り、実行するたびにまったく同じ結果が返されることが保証されています。


今あなたの提案が言うことを見てみましょう:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

このクエリは、SensorValuesテーブルを検索し、3つの条件に一致する行を検索し、それらの行をDate降順で並べ替え、順序を気にせず、1行のみを保持し、最後にSensorValue列のみを選択して返すようにDBMSに指示します。

したがって、基本的には最初の結果と同じですが、条件に一致する1つの結果のみが必要で、どの結果を気にする必要がないことを示します。

ここで、クラスター化インデックスのため、常に同じ結果が得られると想定できますか?
-毎回このクラスター化インデックスを使用する場合は、そうです。

しかし、それを使用しますか?
- 番号。

何故なの?
-できるから。クエリオプティマイザーは、ステートメントを実行するたびに実行パスを自由に選択できます。その時点でそのステートメントに適合すると思われるパスは何でも。

しかし、クラスター化インデックスを使用して結果を取得するための最良/最速の方法ではありませんか?
-いいえ、必ずしもそうではありません。クエリを実行するのは初めてかもしれません。2回目は、キャッシュされた結果を使用する場合があります(DBMSにSQL Serverではなくそのような機能がある場合*)。結果が1000回キャッシュから削除され、別の結果がキャッシュに存在する可能性があります。たとえば、直前にこのクエリを実行したとします。

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

キャッシュされた結果(上記のクエリから)は別の別の結果であり、まだ条件に一致していますが、(必要な)順序付けの最初ではありません。そして、あなたはDBMSに注文を気にしないように言いました。

OK、キャッシュだけがこれに影響を与えることができますか?
-いいえ、他にもたくさんあります。

  • 他のインデックスは、当時、DBMSによってこのクエリに適していると見なされていました。
  • 開発者が、このクラスター化インデックスを変更または完全に削除しました。
  • あなたまたは他の開発者が、オプティマイザがCIよりも使用する方が効率的であると判断した別のインデックスを追加しました。
  • 新しいバージョンに更新し、新しいオプティマイザーにマイナーなバグがあるか、実行プランのランク付けと選択の方法が変更されています。
  • 統計を更新しました。
  • 代わりに並列実行が選択されました。

*:SQL Serverはクエリ結果をキャッシュしませんが、Enterprise Editionには高度なスキャン機能があり、クエリの同時実行により異なる結果が得られる場合があります。これがいつ始まるのか正確にはわかりません。(ヒントはthnx @Martin Smithです。)


特に指定しない限り、SQLクエリが特定の順序で結果を返すことを絶対に信頼してはいけないと確信していることを願っています。もちろん、結果にn行が必要で、どの行が返されるかを気にしない場合を除いて、TOP (n)なしORDER BYで使用しないでください。


2
SQL Server Enterprise Editionには、高度なスキャン機能があり、同時クエリのために異なる結果が得られる場合があります。これがいつ始まるのか正確にはわかりません。
マーティン・スミス

1
結果セットの順序を潜在的に「ランダム化」するもう1つのことは(クエリが順序付けされたインデックスによって明らかに駆動される場合でも)並列処理です。正常に機能していないSQLを実行していたアプリが、自動並列化を有効にした後、正しく動作しなくなったのを見ました(SQL Serverではありませんが、そこにも当てはまると思います)。
マット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.