sql查询初学者指南

Now that we understand what Clustered Index Scan and Clustered Index Seek are, how they occur, and how to eliminate table scans in my previous article SQL Server Query Execution Plans for beginners – Clustered Index Operators, the next topic would be looking at Non-Clustered Indexes

现在,在我之前的文章面向初学者SQL Server查询执行计划–聚簇索引运算符中 ,我们了解了聚簇索引扫描和聚簇索引查找是什么,如何发生以及如何消除表扫描,下一个主题是非聚簇指标

We can start off with the Non-Clustered Index Scan …

我们可以从非聚集索引扫描开始……

非聚集索引扫描 (Non-Clustered Index Scan)

  • When 什么时候

    • A Non-Clustered Index Scan occurs when columns are part of the non-clustered index and the query goes about accessing a large amount of data across this particular index 当列是非聚集索引的一部分时,就会发生非聚集索引扫描,并且查询将通过该特定索引访问大量数据
  • Good or Bad 是好是坏
    • Bad unless large data with most columns and rows retrieved 除非获取的大多数数据具有最多的列和行,否则不正确
  • Action Item 行动项目
    • The action item here is pretty clear. Just look at redefining or refining your Non-Clustered Index. By considering the columns configured in that NON-Clustered index 这里的动作项非常清楚。 只需看看重新定义或完善非聚集索引即可。 通过考虑在该非聚集索引中配置的列

After refining your Non-Clustered Index, you might get into a Non-Clustered Index Seek.

完善非聚集索引之后,您可能会进入非聚集索引搜索。

非聚集索引搜寻 (Non-Clustered Index Seek)

  • When 什么时候

    • Non-Clustered Index Seek occurs when Columns part of non-clustered index accessed in query and rows located in the B+ tree 当在查询中访问非聚集索引的Columns部分以及位于B +树中的行时,发生非聚集索引查找
  • Good or Bad 是好是坏
    • It is good and ideal to have a Non-Clustered Index Seek 进行非聚集索引查找是很好且理想的选择
  • Action Item 行动项目
    • Evaluate other operators 评估其他运算符

Let us take a quick example to see how this can be seen and some of the options and methods to go ahead and mitigate.

让我们举个简单的例子,看看如何看待这种情况,以及一些继续进行和缓解的选择和方法。

We are going to use the same table that we created in my previous article.

我们将使用与上一篇文章中创建的表相同的表。

Then, you can notice some interesting options using that data which will make it very clear on how to get the most performance using non-clustered indexes.

然后,您会注意到使用该数据的一些有趣选项,这将使您非常清楚如何使用非聚集索引获得最佳性能。

First, let us create one non-clustered index based on [OrderQty] and [ProductID] columns.

首先,让我们基于[OrderQty]和[ProductID]列创建一个非聚集索引。

CREATE NONCLUSTERED INDEX [IX_MySalesOrderDetail_OrderQty_ProductID]
ON [SQL_SHACK].[dbo].[MySalesOrderDetail]
([OrderQty],[ProductID])
GO

Now, we can execute the following script and enable include actual execution plan.

现在,我们可以执行以下脚本并启用包含实际的执行计划。

SET STATISTICS IO ON
GO
SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty
FROM [SQL_SHACK].[dbo].[MySalesOrderDetail]

This will show us the result of 121,317 rows and 303 logical reads. Hence, you can see that I was doing a select some columns from an actual table where the query could get satisfied from the non-clustered key and hence, you got a scan of non-cluster.

这将向我们显示121,317行和303个逻辑读取的结果。 因此,您可以看到我正在从实际表中选择一些列,可以从非集群键中满足查询,因此,您可以扫描非集群。

Interestingly, if I go ahead and add a where condition on the [ProductID] column:

有趣的是,如果我继续在[ProductID]列上添加where条件:

SET STATISTICS IO ON
GO
SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty
FROM [SQL_SHACK].[dbo].[MySalesOrderDetail]
WHERE ProductID = 799
GO

It is obvious that we have got the result of 648 rows which is less than the previous result but SQL Server has done the same 303 logical reads and we still did not use non-clustered index seek. So, how can I change and refine to redefine the non-clustered index so that it can start getting better results and a better plan?

显然,我们得到了648行的结果,该结果比以前的结果要少,但是SQL Server进行了303次相同的逻辑读取,并且我们仍然没有使用非聚集索引查找。 因此,如何更改和优化以重新定义非聚集索引,以便可以开始获得更好的结果和更好的计划?

One of the methods that can be used here is to change the where conditions to add additional information so that SQL Server can use the non-clustered index effectively.

此处可以使用的方法之一是更改where条件以添加其他信息,以便SQL Server可以有效地使用非聚集索引。

Remember, we had the index created on order quantity and product ID.

记住,我们已经在订单数量和产品ID上创建了索引。

I will add the order quantity condition as I know that the order quantity is always greater than zero. and in my previous example, I had got 648 rows.

我将添加订单数量条件,因为我知道订单数量始终大于零。 在前面的示例中,我有648行。

SET STATISTICS IO ON
GO
SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty
FROM [SQL_SHACK].[dbo].[MySalesOrderDetail]
WHERE ProductID = 799 AND OrderQty > 0
GO

On execution of this particular query gives me the same 648 rows.

执行此特定查询后,我得到了相同的648行。

Although the messages show me a logical read of 303 yet, you can see the index that is used, the physical operation that is used is an index seek.

尽管消息显示逻辑读取为303,但是您可以看到所使用的索引,但所使用的物理操作是索引查找。

Another method to play over here is to redefine the particular index which for that query by reordering the columns in the index:

在此播放的另一种方法是通过对索引中的列进行重新排序来重新定义针对该查询的特定索引:

drop INDEX [IX_MySalesOrderDetail_OrderQty_ProductID]
ON [SQL_SHACK].[dbo].[MySalesOrderDetail]
CREATE NONCLUSTERED INDEX [IX_MySalesOrderDetail_ProductID_OrderQty]
ON [SQL_SHACK].[dbo].[MySalesOrderDetail]
([ProductID],[OrderQty])
GO

Then we can execute our original query with only the condition of [ProductID] column:

然后,我们可以仅使用[ProductID]列的条件来执行原始查询:

SET STATISTICS IO ON
GO
SELECT SalesOrderID, SalesOrderDetailID, ProductID, OrderQty
FROM [SQL_SHACK].[dbo].[MySalesOrderDetail]
WHERE ProductID = 799
GO

Now, we have the most optimal plan with logical reads of 5 only.

现在,我们有了最优化的计划,逻辑读数仅为5。

Hence, you could see when we went ahead creating a non-clustered index and got a non-clustered scan, we used two methods, one of them is redefining the where clauses to get actually an index seek, yet you could see that IO is never reduced.

因此,您可以看到当我们继续创建非聚集索引并进行非聚集扫描时,我们使用了两种方法,其中一种是重新定义where子句以获取实际的索引查找,但是您可以看到IO是永不减少。

The other way that we have used is to actually define a right index of non-clustered in the right order. Here, you can see the IO is reduced considerably.

我们使用的另一种方法是实际上以正确的顺序定义非聚集的正确索引。 在这里,您可以看到IO大大减少了。

This is how we have converted a non-clustered index scan to the most optimal non-clustered index seek.

这就是我们将非聚集索引扫描转换为最佳非聚集索引搜索的方式。

Let us now look at the next operator, lookups …

现在让我们看看下一个运算符,即查找…

查询 (Lookups )

  • When 什么时候

    • Query Optimizer uses the non-clustered index to search few column data and base table for other columns data 查询优化器使用非聚集索引来搜索少量列数据,并在基表中搜索其他列数据
  • Good or Bad 是好是坏
    • Bad 坏
  • Action Item 行动项目
    • The best way to mitigate them is to have either a covering index or use an index with included columns 减轻它们的最好方法是使用覆盖索引或使用包含列的索引

Here is a typical example of how lookups would happen using the same sample table:

这是使用相同样本表如何进行查找的典型示例:

SET STATISTICS IO ON
GO
SELECT  SalesOrderID, SalesOrderDetailID, ProductID, OrderQty,SpecialOfferID
FROM [SQL_SHACK].[dbo].[MySalesOrderDetail]
WHERE ProductID = 789
GO

This produced 364 rows with huge 1854 logical reads

这产生了364行,具有1854次巨大的逻辑读取

The execution plan has used a where condition which was based on the [ProductID] column using an index seek non-clustered for the operation and it was seeking another extract column so it had to do what we call as a key lookup.

执行计划使用了基于[ProductID]列的where条件,该条件使用了非聚集操作的索引查找,并且它正在寻找另一个提取列,因此它必须做我们所谓的键查找。

The output list shows this [SpecialOfferID] column which is something that the key lookup was sending out.

输出列表显示此[SpecialOfferID]列,这是密钥查找所发出的内容。

So, this particular column is needed to satisfy the select statement.

因此,需要该特定列来满足select语句。

The first option here, I’m going to create an index, a non-clustered index which is based on covering index.

这里的第一个选项是,我将创建一个索引,它是一个基于覆盖索引的非聚集索引。

DROP INDEX [IX_MySalesOrderDetail_ProductID_OrderQty] ON [SQL_SHACK].[dbo].[MySalesOrderDetail]CREATE NONCLUSTERED  INDEX [IX_MySalesOrderDetail_ProductID_OrderQty_SpecialOfferID]
ON [SQL_SHACK].[dbo].[MySalesOrderDetail]
([ProductID],[OrderQty],[SpecialOfferID])
GO

And execute the same query again:

并再次执行相同的查询:

Now, we have obtained the same result set of 364 rows with logical reads of 6 only and also we have eliminated the key lookup operator.

现在,我们获得了364行的相同结果集,其中逻辑读数仅为6,并且消除了键查找运算符。

Second, is to use all the columns required by the select statement in the included columns of the non-clustered index, as below:

其次,是在非聚集索引的包含列中使用select语句所需的所有列,如下所示:

DROP INDEX [IX_MySalesOrderDetail_ProductID_OrderQty_SpecialOfferID] ON [SQL_SHACK].[dbo].[MySalesOrderDetail]CREATE NONCLUSTERED  INDEX [IX_MySalesOrderDetail_ProductID_OrderQty_SpecialOfferID]
ON [SQL_SHACK].[dbo].[MySalesOrderDetail]
([ProductID])
INCLUDE ([OrderQty],[SpecialOfferID])
GO

And execute the same query again:

并再次执行相同的查询:

Now, we can see that it has done an Index Seek Non-Clustered and the bookmark lookup has been eliminated.

现在,我们可以看到它已经完成了“非聚集索引搜索”,并且取消了书签查找。

摘要 (Summary)

Non-clustered indexes are very important part of performance optimization life cycle. Every DBA should know what exactly can be done with them. I tried here to touch the basics of the non-clustered indexes operators and I hope you found this article helpful.

非聚集索引是性能优化生命周期中非常重要的部分。 每个DBA都应该知道用它们到底可以做什么。 我在这里尝试接触非聚集索引运算符的基础知识,希望对本文有所帮助。

Previous articles in this series:

本系列以前的文章:

  • SQL Server Query Execution Plans for beginners – Types and Options 面向初学者SQL Server查询执行计划–类型和选项
  • SQL Server Query Execution Plans for beginners – Clustered Index Operators 面向初学者SQL Server查询执行计划–聚集索引运算符

参考资料 (References)

  • Nonclustered Index Scan Showplan Operator 非聚集索引扫描Showplan运算符
  • Nonclustered Index Seek Showplan Operator 非聚集索引寻求Showplan运算符
  • Key Lookup Showplan Operator 关键查找Showplan运算符

翻译自: https://www.sqlshack.com/sql-server-query-execution-plans-beginners-non-clustered-index-operators/

sql查询初学者指南

sql查询初学者指南_面向初学者SQL Server查询执行计划–非聚集索引运算符相关推荐

  1. 面向初学者的 SQL Server 查询执行计划(1)——聚集索引运算符(Clustered Index)

    在本文中,我们将讨论与聚集索引相关的各种执行计划运算符,以及它们的作用.它们何时出现以及它们何时出现. 执行计划中的每一个运算符都会提供一些有关 SQL Server 运行方式的指标. 我们需要理解这 ...

  2. sql查询初学者指南_面向初学者SQL Server查询执行计划–类型和选项

    sql查询初学者指南 When a DBA is working with the SQL Server, he/she might sometimes say that the execution ...

  3. sql查询初学者指南_面向初学者SQL Server查询执行计划–聚集索引运算符

    sql查询初学者指南 We have discussed how to created estimated execution plans and actual execution plans in ...

  4. sql查询初学者指南_适用于初学者SQL Server查询优化技巧与实际示例

    sql查询初学者指南 In this article, we will continue to learn essential techniques of the SQL Server query t ...

  5. SQL Server临界点游戏——为什么非聚集索引被忽略!

    当我们进行SQL Server问题处理的时候,有时候会发现一个很有意思的现象:SQL Server完全忽略现有定义好的非聚集索引,直接使用表扫描来获取数据.我们来看看下面的表和索引定义: 1 CREA ...

  6. java初学者书籍_面向初学者的5本最佳Java核心书籍

    java初学者书籍 Today I am sharing the best java books to learn java programming. Java is one of the most ...

  7. sql聚集索引和非聚集索引_SQL Server中非聚集索引概述

    sql聚集索引和非聚集索引 This article gives an introduction of the non-clustered index in SQL Server using exam ...

  8. SQL Server索引概要(2)-非聚集索引(Non-Clustered Index)

    介绍 在上一篇SQL Server 聚集索引概述 中,我们探讨了 SQL Server 中索引和聚集索引的要求. 在我们继续之前,让我们快速总结一下 SQL Server 聚集索引: 它根据聚集索引键 ...

  9. [转]SQL Server 2000执行计划成本(1/5)

    表扫描 当没有合适的索引时就发生表扫描操作.这可能意味着没有索引存在或者预期有很多行且比扫描整个表开销更少.如果表是一个堆表,执行计划显示表扫描操作:如果表有聚集索引或者所有需要的值都在一个非聚集索引 ...

最新文章

  1. 一场事先预告的砸冰箱盛宴
  2. Spring Cloud云服务架构 - common-service 项目构建过程
  3. 使用Nginx实现服务器反向代理和负载均衡
  4. 应用篇——SSL/TLS
  5. Docker中RocketMQ的安装与使用
  6. MAC OS 命令行使用详解
  7. java 泛型 子类_Java泛型:要求泛型成为某种类型的子类
  8. python安装插件报错原因_Sublime Text3 python自动补全问题——Sublime Text3安装Anaconda插件...
  9. Redis中的事务和watch(乐观锁)
  10. Midi 乐器set
  11. Visual studio 2013 err:visual studio no editoroptiondefinition export found for the given option ...
  12. maven 阿里云的镜象
  13. 统计学习方法--提升方法adaBoost算法(集成学习)
  14. php函数 99乘法表,[菜鸟学php] php版自定义函数实现99乘法表
  15. 揭秘:为什么羊毛党可以0元购物?
  16. 天刀霸王枪服务器怎么维护了,霸王枪27日合服 11批天涯合服维护公告
  17. WIN10企业版未激活如何解决
  18. 微信小程序通过服务号推送模板消息
  19. 肝不好的人,这几种食物要多吃!
  20. 【mac 环境】邮箱密码修改后,foxmail无法正常接收邮件

热门文章

  1. 《小米网抢购系统开发实践》读后感
  2. 吴裕雄 15-MySQL LIKE 子句
  3. Codeforces 1041C(贪心+set)
  4. WinSock Socket 池
  5. C语言学习系列(六)基本语法
  6. 【转】聊聊HTTPS和SSL/TLS协议
  7. 操作系统---页面置换算法
  8. error This module isn‘t specified in a package.json file.
  9. 【Express】—post传递参数
  10. mysql服务没有权限开机不会自启动_计算机服务项里没有MySQL服务,无法设置开机自启动或者关闭自启动,的解决办法...