我有一张有两个指数的表格;一个是多列聚簇索引,在3列上:
(
symbolid int16,
bartime int32,
typeid int8
)
第二个是非群集
(
bartime int16
)
我正在尝试运行的select语句是:
SELECT symbolID, vTrdBuy
FROM mvTrdHidUhd
WHERE typeID = 1
AND barDateTime = 44991
AND symbolid in (1010,1020,1030,1040,1050,1060)
我使用sql management studio编辑器在sql2008上运行此查询并启用实际执行计划,我发现sql使用第二个索引并且propse为三列(symbolid,bartime,typeid)创建一个新索引但是非聚集! ! (我认为它说非聚集索引,因为已经聚集了一个)
这个选择是错误的,我再次运行相同的查询并强制SQL使用clusted索引(使用“with index”)并且性能更好。
我有两个问题,一个与此行为相关,第二个问题与查询本身相关
"where"
条件中使用哪一个以获得更好的性能symbolid in(1010,1020,1030,1040,1050,1060)
(symbolid = 1010或symbolid = 1020 ..etc)
((1010和1060之间)的符号)
测试后
我发现当我使用IN更改where条件时使用> =和< = bartime列上的非聚集索引比3列上的聚簇索引更好。
所以我有两种情况,如果WHERE使用IN,最好使用聚集索引,如果它包含> =和< =它使用第二种情况。
答案 0 :(得分:3)
SELECT symbolID, vTrdBuy
FROM mvTrdHidUhd
WHERE typeID = 1
AND barDateTime = 44991
AND symbolid IN (1010,1020,1030,1040,1050,1060)
此条件不包含在您的聚集索引的单个连续范围内。
这些行:
1010, 44991, 1
1010, 50000, 1
1020, 44991, 1
将在索引中按顺序排列,但您的查询将选择第一个和第三个,跳过第二个。
如果谓词数量有限, SQL Server
可以使用Clustered Index Seek
,例如IN
案例。在这种情况下,它使用多个范围:
SELECT symbolID, vTrdBuy
FROM mvTrdHidUhd
WHERE (typeID = 1
AND barDateTime = 44991
AND symbolid = 1010)
OR
(typeID = 1
AND barDateTime = 44991
AND symbolid = 1010)
OR …
但是如果BETWEEN
上的symbolid
范围无法构建如此有限数量的谓词,那就是它恢复效率较低的Clustered Index Scan
(symbolid
扫描的原因SELECT symbolID, vTrdBuy
FROM (
SELECT DISTINCT symbolid
FROM mvTrdHidUhd
WHERE symbolid BETWEEN 1010 AND 1050
) s
JOIN mvTrdHidUhd m
ON m.symbolid = s.symbolid
AND m.typeID = 1
AND m.barDateTime = 44991
并且只是过滤掉错误的结果。)
在这种情况下,您的非聚集索引表现更好。
您可以像这样重写您的查询:
Clustered Index Seek
,也会在您的桌子上使用DISTINCT symbolid
,以构建{{1}}列表并加入此列表。
答案 1 :(得分:0)
更新表/索引的统计信息可能会使其选择正确的索引
答案 2 :(得分:0)
尽可能使用symbolid BETWEEN 1010 AND 1050
。使用BETWEEN
或=
或>=
或>
或<
n或<=
或这些与AND
的组合与使用OR
或IN
相比,通常会带来更好的效果和更好的索引选择。
答案 3 :(得分:0)
索引列的顺序可能会影响优化器是否会选择您的索引。您指示索引是(symbolid int16,bartime int32,typeid int8),但symbolid是where子句中最不相同的值。这将需要6个索引查找您拥有的6个值。
我可能会从介绍语句开始,但只测试您的数据,服务器,索引等将证明是最好的情况。
如果您要创建另一个索引,请尝试这些列的其他2个订单。
如其他地方所述,请更新您的统计信息
答案 4 :(得分:0)
您还可以尝试覆盖索引(symbolid,bartime,typeid,mvTrdBuy)
答案 5 :(得分:0)
您的查询引用四个列:
虽然聚集索引仅涵盖其中三个
SQL Server忽略该索引的原因是它对它没用。索引首先按symbolID
排序,您不需要特定的symbolID,而是一堆随机值。这意味着它必须遍历整个表格。
聚集索引中的下一列是vTrdBuy
。这不是用来帮助它跳到它实际想要的行。
查看查询时,两列非常具体,用于限制要返回的行:
WHERE typeID = 1
AND barDateTime = 44991
创建以 typeID 和 barDateTime 开头的索引,对于帮助SQL Server跳转到 感兴趣的行非常有用。
第一个SQL Server可以直接跳转到
行typeID = 1.
在那里,它可以直接跳到酒吧
barDateTime = March 8, 2023
它可以通过索引来搜索,因为索引是按其中的列排序的。这是非常快的,它消除了大部分行被查看。
如果您要创建索引:
(
typeID
barDateTime
symbolID
)
如果查询返回很多行,它仍然可能没用。为了完成SELECT语句,SQL Server仍然需要 vTrdBuy 值。它必须通过跳过符合条件的行的
您希望阻止书签查找,让它不必返回表中缺失值,您希望在索引中包含该值:
CREATE INDEX IX_mvTrdHidUhd_FancyCovering ON mvTrdHidUhd
(
typeID, barDateTime, symbolID, vTrdBuy
)
现在你有一个索引按照它想要的顺序包含SQL Server想要的所有内容,而且你不必搞乱物理表的物理排序(即集群)。