我想为报告执行此操作,但我的表中有20,000,000条记录,它会在我的应用程序中导致TimeOut。
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,还有什么帮助吗?
项目负责人告诉我,查询只有一天可以提供帮助吗?
答案 0 :(得分:2)
据我所知,COUNT(*)会导致全表扫描,这会让我的查询占用太多时间,即使用MS SQL 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)
答案 1 :(得分:1)
如果查看查询的执行计划,则会突出显示执行错误的位。它会告诉您它是在进行表扫描,索引扫描还是索引搜索。 所以这是开始寻找的最佳场所。
目前你有任何索引吗? JOIN和WHERE子句中涉及的字段是主要候选者 - 如果您没有索引,那么这将是一个主要因素。
答案 2 :(得分:0)
你试过吗
COUNT(1)
相反?
此外,是否需要加入 TransactionTypesCurrencies ,似乎您没有使用其中的任何内容?
答案 3 :(得分: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;
一般情况下,您希望确保正确编制索引。如果您无法对此查询的表应用正确的索引,因为它会损害其他查询,那么您可以考虑使用索引视图来维护此计数(以插入/更新性能为代价),或者如果您使用表分区是在企业版上,或偶尔在后台运行这些数据的汇总,以便您的应用程序不必等待它(假设实际计数有点陈旧)。