【翻译】SQL Server索引进阶:第二级,深入非聚集索引

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:


我们先来介绍一些理论,了解一些索引的内部信息,帮助我们解释理论,然后执行一些查询。这些查询会在包含和不包含索引的两种情况被执行,开启性能报告,我们可以看到索引产生的影响。

我们继续使用AdventureWorks 数据库的部分表,主要集中在Contact表。我们将只是用一个索引,在上一级中使用的FullName索引,来证明我们的观点。为了确保我们很好的控制Contact表的索引,我们将做两份拷贝,一份建立FullName索引,一份不建立索引。

 

 
  1. IF EXISTS ( 
  2.  
  3.     SELECT * 
  4.  
  5.         FROM sys.tables 
  6.  
  7.         WHERE OBJECT_ID = OBJECT_ID('dbo.Contacts_index')) 
  8. DROP TABLE dbo.Contacts_index; 
  9. GO 
  10. IF EXISTS ( 
  11.  
  12.     SELECT * 
  13.  
  14.         FROM sys.tables 
  15.  
  16.         WHERE OBJECT_ID = OBJECT_ID('dbo.Contacts_noindex')) 
  17.  
  18.     DROP TABLE dbo.Contacts_noindex; 
  19. GO 
  20. SELECT * INTO dbo.Contacts_index 
  21.  
  22.     FROM Person.Contact; 
  23. SELECT * INTO dbo.Contacts_noindex 
  24.  
  25.     FROM Person.Contact; 



非聚集索引

在Contacts_index 表建立非聚集索引

   
 

 
  1. CREATE INDEX FullName 
  2.  
  3.         ON Contacts_index 
  4.  
  5. ( LastName, FirstName ); 



请记住,非聚集索引顺序存储索引键,通过标记来访问表中真正的数据。你可以把标签看做一种指针。将来的级别中会描述标签的格式,标签的用法,标签的细节。

另外,SQL Server的非聚集索引的入口还有一些内部使用的头信息,还有一些可选的数据值。这些在后面的文章中都会有介绍,现在都不是重点内容。

到目前为止,我们只需要知道,键使得SQL Server找到合适的索引入口,入口的标签使得SQL Server访问表对应的行数据。

索引入口有序的好处

索引的入口是有序的,因此SQL Server可以快速的定位入口。扫描可以从头部开始,可以从尾部开始,也可以从中间开始。

因此,如果一个查询,请求所有LastName以S开头的Contact用户(where lastname like 's%')。SQL Server会快速定位到第一个S开头的记录,然后通过索引,使用标签访问数据行,直到第一个T开头的记录。

如果选择的列都包含在索引中,上面的查询会执行的更快。如果我们执行

 

 
  1. SELECT FirstName, LastName 
  2.  
  3.     FROM Contact 
  4.  
  5.     WHERE LastName LIKE 'S%'



SQL Server快速的导航到S入口,然后通过索引,忽略标签,直接从索引的入口返回数据,直到第一个T入口。在关系数据库的名词中,叫做查询全覆盖索引。

很多SQL的操作都可以从索引中受益,包括:ORDER BY, GROUP BY, DISTINCT, UNION( not UNION ALL ), JOIN ... ON 。

谨记从左到右的键顺序的重要性。我们建立的索引对于lastname=“ashton”很管用,但是对于firstname=“ashton”作用会小很多,甚至没有用。

测试一些简单的查询

如果你要执行下面的查询,确保你执行了前面的脚本,创建了contact_index和contact_noindex表,而且也在contact_index表创建了LastName, FirstName索引。

开启统计

 

 
  1. SET STATISTICS io ON 
  2.  
  3. SET STATISTICS time ON 



因为contact表中的数据只有19972行,很难得到有意义的统计时间。大部分的查询都显示CPU time: 0 毫秒,因此我们可以关闭time统计,只显示io统计。如果你需要一张大表来统计真实的time信息,可以用文章后面的脚本构建一个百万行数据的contact表。下面的测试都以19972行的表为测试对象。


测试一个完全覆盖的查询


第一个查询是一个覆盖索引的查询,获取contact表中lastname以S开头的记录的一部分列。下面是执行的信息。

 

SQL语句 SELECT FirstName, LastName
FROM dbo.Contacts  -- execute with both Contacts_noindex and
-- Contacts_index
WHERE LastName LIKE 'S%'
没有索引的情况下 (2130 row(s) affected)
Table 'Contacts_noindex'. Scan count 1, logical reads 568.
有索引的情况 (2130 row(s) affected)
Table 'Contacts_index'. Scan count 1, logical reads 14.
索引产生的影响 IO从568次减少到14次
注释 覆盖查询的索引是个好东西。没有索引,就会进行全表扫描。2130行,表明以S开头的记录占到了10%的数据。

 

 

 

 

 

 

 

 

 

测试一个非完全覆盖的查询

我们修改一下查询,还是相同的查询,只是获取的列包含了一些没有建立索引的列,下面是执行的结果。

 

SQL语句 SELECT *
FROM dbo.Contacts  -- execute with both Contacts_noindex and
-- Contacts_index
WHERE LastName LIKE 'S%'
没有索引的情况下 (2130 row(s) affected)
Table 'Contacts_noindex'. Scan count 1, logical reads 568.
有索引的情况 (2130 row(s) affected)
Table 'Contacts_index'. Scan count 1, logical reads 568.
索引产生的影响 IO没有影响
注释 在查询的过程中没有使用到索引。在这种情况下,SQL Server觉得使用索引查找,比不适用索引直接扫描,还要做更多的工作。

 

 

 

 

 

 

 

 

 

测试一个非完全覆盖的查询,但是提供更多的条件

我们修改一下查询,还是相同的查询,只是缩减了查询结果的范围,增加使用索引的好处,下面是执行的结果。

 

SQL语句 SELECT *
FROM dbo.Contacts  -- execute with both Contacts_noindex and
-- Contacts_index
WHERE LastName LIKE 'Ste%'
没有索引的情况下 (107 row(s) affected)
Table 'Contacts_noindex'. Scan count 1, logical reads 568.
有索引的情况 (107 row(s) affected)
Table 'Contact_index'. Scan count 1, logical reads 111.
索引产生的影响 IO从568次减少到111次。
注释

SQL Server访问了107条入口,都在索引的连续范围内。每个入口的标签都被用来获取对应的行数据。这些行在表中不是连续的。

这些查询用到了索引,但是不如第一次的覆盖查询效果好,尤其是在IO的读取方面。

你希望读取107次索引,然后获取107条数据,产生107次读取。

之前的查询,请求了2130行数据,没有用到索引。这次请求107行数据,使用了索引。你很像知道使用索引的临界点在哪里?在后面的级别中我们将会介绍这方面的内容。

 

 

 

 

 

 

 

 

 

 

 

 

 


测试一个完全覆盖的聚合查询


最后一个例子是一个聚合查询,包含了count计算。

 

SQL语句 SELECT LastName, FirstName, COUNT(*) as 'Contacts'
FROM dbo.Contacts  -- execute with both Contacts_noindex and
-- Contacts_index
WHERE LastName LIKE 'Ste%'
GROUP BY LastName, FirstName
没有索引的情况下 (2130 row(s) affected)
Table 'Contacts_noindex'. Scan count 1, logical reads 568.
有索引的情况 (104 row(s) affected)
Table 'Contacts_index'. Scan count 1, logical reads 4.
索引产生的影响 IO从568次减少到4次
注释 所有需要查询的信息都包含在索引中,很好的使用了索引。

 

 

 

 

 

 

 

 

 

测试一个非完全覆盖的聚合查询

我们修改一下查询,还是相同的查询,只是获取的列包含了一些没有建立索引的列,下面是执行的结果。

 

SQL语句 SELECT LastName, FirstName, MiddleName, COUNT(*) as 'Contacts'
FROM dbo.Contacts  -- execute with both Contacts_noindex and
-- Contacts_index
WHERE LastName LIKE 'Ste%'
GROUP BY LastName, FirstName, MiddleName
没有索引的情况下 (2130 row(s) affected)
Table 'Contacts_noindex'. Scan count 1, logical reads 568.
有索引的情况 (105 row(s) affected)
Table 'ContactLarge'. Scan count 1, logical reads 111.
索引产生的影响 IO从568次减少到111次
注释

 

 

 

 

 

 

 

 

 

 

结论

当目前位置,我们知道非聚集索引有下面的一些好处:

  • 是一些有序的入口集合。
  • 表中的每一行都有一个入口。
  • 包含一个索引键和一个标签。
  • 用户负责创建的。
  • SQL Server来维护。
  • SQL Server用来最小化查询尝试,来满足客户的请求。

通过一些例子,我们看到SQL Server通过索引可以满足查询的请求,也有一些查询会完全忽略索引,还有一些会部分的使用索引。基于这个原因,我们来更新一下在第一级中的一个结论。

当一个请求到达数据库的时候,SQL Server只有三种访问数据的方式:

  1. 访问非聚集索引,避免访问表。这只发生在索引包含了请求中的所有数据。
  2. 通过索引键访问非聚集索引,然后使用标签访问表中的行数据。
  3. 忽略非聚集索引,扫描表找到请求的行数据。

通常来说,第一种是理想的,第二种要比第三种好。在之前的介绍中,我们知道了如何增加索引的使用可能性,如何决定更高效的使用非聚集索引。但是我们需要知道更多的索引内部的细节。

在我们知道细节之前,我们还需要介绍其他类型的SQL Server索引:聚集索引。

代码下载

 




本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/984780,如需转载请自行联系原作者

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
8天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
51 10
|
28天前
|
SQL 存储 数据库
sql事务、视图和索引
sql事务、视图和索引
14 0
|
18天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
16 0
|
8天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
66 6
|
3天前
|
SQL 安全 网络安全
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
8 0
|
8天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
10天前
|
SQL 数据库 索引
SQL索引失效原因分析与解决方案
SQL索引失效原因分析与解决方案
19 0
|
12天前
|
SQL 数据安全/隐私保护
SQL Server 2016安装教程
SQL Server 2016安装教程
16 1
|
12天前
|
SQL 安全 Java
SQL server 2017安装教程
SQL server 2017安装教程
14 1
|
25天前
|
SQL 存储 Python
Microsoft SQL Server 编写汉字转拼音函数
Microsoft SQL Server 编写汉字转拼音函数