2

未読の電子メールを持っているメンバーを見つけるために、250万を超えるレコードを調べなければならないスクリプトがあります。速度を上げるために何ができるか知りたいです。現在、スクリプトの実行には最大8秒かかる場合があります。

SELECT TOP(1) MemberMailID
FROM MemberMail
WHERE ToReadFlag = 0
AND ToMemberID = 102
AND ToDeletedFlag = 0
AND FromDeletedFlag = 0
AND OnHold = 0
AND ToArchivedFlag = 0

インデックスを使用して高速化するにはどうすればよいですか?

4

4 に答える 4

4

このインデックスはおそらく役立つでしょうが、フリーランチがないことに注意してください(インデックスを維持する必要があるため、これは挿入/更新/削除のワークロードに影響します):

CREATE NONCLUSTERED INDEX unread_emails
  ON dbo.MemberMail(ToMemberID)
  INCLUDE (MemberMailID)
  WHERE ToReadFlag = 0
  AND ToDeletedFlag = 0
  AND FromDeletedFlag = 0
  AND OnHold = 0
  AND ToArchivedFlag = 0;

これで、クエリは次のように言うことができます。

SELECT TOP (1) MemberMailID
  FROM dbo.MemberMail -- dbo prefix
    WITH (INDEX (unread_emails)) -- in case you need to force, though you should not
WHERE ToMemberID = 102
AND ToReadFlag = 0
AND ToDeletedFlag = 0
AND FromDeletedFlag = 0
AND OnHold = 0
AND ToArchivedFlag = 0
ORDER BY ToMemberID; -- ORDER BY is important!

クエリに応じてこれらのフラグの一部の値を変更する場合は、フィルターの代わりにインデックスのキーにこれらの列を追加してみてください。たとえば、チェックする場合OnHold = 0と、次の場合がありOnHold = 1ます。

CREATE NONCLUSTERED INDEX unread_emails
  ON dbo.MemberMail(ToMemberID, OnHold)
  INCLUDE (MemberMailID)
  WHERE ToReadFlag = 0
  AND ToDeletedFlag = 0
  AND FromDeletedFlag = 0
  AND ToArchivedFlag = 0;

MemberMailIDまた、の代わりにキーを使用して実験することもできますINCLUDE。例えば:

CREATE NONCLUSTERED INDEX unread_emails
  ON dbo.MemberMail(ToMemberID, MemberMailID)
  WHERE ToReadFlag = 0
  AND ToDeletedFlag = 0
  AND FromDeletedFlag = 0
  AND OnHold = 0
  AND ToArchivedFlag = 0;

これらの違いは、データや使用パターンには関係ない場合がありますが、推測よりも簡単に違いをテストできます。

于 2013-03-25T17:51:14.160 に答える
3

フィルタリングされたインデックスの適切な候補のように見えます。

フィルター処理されたインデックスは、最適化された非クラスター化インデックスであり、明確に定義されたデータのサブセットから選択するクエリをカバーするのに特に適しています。フィルタ述語を使用して、テーブル内の行の一部にインデックスを付けます。適切に設計されたフィルター処理されたインデックスは、フルテーブルインデックスと比較して、クエリパフォーマンスを向上させ、インデックスメンテナンスのコストを削減し、インデックスストレージのコストを削減できます。

これらの線に沿った何か:

CREATE NONCLUSTERED INDEX IX_MemberMail_ToMemberId_Unread
ON dbo.MemberMail (ToMemberId ASC)
WHERE ToReadFlag = 0
AND ToDeletedFlag = 0
AND FromDeletedFlag = 0
AND OnHold = 0
AND ToArchivedFlag = 0;
于 2013-03-25T17:56:09.633 に答える
2

SSMSで(CTRL + M)を使用して実際のクエリプランを取得します。または、クエリをSSMSに貼り付けて右クリックし、データベースエンジンチューニングアドバイザーで[クエリの分析]を選択すると、追加する必要のあるインデックスが表示されます。基本的に、composite+includeインデックスが必要です。

于 2013-03-25T17:36:42.653 に答える
0

経験則として、頻繁にフィルター(条件)を実行するすべてwhereのフィールドにインデックスを付ける必要があります。

繰り返しますが、経験則として、私は次の基準に従います。

  1. すべてのキーフィールド(プライマリまたは外部)にインデックスを付ける必要があります
  2. 頻繁にルックアップを実行する必要があるすべてdateのフィールドにインデックスを付ける必要があります
  3. 私はそれを避けていますが、charまたはvarcharフィールドで頻繁に検索を実行する必要がある場合は、それらにもインデックスを付けます

すべてにインデックスを付けるという誘惑に陥りやすいことに注意してください。しないでください。注意して、最高のコストと利益の関係でインデックスを設計してください。

私はMySQLユーザーであり、SQLサーバーでそれを行う方法はありませんが、クエリの実行プランを表示する方法が必要です(MySQLではそうですexplain select...)。実行計画を示してから、それに基づいて、インデックスを作成する必要のあるフィールドを決定します。

于 2013-03-25T17:37:16.660 に答える