使用 WHERE PK IN (...) 进行缓慢查询
Slow query with WHERE PK IN (...)
我有一个非常简单但很大的 table 像这样:
CREATE TABLE tblMulti (
pk1 bigint,
pk2 bigint
)
其中PK是pk1-pk2的组成(按此顺序)。
然后,我有一个大的table像这样:
CREATE TABLE tbl (
ID bigint,
field1 int,
... (other fields)
)
ID是table的唯一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 table 的 94%),因此 SQL 服务器决定执行索引扫描而不是索引查找。
如何提高此查询的性能?
非常感谢
cghersi
以下是我要优化的内容:
- 在
pk2
列上创建 NON CLUSTERED
索引。
- 在
field1
列上创建 NON CLUSTERED
索引。
- Rebuild/Reorganize 索引和统计数据。
- 使用 JOIN 而不是 IN。
- 使用
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));
试试这样的……
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;
这看起来很慢的原因是因为您在 pk2
字段上没有索引,但您使用它来将结果限制为 'just one type' (101
) ( **).
=> 假设您在这里只需要 table 进行查询,您可以简单地颠倒 tblMulti 的主键的顺序,它(在功能上)将是完全相同的东西。
=> 假设您需要具有所述字段顺序的 pk 用于其他内容,您可以在 table 上创建一个额外的唯一索引(或约束),字段顺序相反。
**:是的,我知道你在索引中 有 pk2
,但这对 MSSQL 和我告诉你找到 phone-名字以"mith, John"结尾的人的数量,将phone-书编入姓氏索引对您也没有太大帮助。
此外,由于您知道组合 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;
我有一个非常简单但很大的 table 像这样:
CREATE TABLE tblMulti (
pk1 bigint,
pk2 bigint
)
其中PK是pk1-pk2的组成(按此顺序)。
然后,我有一个大的table像这样:
CREATE TABLE tbl (
ID bigint,
field1 int,
... (other fields)
)
ID是table的唯一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 table 的 94%),因此 SQL 服务器决定执行索引扫描而不是索引查找。
如何提高此查询的性能?
非常感谢
cghersi
以下是我要优化的内容:
- 在
pk2
列上创建NON CLUSTERED
索引。 - 在
field1
列上创建NON CLUSTERED
索引。 - Rebuild/Reorganize 索引和统计数据。
- 使用 JOIN 而不是 IN。
- 使用
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));
试试这样的……
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;
这看起来很慢的原因是因为您在 pk2
字段上没有索引,但您使用它来将结果限制为 'just one type' (101
) ( **).
=> 假设您在这里只需要 table 进行查询,您可以简单地颠倒 tblMulti 的主键的顺序,它(在功能上)将是完全相同的东西。
=> 假设您需要具有所述字段顺序的 pk 用于其他内容,您可以在 table 上创建一个额外的唯一索引(或约束),字段顺序相反。
**:是的,我知道你在索引中 有 pk2
,但这对 MSSQL 和我告诉你找到 phone-名字以"mith, John"结尾的人的数量,将phone-书编入姓氏索引对您也没有太大帮助。
此外,由于您知道组合 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;