优化我的SQL查询 - 选择正确的索引

时间:2013-09-25 16:29:00

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

我有一个基本表格如下。

create table Orders
(
    ID INT IDENTITY(1,1) PRIMARY KEY,
    Company VARCHAR(3),
    ItemID INT,
    BoxID INT,
    OrderNum VARCHAR(5),
    Status VARCHAR(5),
    --about 10 more columns, varchars and ints and dates
)

我正在尝试优化我的所有SQL,因为我遇到了一些死锁和一些缓慢的问题 - 但我不是这方面的专家!

我创建了一些索引:
在ID(主键)上聚集。
([ItemID])上的非聚集索引 ([BoxID])上的非聚集索引 ([公司],[订单号],[状态])上的非聚集索引 在其他一些专栏上可能还有1或2个

但我对结果并不满意。

SELECT * FROM Orders WHERE ItemID=100

给我一​​个索引搜索+一个键查找和一个嵌套循环(内连接)。 我明白为什么 - 但不知道我是否应该采取任何措施。他们的密钥查找是批次的97%,看起来很糟糕!

使用的每个查询都会拉回表中的每一列,但我不喜欢在索引中包含每一列的想法。

我现在正在进行更改,以查询[公司]字段中的所有内容每个查询都将使用它,因为从不的结果应包含多于1个值。所以他们都会改变:

SELECT * FROM Orders WHERE ItemID=100    --Old
SELECT * FROM Orders WHERE Company='a' and ItemID=100    --New

但是执行计划给了我完全相同的不包括公司(这让我感到惊讶!)。

  • 为什么两个执行计划高于同一个? (目前我[公司]没有索引)

  • 是否值得将[公司]添加到我的所有索引中,因为它似乎可以 0与执行计划不同?

  • 我应该只为[公司]添加1个单一索引并保留原始索引吗? - 但那会 意味着每个查询都有2个搜索?

  • 是否值得“包括”索引中的所有其他列以避免使用 密钥查找? (使得该指数更大,但可能 加快速度?),即

    CREATE NONCLUSTERED INDEX [IX_Orders_MyIndex] ON [Orders]
    ( [Company] ASC, [OrderNum] ASC, [Status] ASC )
    INCLUDE ([ID],[ItemID],[BoxID],
    [Column5],[Column6],[Column7],[Column8],[Column9],[Column10],etc)
    

如果我在4或5个索引上做到这一点,那似乎很麻烦。

基本上我有4-5个经常运行的查询(有些选择和更新),所以我想让它尽可能高效。 所有查询都将使用[company]字段,至少还有1个。我应该怎么做呢。

任何帮助表示赞赏:)

1 个答案:

答案 0 :(得分:3)

在执行计划中,您说查找占批次的97%。

在这种情况下,它并不意味着什么,因为索引搜索速度非常快,而且您没有那么多操作要做。

该查找实际上是您根据指定的索引读取的记录。

为什么两个执行计划高于同一个? (目前我[公司]没有索引)

Non-Clustered index on ([Company],[OrderNum],[Status])

仅当您的where子句中出现CompanyOrderNumStatus时,才会考虑此索引。

当仅传递company时,连续索引会生成一个看起来像0000000000000的密钥,它会创建一个不完整的密钥,需要使用通配符将另一个密钥用于值。

看起来有点像这样:key like 'XXX%'这个逻辑需要一个耗时的索引扫描。

优化程序将确定首先从ItemID索引中搜索和排序,然后扫描这些索引以匹配所需公司的任何内容。

是否值得将[公司]添加到我的所有索引中,因为它似乎与执行计划有所不同?

您应该考虑使用Company索引,而不是将其添加到所有索引中。 复合索引可以通过减少嵌套循环的数量来加快速度,但是你必须彻底思考。

您添加到此类索引的字段的顺序非常重要,它们应按唯一性排序,以便更好地进行搜索。此外,您永远不应添加可能未在查询中使用的字段。

我应该只为[公司]添加1个单一索引并保留原始索引吗? - 但这是否意味着每个查询都有2次搜索?

有多个索引搜索并不是那么糟糕,它们通常是并行的,只有两者的结果匹配在一起。

是否值得“包括”索引中的所有其他列以避免密钥查找? (使指数变得更大,但可能加速它?)

值得一提的是,只有少数几个字段在where子句中是可选的,或者当您使用指定索引时只有那些字段时才会选择这些字段。

最后的注释

所有索引都不相等,比较字符串(varchar)与比较数字(整数,日期时间,字节等)不同。

另外,保持它们清洁有很大帮助,如果你的索引碎片化,它们在性能提升方面将毫无用处。