我正在调整 SQL Server 2005 上的查询。 请注意真正的问题在最后。 我有以下查询,pto 和 ph 都有大约 3000 万行。查询最初运行很慢(3 分钟)。所以我分别在pto、ph上加了两个索引。
SELECT
MAX(ph.txn_date_time)
FROM
pto AS pto WITH (NOLOCK)
INNER JOIN ph AS ph WITH (NOLOCK) ON ph.receipt_id = pto.receipt_id
WHERE
pto.subtype = 'ff'
AND pto.Units_No > 0
AND ph.branch_id = 5
CREATE NONCLUSTERED INDEX [IX_pto_subTypeUnitReceipt] ON [dbo].[pto]
(
[SUBTYPE] ASC,
[Units_No] ASC,
[RECEIPT_ID] ASC
)WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = ON, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [Indexes]
CREATE NONCLUSTERED INDEX [IX_ph_branchReceiptTxn] ON [dbo].[ph]
(
[BRANCH_ID] ASC,
[RECEIPT_ID] ASC,
[TXN_DATE_TIME] ASC
)WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [Indexes]
现在查询运行时间为 350 毫秒。伟大的。执行计划也非常简单,它使用从两个表创建的索引并对 receipt_id 列进行哈希连接,然后使用流聚合来执行 MAX(ph.txn_date_time)。所以查询中的每一列都被两个添加的索引覆盖。
问题是为什么它在 receipt_id 列上使用哈希连接?我的意思是,由于两个索引中的 RECEIPT_ID 都已排序,因此优化器应该使用合并连接。为了弄清楚为什么我将第一个索引更改为下面(将 RECEIPT_ID 放在 Units_No 之前)。
CREATE NONCLUSTERED INDEX [IX_pto_subTypeUnitReceipt] ON [dbo].[pto]
(
[SUBTYPE] ASC,
[RECEIPT_ID] ASC,
[Units_No] ASC
)WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = ON, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [Indexes]
现在我在 RECEIPT_ID 列上看到合并联接。查询也在 170 毫秒内运行。现在很明显,优化器认为两个索引中的 RECEIPT_ID 都已排序,因此使用了合并连接。但我不明白为什么在第一种情况下它不这么认为?
最佳答案
原因是 RECEIPT_ID
不是您所拥有的索引中的第一个排序项。你有 units_no
挡路。
想象一下,您有一排书按出版商排序,然后按作者排序,然后按颜色排序。如果你想找到特定颜色的所有书籍,你需要访问每个出版商部分,然后是每个作者部分,然后找到正确颜色的书籍。因此,“索引”不太适合按颜色扫描,即使您可以暂时说这些书是按颜色分类的。
当您添加最后一个索引时,RECEIPT_ID
可以排序,因为您通过 SUBTYPE
限制了查询。因此,双方的所有 RECEIPT_ID
值都是可用的,成本很低,并且选择了合并连接。
关于sql-server - 使用覆盖索引、合并连接、散列连接的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12093714/