我有一个非常简单但很大的表:
CREATE TABLE tblMulti (
pk1 bigint,
pk2 bigint
)
其中PK是pk1-pk2的组成(按此顺序)。
然后,我有一个像这样的大表:
CREATE TABLE tbl (
ID bigint,
field1 int,
... (other fields)
)
ID是表中唯一的PK。
我需要执行以下查询:
SELECT ID, COUNT(*) OVER () as TotalCount
FROM tbl
WHERE ID IN (
SELECT pk1
FROM tblMulti
WHERE pk2 = 101)
ORDER BY field1 DESC, ID DESC
OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;
问题是过滤器" pk2 = 101"导致大量行(占整个tblMulti表的94%),因此SQL Server决定执行索引扫描而不是索引搜索。
如何增强此查询的效果?
非常感谢
cghersi
答案 0 :(得分:1)
这是我要做的优化:
NON CLUSTERED
列上创建pk2
索引。NON CLUSTERED
列上创建field1
索引。OPTIMIZE FOR
查询提示。所以,试试这个:
DECLARE @C INT = 101;
SELECT ID, COUNT(*) OVER () as TotalCount
FROM tbl
INNER JOIN tblMulti
ON tbl.ID = tblMulti.pk1
WHERE pk2 = @C
ORDER BY field1 DESC, ID DESC
OFFSET @start ROWS FETCH NEXT @count ROWS ONLY
OPTION (OPTIMIZE FOR (@C = 101));
答案 1 :(得分:0)
尝试这样的事情......
SELECT t1.ID, COUNT(*) OVER () as TotalCount
FROM tbl t1
WHERE EXISTS (SELECT 1
FROM tblMulti
WHERE t1.ID = pk1
AND pk2 = 101)
ORDER BY t1.field1 DESC, t1.ID DESC
OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;
答案 2 :(得分:0)
这看起来很慢的原因是因为您在pk2
字段上没有索引,但是您使用它来将结果限制为只有一种类型' (101
)(**)。
=>假设你在这里只需要查询表,你可以简单地颠倒tblMulti主键的顺序,它将(在功能上)完全相同。
=>假设您需要带有所述字段顺序的pk用于其他内容,您可以在表上创建一个额外的唯一索引(或约束),其中字段的顺序相反。
**:是的,我知道你在索引中拥有 pk2
,但这对MSSQL来说同样有用,因为我告诉你找到的电话号码是名字结束的人,约翰",将电话簿编入家庭姓名索引也不会对你有所帮助。
此外,由于您知道组合pk1
,pk2
是唯一的,因此您可以使用JOIN
代替WHERE EXISTS()
SELECT t1.ID,
COUNT(*) OVER () as TotalCount
FROM tbl t1
JOIN tblMulti tm
ON tm.pk1 = t1.ID
AND tm.pk2 = 101
ORDER BY t1.field1 DESC,
t1.ID DESC
OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;
那就是说,我对这项工作有点惊讶。您对不属于输出的字段执行ORDER BY
。我以某种方式猜测MSSQL将其排除在外并只使用t1.ID
?!
以下查询不会更直接使用吗?
SELECT t1.ID,
COUNT(*) as TotalCount
FROM tbl t1
JOIN tblMulti tm
ON tm.pk1 = t1.ID
AND tm.pk2 = 101
GROUP BY t1.ID
ORDER BY t1.ID DESC
OFFSET @start ROWS FETCH NEXT @count ROWS ONLY;