使用WHERE PK IN缓慢查询(...)

时间:2015-01-03 18:06:24

标签: sql-server query-performance sql-server-2014

我有一个非常简单但很大的表:

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

3 个答案:

答案 0 :(得分:1)

这是我要做的优化:

  1. NON CLUSTERED列上创建pk2索引。
  2. NON CLUSTERED列上创建field1索引。
  3. 重建/重组索引和统计信息。
  4. 使用JOIN代替IN。
  5. 使用OPTIMIZE FOR查询提示。
  6. 所以,试试这个:

    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来说同样有用,因为我告诉你找到的电话号码是名字结束的人,约翰",将电话簿编入家庭姓名索引也不会对你有所帮助。

此外,由于您知道组合pk1pk2是唯一的,因此您可以使用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;