【问题标题】:Question regarding index关于索引的问题
【发布时间】:2011-05-31 10:12:23
【问题描述】:

我有以下疑问:

            SELECT 
                  M.Col7,   
                  M.Col8,   
                  M.Col9,   
                      M.Col10   

                FROM    [MyTable] M                    

        WHERE   M.Col1 = COALESCE(@Col1, M.Col1)              
                AND M.Col2 = COALESCE(@Col2, M.Col2)              
                AND M.Col3 = COALESCE(@Col3,              
                                                M.Col3)              
                AND M.Col4 = COALESCE(@Col4,              
                                                 M.Col4)              
                AND M.Col5 = COALESCE(@Col5,              
                                                    M.Col5)              
                AND M.Col6 LIKE COALESCE(@Col6, M.Col6) +'%'

我在 col7,8,9,10 列上有一个组合的非聚集索引。如果我删除 where 子句,查询运行良好。但是,只要我放置 where 子句,查询就需要很长时间才能执行。我的表有 200 K 行。现在我正在考虑按 Col1、2、3、4、5、6 的顺序放置一个包含列的单个非聚集索引。我是否正确地加快了速度,或者什么应该是最好的选择?

【问题讨论】:

  • 请添加表+键+索引定义...
  • 那些COALESCEs 可能会搞砸索引的任何使用。
  • 那我该如何使用索引呢?我从外面得到@Col1、@Col2、@Col3,它们可以为空。

标签: sql-server sql-server-2005 sql-server-2008 indexing


【解决方案1】:

试试这个有一个覆盖索引

CREATE INDEX IX_foo ON MyTable
   (Col1,Col2,Col3,Col4,Col5,Col6)
   INCLUDE (Col7,Col8,Col9,Col10)

其他想法:

其他:

  • 什么是聚集索引和主键?

编辑,解释 WHERE cmets

WHERE
    M.Col1 = ISNULL(@Col1, M.Col1)
    AND
    ...

WHERE
    (@Col1 IS NULL OR M.Col1 = @Col1
    AND
    ...

【讨论】:

  • 你的意思是说 M.Col1 = ISNULL(@Col1, M.Col1) 将使用索引而 M.Col1 = COALESCE(@Col1, M.Col1) 不是?
  • 对我来说 ISNULL(@Col1, M.Col1), M.Col1 = COALESCE(@Col1, M.Col1) 和 (@Col1 IS NULL OR M.Col1 = @Col1 都在做索引扫描而不是搜索
  • @Rocky Singh:我说“试试看”。您是否按照我的建议添加了新索引?您是否更改了列顺序以匹配选择性?
  • 我有一个查询,询问您如何决定保留哪些列,哪些不包含,以及按什么顺序?
  • @Rocky Singh:很简单。关键列 = 过滤、JOINed 和 ORDERing。 INCLUDE = 仅 SELECT 子句。
【解决方案2】:

除了创建覆盖索引之外,

CREATE INDEX NC_Col1Col2Col3Col4Col5Col6_I_Col7Col8Col9Col10
   ON MyTable(Col1, Col2, Col3, Col4, Col5, Col6)   
      INCLUDE (Col7, Col8, Col9, Col10)

我将使用ISNULL() 而不是COALESCE() 进行基准测试,并将WHERE 子句置于可SARG 的形式中,以便可以使用索引,例如

WHERE  (@Col1 IS NULL OR M.Col1 = @Col1)
       AND   -- etc...

【讨论】:

  • “并把 WHERE 子句放在一个 SARG'able 的形式,以便可以使用一个索引”你能告诉我我应该做的查询,以便使 ir sargable?
【解决方案3】:

@gbn 建议的查询覆盖索引可能是最好的主意。

另一方面,为很多列覆盖索引并不是一个好主意...

我会在WHERE 子句中最具选择性的列上尝试(如果可能的话)簇索引

这种最小化的索引大小并允许直接访问所有其他列——也许这足以加快您的查询速度。

【讨论】:

    【解决方案4】:

    洛基,

    到目前为止给出的所有答案都会有所帮助。但我不得不说,我相信这个问题比缺失的索引更深层次。

    首先,纯粹是猜测,但表中已经有 200k 行这一事实向我表明,即使没有,也会发生大量插入以运行超过 200K 行的函数慢一点,越多的行越慢。

    我建议在 where 子句中使用 CASE 语句。这将消除它扫描的每一行的 FUNCTION 调用 多次 次。它还将为 SQL Server 生成一个更好的查询执行计划,或者更确切地说允许 SQL Server 选择一个更优化的计划根据我的经验

    所以这是修改后的查询:

    SELECT M.Col7, M.Col8, M.Col9, M.Col10   
    FROM [MyTable] M                    
    WHERE M.Col1 = CASE WHEN @Col1 IS NULL THEN M.Col1 ELSE @Col1 END
        AND M.Col2 = CASE WHEN @Col2 IS NULL THEN M.Col2 ELSE @Col2 END           
        AND M.Col3 = CASE WHEN @Col3 IS NULL THEN M.Col3 ELSE @Col3 END             
        AND M.Col4 = CASE WHEN @Col4 IS NULL THEN M.Col4 ELSE @Col4 END              
        AND M.Col5 = CASE WHEN @Col5 IS NULL THEN M.Col5 ELSE @Col5 END              
        AND M.Col6 LIKE CASE WHEN @Col6 IS NULL THEN M.Col6 ELSE @Col6 END +'%'
    

    希望这会有所帮助。然后添加@gbn 的索引(+1)。

    【讨论】:

    • 难道 COALESCE(@Col1, M.Col1) 不会在内部做同样的事情吗?
    • 试试看查询执行计划。另一种可能性是执行动态 SQL,然后使用 sp_executesql 或使用 if-else 语句执行它,然后只有 where 条件与您的输入相匹配。
    猜你喜欢
    • 1970-01-01
    • 2022-01-17
    • 2013-03-04
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 2018-10-31
    • 2010-10-15
    相关资源
    最近更新 更多