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(*) 会导致全表扫描,这使我的查询花费了太多时间,我正在使用 MS SQL 2005,有什么帮助吗?

编辑:

项目负责人告诉我,查询只是一天,它可以提供帮助吗?

4

4 回答 4

2

据我所知 COUNT(*) 会导致全表扫描,这使我的查询花费了太多时间,我正在使用 MS SQL 2005,有什么帮助吗?

COUNT(*)可以使用任何能够给出答案的来源,这包括索引。

在您的情况下,我会在(id_ent, transactionStatusID)with上创建一个覆盖索引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

事务表上的聚集索引是什么?还存在哪些其他索引?您可以尝试使用此查询来消除一个连接:

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;

一般来说,虽然你想确保你得到正确的索引。如果您无法对该查询的表应用正确的索引,因为它会损害其他查询,那么您可以考虑使用索引视图来为您维护此计数(以插入/更新性能为代价),或者如果您使用表分区在企业版上,或者偶尔在后台运行此数据的汇总,以便您的应用程序不必等待它(假设实际计数有点陈旧是可以的)。

于 2009-12-09T16:12:57.000 回答