1

レポートに対してこれを実行したいのですが、テーブルに20,000,000のレコードがあり、アプリケーションでタイムアウトが発生します。

SELECT
        T.transactionStatusID,
        TS.shortName AS TransactionStatusDefShortName,
        count(*) AS qtyTransactions
    FROM
        Transactions T 

    INNER JOIN TransactionTypesCurrencies TTC
                ON  T.id_Ent = TTC.id_Ent
                    AND T.trnTypeCurrencyID = TTC.trnTypeCurrencyID
            INNER JOIN TransactionStatusDef TS
                ON  T.id_Ent = TS.ent_Ent
                AND T.transactionStatusID = TS.ID
WHERE
    T.id_Ent = @id_Ent
GROUP BY
        T.transactionStatusID,
        TS.shortName

私の知る限り、COUNT(*)は全表スキャンを引き起こし、クエリに時間がかかりすぎます。MSSQL 2005を使用している場合、何か助けはありますか?

編集:

プロジェクトリーダーは、クエリは1日だけで役立つと言っていますか?

4

4 に答える 4

2

私の知る限り、COUNT(*)は全表スキャンを引き起こし、クエリに時間がかかりすぎます。MSSQL 2005を使用している場合、何か助けはありますか?

COUNT(*)答えを出すことができる任意のソースを使用できます。これにはインデックスが含まれます。

あなたの場合、私は次のようにカバーするインデックスを作成し(id_ent, transactionStatusID)ますtrnTypeCurrencyID

CREATE INDEX ON Transactions (id_ent, transactionStatusID) INCLUDE (trnTypeCurrencyID)

クエリを少し書き直します。

SELECT  transactionStatusID, qtyTransactions, TS.shortName
FROM    (
        SELECT  T.transactionStatusID,
                COUNT(*) AS qtyTransactions
        FROM    Transactions T
        JOIN    TransactionTypesCurrencies TTC
        ON      TTC.id_Ent = T.id_Ent
                AND TTC.trnTypeCurrencyID = T.trnTypeCurrencyID
        WHERE   T.id_Ent = @id_Ent
        GROUP BY
                T.transactionStatusID
        ) TD
JOIN    TransactionStatusDef TS
ON      TS.ent_Ent = @id_Ent
        AND TS.ID = TD.transactionStatusID

インデックスはでフィルタリングされid_ent、並列化されtransactionStatusIDます。カバーしたのでtrnTypeCurrencyID、エンジンはテーブル内の値を検索する必要はなく、すでにインデックスに存在しています。

このGROUP BY句には、インデックスの列のみが含まれているため、並列化がはるかに優れています。

アップデート:

追加WITH (ONLINE = ON)することにより、インデックスが作成されている間、テーブルを操作可能なままにすることができます。

CREATE INDEX ON Transactions (id_ent, transactionStatusID) INCLUDE (trnTypeCurrencyID) WITH (ONLINE = ON)
于 2009-12-09T16:17:09.440 に答える
1

クエリの実行プランを見ると、パフォーマンスが悪いビットが強調表示されます。テーブルスキャン、インデックススキャン、インデックスシークのいずれを実行しているかがわかります。だから、それは探し始めるのに最適な場所です。

現在、インデックスはありますか?JOINおよびWHERE句に含まれるフィールドは、主要な候補です。インデックスがない場合は、それが主要な要因になります。

于 2009-12-09T16:13:13.113 に答える
0

やってみました

COUNT(1)

その代わり?

また、TransactionTypesCurrenciesへの参加は必要ですか、それから何かを使用しているようには見えませんか?

于 2009-12-09T16:10:49.670 に答える
0

トランザクションテーブルのクラスター化インデックスとは何ですか?他にどのようなインデックスがありますか?このクエリを試して、1つの結合を削除できます。

SELECT
    T.TransactionStatusID,
    TS.ShortName,
    qtyTransactions = COUNT(*)
FROM
    dbo.Transactions AS T
INNER JOIN
    dbo.TransactionStatusDef AS TS
    ON T.id_Ent = TS.ent_Ent
    AND T.transactionStatusID = TS.ID
WHERE EXISTS
(
    SELECT 1
        FROM do.TransactionTypeCurrencies AS TTC
        WHERE TTC.id_Ent = T.id_Ent
        AND TTC.trnTypeCurrencyID = T.trnTypeCurrencyID
)
AND T.id_Ent = @id_Ent
GROUP BY
    T.transactionStatusID,
    TS.shortName;

クエリを発行する前にスナップショットアイソレーションを使用することもできます。

SET TRANSACTION ISOLATION LEVEL SNAPSHOT;

これを行うには、次のものが必要です。

ALTER DATABASE dbname SET ALLOW_SNAPSHOT_ISOLATION ON;

一般的には、インデックスが正しく作成されていることを確認する必要があります。他のクエリに悪影響を与えるため、このクエリのテーブルに適切なインデックスを適用できない場合は、インデックス付きビューを検討して、このカウントを維持するか(挿入/更新のパフォーマンスを犠牲にして)、テーブルのパーティション分割を検討できます。 Enterprise Editionを使用している場合、またはアプリケーションがデータを待機する必要がないように、このデータのロールアップをバックグラウンドで実行する場合があります(実際のカウントが少し古くなっていても問題ないと仮定します)。

于 2009-12-09T16:12:57.000 に答える