sql server多列索引&查询过滤器具有索引键中的第一列和最后一列

时间:2017-01-11 13:58:29

标签: sql-server sql-server-2012

如果我有列密钥的多列索引:col_1,col_2和col_3

如果查询在WHERE子句中具有以下条件,则查询是否会使用此索引: col_1 = any_value AND col_3 = any_value

(索引键中的第二列未添加到WHERE子句中)

这是另一个例子: 如果索引有10列,并且列键按此顺序排列: col_1,col_2,....,col_10 然后,我运行了这个查询: 从X中选择col_1,col_2,...,col_10 WHERE col_1 = any_value AND col_5 = any_value AND col_10 = any_value

和我的问题:在这种情况下是否会使用索引?

3 个答案:

答案 0 :(得分:0)

新答案,因为我现在对您的问题更加清楚

不,不会使用索引。只有在col_1col_1 / col_2col_1 / col_2 / col_3上查询时,索引才会 被使用。使用查询的执行计划进行检查。您的多列索引的顺序很重要:请查看此问题,以便围绕此主题Multiple Indexes vs Multi-Column Indexes

进行一些讨论

如果您认为您更有可能在col_1col_3上进行查询,为什么不在这两列上创建多列索引?

答案 1 :(得分:0)

可能会被使用。这取决于许多因素,主要是您的数据(以及有关您的数据的统计数据)和您的查询。

  

TL / DR;您需要根据自己的数据和自己的查询对此进行测试。可以使用索引。

您应该尝试一下您拥有或期望拥有的数据。创建一些测试数据非常容易,您可以在其中测试查询并尝试不同的索引。您可能还需要重新考虑索引中列的顺序,col_1真的是索引中第一个最好的列吗?

下面是一个非常具体的场景,我们只能从中得出结论,有时可以在与您类似的场景中使用索引。

请考虑以下情况;该表包含1M行,并且(a,b,c)上只有一个非聚簇索引。请注意,D列中的值非常大。

下面的前4个查询使用了索引,只有第5个查询没有。

为什么?

Sql Server需要弄清楚如何在读取最少量数据时完成查询。有时,即使查询过滤器与索引不完全匹配,SQL Server也更容易读取索引而不是表。

在查询1和2中,查询实际上会对索引进行搜索,这非常好。它知道A列是执行Seek on的良好候选者。

在查询3和4中,它需要扫描整个索引以查找匹配的行。它仍然使用索引。

在查询5中,SQL Server意识到扫描实际表而不是索引更容易。

IF OBJECT_ID('tempdb..#peter') IS NOT NULL DROP TABLE #peter;
CREATE TABLE #peter(a INT, b INT, c VARCHAR(100), d VARCHAR(MAX));

WITH baserows AS (
    SELECT * FROM master..spt_values WHERE type = 'P'
),
numbered AS (
SELECT TOP 1000000 
    a.*, rn = ROW_NUMBER() OVER(ORDER BY (SELECT null))
FROM baserows a, baserows b, baserows c
)

INSERT #peter
        ( a, b, c, d )
SELECT 
    rn % 100, rn % 10, CHAR(65 + (rn % 60)), REPLICATE(CHAR(65 + (rn % 60)), rn)
FROM numbered

CREATE INDEX ix_peter ON #peter(a, b, c);



-- First query does Seek on the index + RID Lookup.
SELECT * FROM #peter WHERE a = 55 AND c = 'P'
-- Second Query does Seek on the index.
SELECT a, b, c FROM #peter WHERE a = 55 AND c = 'P'
-- Third query does Scan on the index because the index is smaller to scan than the full table.
SELECT a, b, c FROM #peter WHERE c = 'P'
-- Fourth query does a scan on the index
SELECT a, b, c FROM #peter WHERE b = 22
-- Fifth query scans the table and not the index
SELECT MAX(d) FROM #peter
  

在SQL Server 2014上测试。

答案 2 :(得分:0)

该索引肯定会使用,但不会有效。

我做了一个实验(SQL Server),这是它的外观[IX_AB是a,b上的索引],我可以将您的问题与此相关联。

enter image description here

这些是结论

  1. 如果您使用col1,col2和col3创建索引并仅传递col1和col3,则该索引将仅过滤col1值,然后将从那里检索到的数据以编程方式过滤O(N),其中N是标记为索引。
  2. 将中间值传递为“ not null”或“ null”没有帮助。