我有这张桌子:
Nodes(IDNode, LeftPath, RightPath);
IDNode LeftPath RightPath
1 1 1Z
2 1.2 1.2Z
3 1.3 1.3Z
4 1.2.4 1.2.4Z
5 5 5Z
6 5.6 5.6Z
LeftPath是节点的左侧路径,RightPath是以" Z"结尾的leftPath。
这是树结构中物化路径的修改。
如果我想要节点1的所有子节点,我只有左路径,我必须使用查询:
select * from Nodes where LeftPath like "1%";
但是,如果我使用rightPath,我可以使用此查询:
select * from Nodes where LeftPath between [1] and [1Z];
如果我有一个LeftPath的索引,当我使用like时,性能比使用之间差吗?因为索引对顺序进行排序,我想它可以快速获得所有儿童。我之间的表现更好吗?
答案 0 :(得分:2)
在考虑该级别的索引类型或其他详细信息之前,您是否查看了要比较的查询的execution plan
? " SQL计划"告诉您,您的查询方法是否正在使用您为优化添加的索引,或者它们是否优于原始的非优化设计。
以下讨论通过一些关键概念来解释原始帖子中解释的观察结果:
LIKE
和BETWEEN
子句的查询是否会受益于列索引?预测:提供的示例的记录集看起来非常小。即使有一个索引并且它正在执行计划中使用,基于堆的表扫描(即逐个遍历所有记录)和使用索引的计划之间的速度可能没有差异。以某种方式组织记录。至于问题(2),关于
query plan caching
的扩展谈话表明了每个SQL运算符的结果之间观察到的差异的原因。
关于原帖中示例的评论:
第二个示例查询根本不涉及列RightPath
。
使用索引并不总是意味着更快,更有效的查询。索引并不总是=更快的查询性能。
我使用MySQL数据库来说明一些仍应扩展到MSSQL RDBMS环境的概念。关键指标将向您证明"缓慢" vs." fast"查询响应包含许多因素,最初可以通过查询EXECUTION PLAN
来识别。在某些情况下甚至没有使用索引。
设置我使用的测试环境(在MySQL中):
CREATE TABLE Nodes
(
IDNode int auto_increment primary key,
LeftPath varchar(20),
RightPath varchar(30)
);
INSERT INTO Nodes (LeftPath, RightPath)
VALUES
('1', '1Z'),
('1.2', '1.2Z'),
('1.3', '1.3Z'),
('1.2.4', '1.2.4Z'),
('5', '5Z'),
('5.6', '5.6Z');
COMMIT;
CREATE TABLE NodesWIndx
(
IDNode int auto_increment primary key,
LeftPath varchar(20),
RightPath varchar(30)
);
CREATE INDEX NodesIndx_Ix1 ON NodesWIndx(LeftPath);
CREATE INDEX NodesIndx_Ix2 ON NodesWIndx(RightPath);
INSERT INTO NodesWIndx (LeftPath, RightPath)
VALUES
('1', '1Z'),
('1.2', '1.2Z'),
('1.3', '1.3Z'),
('1.2.4', '1.2.4Z'),
('5', '5Z'),
('5.6', '5.6Z');
COMMIT;
您的第一个查询是使用您放置的索引。放置在字符串类型列(例如示例)上的非指定索引将从左到右工作,如:
-- Querying a Table WITH an Index
SELECT * FROM NodesWIndx WHERE LeftPath LIKE '1%'
| IDNODE | LEFTPATH | RIGHTPATH |
|--------|----------|-----------|
| 1 | 1 | 1Z |
| 2 | 1.2 | 1.2Z |
| 3 | 1.3 | 1.3Z |
| 4 | 1.2.4 | 1.2.4Z |
查询执行计划和索引利用率
请注意,此查询中的计划显示使用表NodesIndx_Ix1
创建的索引用于帮助查找具有与查询条件匹配的LeftPath
列值的记录。
以下是针对类似表的相同查询以及过滤列上没有索引的数据:
-- Querying a Table WITHOUT an Index
SELECT * FROM Nodes WHERE LeftPath LIKE '1%'
| IDNODE | LEFTPATH | RIGHTPATH |
|--------|----------|-----------|
| 1 | 1 | 1Z |
| 2 | 1.2 | 1.2Z |
| 3 | 1.3 | 1.3Z |
| 4 | 1.2.4 | 1.2.4Z |
查询执行计划和索引利用率
在这种情况下,该计划显示没有使用索引来帮助提供SQL查询结果。
以下是针对类似表的相同查询以及过滤列上没有索引的数据:
-- Querying a Table Using BETWEEN with an Index
SELECT * FROM Nodes WHERE LeftPath BETWEEN '1' and '1Z'
| IDNODE | LEFTPATH | RIGHTPATH |
|--------|----------|-----------|
| 1 | 1 | 1Z |
| 2 | 1.2 | 1.2Z |
| 3 | 1.3 | 1.3Z |
| 4 | 1.2.4 | 1.2.4Z |
查询执行计划和索引利用率
带有BETWEEN
子句的查询似乎也使用为WHERE
条件中使用的列创建的索引。
使用LIKE
或BETWEEN
运算符的查询之间观察到的性能跳跃可能是从先前请求缓存查询执行计划的结果。
每当尝试执行查询时,查询管道都会查找其查询计划缓存,以查看确切的查询是否已编译并可用。 More on SQL Server Query Plan Caching
至少在来自MySQL示例的更简单的执行计划信息中,两个查询都使用了相同的索引优化(possible_keys
值)以及其他剩余的配置文件值。
指数有所作为吗?
索引并不总能提供可预测的性能改进。此外,应该适当选择创建的索引类型(例如,在MSSQL:Unique,Clustered和Non-Clustered等中)以匹配查询的数据类型(及其值的分布),否则RDBMS将忽略索引。
我在选择索引候选人时找到了a useful discussion on best practices。本文最有用的提示是:
大多数数据都可以看到索引的大多数索引性能改进。
究竟有多大?在Microsoft SQL Server article about best practices设置表索引以获得性能提升时,作者仅对DML
和SELECT
运行测试,测试记录集为100万或更多,以便产生显着且可测量的差异在表现。
我或许可以使用SQL Server示例更新一些讨论,但就目前而言,无论您正在查看哪个RDBMS,检查执行计划的概念都保持不变。一些RDBMS平台的计划比其他平台更详细,但在分析SQL查询以进行优化时,它们会使开发人员处于相同的总体方向。