行存储和列存储
行存储
场景:数据维护,数据检索
列存储
场景:数据分析
索引的了解
聚集索引
-
聚集索引中,叶节点包含基础表的数据页。
-
数据链内的页和行将按聚集索引键值进行排序。
-
主键通常是聚集索引,但可以不是聚集索引。
非聚集索引
-
基础表的数据行不会根据其非聚集键按顺序排序和存储。
-
非聚集索引的叶级别是由索引页而不是由数据页组成。
-
非聚集索引的叶级别的索引页包含键列以及包含列。
SQL Server查找数据记录的几种方式:
1.Table Scan
--表扫描(最慢),对表记录逐行进行检查,对于没有索引或者查询条件不走索引时会进行全表扫描;
2.Clustered Index Scan
--聚集索引扫描(较慢),按聚集索引对记录逐行进行检查,对有主键/聚集索引的表进行无条件查找或者使用主键/聚集索引过滤;
3.Index Scan
--索引扫描(普通),根据索引滤出部分数据在进行逐行检查,;
4.Index Seek
--索引查找(较快),根据索引定位记录所在位置再取出记录,建立非聚集索引并把其他显示列加入索引中;
5.Clustered Index Seek
--聚集索引查找(最快),直接根据聚集索引获取记录,建立非聚集索引并把其他显示列加入索引中并把聚集索引列当作条件;
6.Key Lookup
--书签查找:通过非聚集索引找到所求的行,但这个索引并不包含显示的列,因此还要额外去基本表中找到这些列,所以要进行键查找,如果基本表在堆中则Key Lookup会变成RID查找。
7.RID
--书签查找:同上
如果有些SQL执行很慢,可以用执行计划看一下是否包含太多“扫描”操作,可以考虑为这些字段建立索引,建立索引切记不要再经常有更新操作的字段上建立,每次更新数据和插入数据都会导致重建索引的操作,会增加索引的维护成本。
Showplan 运算符 | 说明 | |
---|---|---|
Table Scan | Table Scan 运算符从查询执行计划的 Argument 列所指定的表中检索所有行。 如果 WHERE:() 谓词出现在 Argument 列中,则仅返回满足此谓词的那些行。 Table Scan 既是一个逻辑运算符,也是一个物理运算符。 |
|
Clustered Index Scan | Clustered Index Scan 运算符会扫描查询执行计划的 Argument 列中指定的聚集索引。 存在可选 WHERE:() 谓词时,则只返回满足该谓词的那些行。 如果 Argument 列包含 ORDERED 子句,则表示查询处理器已请求按聚集索引排列行的顺序返回行输出。 如果没有 ORDERED 子句,存储引擎将以最佳方式扫描索引,而无需对输出进行排序。 Clustered Index Scan 既是一个逻辑运算符,也是一个物理运算符。 |
|
Index Scan | Index Scan 运算符从 Argument 列中指定的非聚集索引中检索所有行。 如果可选的 WHERE:() 谓词出现在 Argument 列中,则仅返回满足此谓词的那些行。 Index Scan 既是一个逻辑运算符,也是一个物理运算符。 |
|
Index Seek | Index Seek 运算符利用索引的查找功能从非聚集索引中检索行。 Argument 列包含所使用的非聚集索引的名称。 它还包括 SEEK:() 谓词。 存储引擎仅使用索引来处理满足 SEEK:() 谓词的行。 它可能还包含一个 WHERE:() 谓词,其中存储引擎对满足 SEEK:() 谓词的所有行进行计算(不使用索引来完成)。 如果 Argument 列包含 ORDERED 子句,则表示查询处理器已决定必须按非聚集索引排序行的顺序返回行。 如果没有 ORDERED 子句,则存储引擎将以最佳方式(不保证对输出排序)搜索索引。 如果让输出保持其顺序,则效率可能低于生成非排序输出。 Index Seek 既是一个逻辑运算符,也是一个物理运算符。 |
|
Clustered Index Seek | Clustered Index Seek 运算符可以利用索引的查找功能从聚集索引中检索行。 Argument 列包含所使用的聚集索引名称和 SEEK:() 谓词。 存储引擎仅使用索引来处理满足此 SEEK:() 谓词的行。它还包括 WHERE:() 谓词,其中存储引擎对满足 SEEK:() 谓词的所有行进行计算, 但此操作是可选的,并且不使用索引来完成此过程。 如果 Argument 列包含 ORDERED 子句,则表示查询处理器已决定必须按聚集索引排序行的顺序返回行。 如果没有 ORDERED 子句,存储引擎将以最佳方式搜索索引,而不对输出进行必要的排序。 若允许输出保持顺序,则效率可能比生成非排序输出的效率低。 出现关键字 LOOKUP 时,将执行书签查找。 在 SQL Server 2008 (10.0.x) 及更高版本中,键查找运算符提供书签查找功能。 Clustered Index Seek 既是一个逻辑运算符,也是一个物理运算符。 |
|
Key Lookup | Key Lookup 运算符是在具有聚集索引的表上进行的书签查找。 Argument 列包含聚集索引的名称和用来在聚集索引中查找行的聚集键。 Key Lookup 通常带有 Nested Loops 运算符。 如果 Argument 列中出现 WITH PREFETCH 子句, 则表示查询处理器已决定在聚集索引中查找书签时将使用异步预提取(预读)作为最佳选择。 在查询计划中使用 Key Lookup 运算符表明该查询可能会从性能优化中获益。 例如,添加涵盖索引可能会提高查询性能。 |
|
RID Lookup | RID Lookup 是使用提供的行标识符 (RID) 在堆上进行的书签查找。 Argument 列包含用于查找表中的行的书签标签和从中查找行的表的名称。 RID Lookup 通常带有 NESTED LOOP JOIN。 RID Lookup 是一个物理运算符。 有关书签查找的详细信息,请参阅 MSDN SQL Server 博客中的Bookmark Lookup(书签查找)。 |
数据 JOIN方式
在SQL Server中,每个join命令,都会在内部执行时采用这几种更具体的方式来运行:
Nested Loops join
:如果一个联接输入很小,而另一个联接输入很大而且已在其联接列上创建了索引, 则索引 Nested Loops 连接是最快的联接操作,因为它们需要的 I/O 和比较都最少。嵌套循环联接也称为“嵌套迭代”,它将一个联接输入用作外部输入表(显示为图形执行计划中的顶端输入),将另一个联接输入用作内部(底端)输入表。外部循环逐行处理外部输入表。内部循环会针对每个外部行执行,在内部输入表中搜索匹配行。最简单的情况是,搜索时扫描整个表或索引;这称为“单纯嵌套循环联接”。如果搜索时使用索引,则称为“索引嵌套循环联接”。如果将索引生成为查询计划的一部分(并在查询完成后立即将索引破坏),则称为“临时索引嵌套循环联接”。
如果外部输入较小而内部输入较大且预先创建了索引,则嵌套循环联接尤其有效。在小事务中(只影响较少数据的事务),索引嵌套循环联接优于合并联接和哈希联接,但在大型查询中,嵌套循环联接通常不是最佳选择。
-
Merge Join
:如果两个联接输入并不小但已在二者联接列上排序(例如,如果它们是通过扫描已排序的索引获得的),则合并联接是最快的联接操作。如果两个联接输入都很大,而且这两个输入的大小差不多,则预先排序的合并联接提供的性能与哈希联接相近。但是,如果这两个输入的大小相差很大,则哈希联接操作通常快得多。合并联接要求两个输入都在合并列上排序,而合并列由联接谓词的等效 (ON) 子句定义。通常,查询优化器扫描索引(如果在适当的一组列上存在索引),或在合并联接的下面放一个排序运算符。在极少数情况下,虽然可能有多个等效子句,但只用其中一些可用的等效子句获得合并列。 -
Hash Join
:哈希联接可以有效处理未排序的大型非索引输入。它们对复杂查询的中间结果很有用,因为:①.中间结果未经索引(除非已经显式保存到磁盘上然后创建索引),而且通常不为查询计划中的下一个操作进行适当的排序。②.查询优化器只估计中间结果的大小。由于对于复杂查询,估计可能有很大的误差,因此如果中间结果比预期的大得多,则处理中间结果的算法不仅必须有效而且必须适度弱化。哈希联接可以减少使用非规范化。非规范化一般通过减少联接操作获得更好的性能,尽管这样做有冗余之险(如不一致的更新)。哈希联接则减少使用非规范化的需要。哈希联接使垂直分区(用单独的文件或索引代表单个表中的几组列)得以成为物理数据库设计的可行选项。
Showplan 运算符 | 说明 | |
---|---|---|
合并联接 Merge Join |
Merge Join 运算符执行内部联接、左外部联接、左半部联接、左反半部联接、右外部联接、右半部联接、右反半部联接和联合逻辑运算。 在 Argument 列中,如果操作执行一对多联接,则 Merge Join 运算符将包含 MERGE:() 谓词;如果操作执行多对多联接,则该运算符将包含 MANY-TO-MANY MERGE:() 谓词。 Argument 列还包含一个用于执行操作的列的列表,该列表以逗号分隔。 Merge Join 运算符要求在各自的列上对两个输入进行排序,这可以通过在查询计划中插入显式排序操作来实现。 如果不需要显式排序(例如,如果数据库内有合适的 B 树索引或可以对多个操作(如合并联接和对汇总分组)使用排序顺序),则合并联接尤其有效。 Merge Join 是一个物理运算符。 有关详细信息,请参阅理解合并联接。 |
|
Nested Loops | Nested Loops 运算符执行内部联接、左外部联接、左半部联接和左反半部联接逻辑运算。 嵌套循环联接通常使用索引,针对外部表的每一行在内部表中执行搜索。 查询处理器根据预计的开销来决定是否对外部输入进行排序,以改进内部输入索引上的搜索定位。 将基于所执行的逻辑操作返回所有满足 Argument 列中的(可选)谓词的行。 如果 OPTIMIZED 特性设置为“True”,则表示使用了优化的嵌套循环(或批处理排序)。 Nested Loops 是一个物理运算符。 有关详细信息,请参阅了解嵌套循环联接。 |
|
无 | Hash join | 哈希联接可以有效处理未排序的大型非索引输入。 它们对复杂查询的中间结果很有用,因为: 中间结果未经索引(除非已经显式保存到磁盘上然后创建索引),而且通常不为查询计划中的下一个操作进行适当的排序。 查询优化器只估计中间结果的大小。 由于对于复杂查询,估计可能有很大的误差,因此如果中间结果比预期的大得多,则处理中间结果的算法不仅必须有效而且必须适度弱化。 哈希联接可以减少使用非规范化。 非规范化一般通过减少联接操作获得更好的性能,尽管这样做有冗余之险(如不一致的更新)。 哈希联接则减少使用非规范化的需要。 哈希联接使垂直分区(用单独的文件或索引代表单个表中的几组列)得以成为物理数据库设计的可行选项。 哈希联接有两种输入:生成输入和探测输入。 查询优化器指派这些角色,使两个输入中较小的那个作为生成输入。 哈希联接用于多种设置匹配操作:内部联接;左外部联接、右外部联接和完全外部联接;左半联接和右半联接;交集;并集和差异。 此外,哈希联接的某种变形可以进行重复删除和分组,例如 SUM(salary) GROUP BY department。 这些修改对生成和探测角色只使用一个输入。 |
参考:
显示计划逻辑运算符和物理运算符参考 - SQL Server | Microsoft Learn
标签:排序,性能,SQLSERVER,查询,运算符,索引,联接,优化,聚集 From: https://www.cnblogs.com/tangge/p/17968884