zoukankan      html  css  js  c++  java
  • 第六章——根据执行计划优化性能(1)——理解哈希、合并、嵌套循环连接策略

    前言:

    本系列文章包括:

    1、 理解Hash、Merge、Nested Loop关联策略。

    2、 在执行计划中发现并解决表/索引扫描。

    3、 介绍并在执行计划中发现键查找并解决它们。

    对于性能优化,需要集中处理以下的问题:

    1、 为你的环境创建性能基线。

    2、 监控现在的性能并发现瓶颈。

    3、 解决瓶颈以便得到更好的性能。

    一个预估执行计划是描述查询将会如何执行的一个蓝图,而一个实际执行计划就是一个查询执行时实际发生的镜像。通过对比两个执行计划,可以发现查询是否真的按照预估执行计划来执行。

    在执行计划中,有一些非常重要的操作符需要清楚:

    1、           Join策略:SQLServer有3种策略——哈希、合并、嵌套循环。每种策略都有其优缺点,本章将讲述这部分。

    2、           扫描和查找是SQLServer用于读取数据的两种方式,这两种方式在性能优化中是核心概念。将会在下一篇中讲述。

    3、           键查找有时候会成为主要的性能问题。因为存储引起必须从非聚集索引中跳到聚集索引,一边找到非聚集索引中的非键值列的值。这样的行为通常很耗时间。

    理解哈希、合并、嵌套循环连接策略

    SQLServer提供了3中JOIN的策略,它们没有绝对的好和坏之分。

    1、 哈希(Hash Join):SQLServer选择哈希关联作为物理操作符,一边对于大容量数据,且未排序或者没有索引时进行查询。两个进程关联起来进行哈希关联,它们为【建立】和【探测】,在【建立】进程中,会从建立输入(即join的左表中,但是可能这个左表会在优化过程中交换位置,使得不一定就是实际上的左表。)读取所有行,然后在内存中创建一个符合关联条件的哈希表。在【探测】进程中,会从探测表(输入的右表)中读取所有的行,并根据关联条件,与之前创建的内存哈希表匹配。

    2、 合并(Merge Join):如果关联表中已经排序,SQLServer会选择合并关联。合并关联要求关联条件中最少有一个是已经被排序了的。如果数据量不大的时候,这比哈希关联更加有效,它并不是重负荷关联的方式。

    3、 嵌套循环(Nested Loop):在最少两个结果集中,使用嵌套循环会比较有效,这两个结果集中,作为外部表的集合要小,而内部循环结果集具有有效的索引。这种方式不适用于大结果集。

    准备工作:

    下面将创建两个表,然后看看各种关联方式的执行计划:

    [sql] view plain copy

     print?

    1. USE AdventureWorks  

    2. GO  

    3. IF OBJECT_ID('SalesOrdHeaderDemo') IS NOT NULL   

    1. 4.     BEGIN  
    2. 5.         DROP TABLE SalesOrdHeaderDemo  
    3. 6.     END  

    7. GO  

    1. 8.   

    9. IF OBJECT_ID('SalesOrdDetailDemo') IS NOT NULL   

    1. 10.     BEGIN  
    2. 11.         DROP TABLE SalesOrdDetailDemo  
    3. 12.     END  

    13. GO  

    1. 14.   

    15. SELECT  *  

    16. INTO    SalesOrdHeaderDemo  

    17. FROM    Sales.SalesOrderHeader  

    18. GO  

    1. 19.   

    20. SELECT  *  

    21. INTO    SalesOrdDetailDemo  

    22. FROM    Sales.SalesOrderDetail  

    23. GO  

    步骤:

    1、 执行一下查询,并开启执行计划(Ctrl+M):

    [sql] view plain copy

     print?

    1. SELECT  sh.*  

    2. FROM    SalesOrdDetailDemo AS sd  

    1. 3.         INNER JOIN SalesOrdHeaderDemo AS sh ON sh.salesorderID = sd.salesorderid  

    4. GO  

    2、 然后从执行计划截图中可以看到使用了哈希连接:

     

    3、 现在先创建唯一的聚集索引在两个表中:

    [sql] view plain copy

     print?

    1. CREATE UNIQUE CLUSTERED INDEX idx_salesorderheaderdemo_SalesOrderID ON salesordheaderdemo(SalesOrderID)  

    1. 2.   

    3. GO  

    1. 4.   

    5. CREATE UNIQUE CLUSTERED INDEX idx_SalesDetail_SalesOrderID ON SalesOrdDetailDemo(SalesOrderID,SalesOrderDetailID)  

    1. 6.   

    7. GO  

    4、 再次执行步骤1的语句:

    5、 截图是第二次执行的执行计划,可以发现变成了合并连接,并且表扫描变成了聚集索引扫描:

     

    6、 现在来看看嵌套循环关联,在上面的查询中添加where条件来限定查询的结果集:

    [sql] view plain copy

     print?

    1. SELECT  sh.*  

    2. FROM    SalesOrdDetailDemo AS sd  

    1. 3.         INNER JOIN SalesOrdHeaderDemo AS sh ON sh.salesorderID = sd.salesorderid  

    4. WHERE   sh.salesorderid = 43659  

    5. GO  

    7、 从执行结果中看到现在关联变成了嵌套循环: 

     

    分析:

            前面已经提到,哈希关联工作在大数据量且关联字段没有排序的关联中。所以在步骤1中,由于没有索引或者预先排序,数据的关联会使用哈希关联。

            在步骤3中,创建了一个唯一的聚集索引,所以表已经通过聚集索引排序了,此时优化器会选择合并关联。

            在步骤6中,由于使用了where条件限制数据集的大小,同时由于已经排序,所以使用了嵌套循环关联。

            每一种关联方法都有其优缺点,视乎如何优化而已。有时候哈希关联有其非常重要的作用,但是如果可以,强烈建议每个表都应该有一个唯一的聚集索引,一边使用合并关联,如果不可以,千万别尝试使用OPTION提示符来把关联改成合并或者嵌套循环,这可能会降低性能。而嵌套循环仅在小结果集的时候运行的最好。

  • 相关阅读:
    201504051930_《移动APP框架——MUI——HTML5》
    201503121644_《ios直播协议相关》
    2010502260926_《avolon》
    201502251333_《avolon作用域》
    201502251308_《fekit》
    使用Eclipse下载CRaSH源代码
    网络流量监控工具
    Map的putAll方法验证
    bat脚本中%~dp0含义解释
    CD管理和检索软件比较
  • 原文地址:https://www.cnblogs.com/binghou/p/9140328.html
Copyright © 2011-2022 走看看