Sql server SQL Server不会使用我的索引

Sql server SQL Server不会使用我的索引,sql-server,sql-server-2005,performance,indexing,Sql Server,Sql Server 2005,Performance,Indexing,我有一个相当简单的问题: SELECT col1, col2… FROM dbo.My_Table WHERE col1 = @col1 AND col2 = @col2 AND col3 <= @col3 我有什么遗漏吗?我不喜欢在存储过程中添加索引提示,但SQLServer似乎无法获得关于这一点的线索。有人知道其他可能会妨碍SQLServer认识到使用索引是一个好主意的事情吗 编辑:返回的列之一是文本列,因此使用覆盖索引或包

我有一个相当简单的问题:

SELECT
     col1,
     col2…
FROM
     dbo.My_Table
WHERE
     col1 = @col1 AND
     col2 = @col2 AND
     col3 <= @col3
我有什么遗漏吗?我不喜欢在存储过程中添加索引提示,但SQLServer似乎无法获得关于这一点的线索。有人知道其他可能会妨碍SQLServer认识到使用索引是一个好主意的事情吗


编辑:返回的列之一是文本列,因此使用覆盖索引或包含将不起作用:

索引的顺序对于此查询很重要:

CREATE INDEX MyIndex ON MyTable (col3 DESC, col2 ASC, col1 ASC)
与其说是ASC/DESC,不如说是当sql server匹配where子句时,它可以首先匹配col3并沿着该值遍历索引

SQL Server optimizer在优化使用变量的查询时效果不佳

如果您确信您将始终受益于使用索引,只需给出一个提示

如果将文本值而不是变量放入查询,它将选择正确的统计信息并使用索引

您还可以尝试提供更轻松的提示:

OPTION (OPTIMIZE FOR (@col1 = 1, @col2 = 0, @col3 = '2009-07-09'))

,它将使用统计信息计算这些变量值的最佳执行计划,并且无论发生什么情况都不会坚持使用索引。

您是否尝试过从索引中去掉位

create index ix1 on My_Table(Col3, Col1) INCLUDE(Col2) 
-- include other columns from the select list if needed

此外,您还忽略了选择列表中的其余列。如果在索引或AS语句中没有很多来创建查询的覆盖索引,那么您可能需要考虑包括那些。< /P> < P>尝试屏蔽参数以防止参数嗅探:

CREATE PROCEDURE MyProc AS
    @Col1 INT
    -- etc...
AS
    DECLARE @MaskedCol1 INT
    SET @MaskedCol1 = @Col1
    -- etc...

    SELECT
         col1,
         col2…
    FROM
         dbo.My_Table
    WHERE
         col1 = @MaskecCol1 AND
         -- etc...

听起来很愚蠢,但我看到SQL server因为参数嗅探而做了一些奇怪的事情。

我打赌SQL server认为获得由指定的其余列的代价是。。。在您的示例中,聚集索引的好处大于索引的好处,因此它只扫描聚集键。如果是的话,看看你能不能把它作为一个覆盖索引


还是使用另一个索引?

列是否可以为空?有时Sql Server认为必须扫描表才能找到空值

尝试将col1添加到查询中,并且col1不为null,这将使sqlserver使用索引wtihout提示

此外,检查统计数据是否真的是最新的:

SELECT 
    object_name = Object_Name(ind.object_id),
    IndexName = ind.name,
    StatisticsDate = STATS_DATE(ind.object_id, ind.index_id)
FROM SYS.INDEXES ind
order by STATS_DATE(ind.object_id, ind.index_id) desc

有800k行被col1、col2、col3索引。Col2有点小,所以它的选择性是50%。如果SELECT返回的列不在索引SQL my中,则Col3是一个范围上的选中项。如果SELECT返回的列不在索引SQL my中,则查找聚集索引会更有效,而不必执行键查找来查找您请求的其他值


如果有文本列,请尝试将数据类型切换为VARCHARMAX,然后将值包括在非聚集索引中。

对于此查询,索引的顺序应与@Tom H.创建的顺序相同。我确实尝试了列的几种可能顺序。所有列都给出了相同的结果。如果在列列表中添加了省略号,则选择其他哪些列?如果它只是col1、col2和col3呢?Chris,这一点很好,但当我强制它使用我的索引时,它返回的结果立即覆盖了这一点。省略号是因为查询返回表中的所有列。我想我可以将SELECT*与Oracle不同,SQL Server索引也是空的,并且索引总是覆盖所有行。我的理论是,有时统计数据显示有许多行具有空。然后Sql Server恢复到表扫描,以覆盖c1为空的情况。@Andomar:此查询永远不能覆盖COL1为空的行谢谢您的建议。虽然我可以在SP之外运行SELECT,但我仍然看到相同的情况。感谢您提供的信息和建议。它给了我一些想法,如果我不强制使用索引,它将使用聚集键。列列表包括表中的所有列。虽然我可以在上面放一个大的覆盖索引,但我实际上是在复制表格。我需要查看插入/更新/删除频率,以确定成本是否合理。如果我在SP之外运行查询,并且列值已硬编码,它仍然使用聚集索引扫描:@Tom:请发布准确的表定义好吗?
SELECT 
    object_name = Object_Name(ind.object_id),
    IndexName = ind.name,
    StatisticsDate = STATS_DATE(ind.object_id, ind.index_id)
FROM SYS.INDEXES ind
order by STATS_DATE(ind.object_id, ind.index_id) desc