MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术

 

逻辑查询优化包括的技术

  1)子查询优化  2)视图重写  3)等价谓词重写  4)条件简化  5)外连接消除  6)嵌套连接消除  7)连接消除  8)语义优化 9)非SPJ优化

 

一、子查询优化

  1. 什么是子查询:当一个查询是另一个查询的子部分时,称之为子查询。

  2. 查询的子部分,包含的情况:

    a) 目标列位置:子查询如果位于目标列,则只能是标量子查询,否则数据库可能返回类似“错误:子查询只能返回一个字段 ( [Err] 1242 - Subquery returns more than 1 row )”的提示。

    b) FROM子句位置:相关子查询出现在FROM子句中,数据库可能返回类似“错误:在FROM子句中的子查询无法参考相同查询级别中的关系”的提示,所以相关子查询不能出现在FROM子句中(即FROM型子查询不能与外面的查询有任何的关联)。

      非相关子查询出现在FROM子句中,可上拉子查询到父层,在多表连接时统一考虑连接代价然后择优。

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第1张图片

    c) WHERE子句位置:出现在WHERE子句中的子查询,是一个条件表达式的一部分,而表达式可以分解为操作符和操作数;根据参与运算的不同的数据类型,操作符也不尽相同,如int型有“>、<、=、<>”等操作;这对子查询就有了一定的要求,如int型的等值操作,要求子查询必须是标量子查询。另外,子查询出现在WHERE子句中的格式,也有用谓词指定的一些操作,如“in、between... 、exists”等。

    d) JOIN/ON子句位置:JOIN/ON子句可以拆分为两部分,一是JOIN块类似于FROM子句,二是ON子句块类似于WHERE子句,这两部分都可以出现子查询。子查询的处理方式同FROM子句和WHERE子句。

    e) GROUP BY子句位置:目标列必须和GROUP BY 关联,可将子查询写在GROUP BY位置处,但子查询用在GROUP BY处没有实用意义。

    f) ORDER BY子句位置:可将子查询写在ORDER BY位置处。但ORDER BY操作是作用在整条SQL语句上的,子查询用在ORDER BY处没有实用意义。

  3.子查询的类型——从对象间的关系看

    a) 相关子查询:子查询的执行依赖于外层父查询的一些属性值。子查询因依赖于父查询的参数,当父查询的参数改变时,子查询需要根据新参数值重新执行(查询优化器对相关子查询进行优化有一定意义)。

       MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第2张图片

    b) 非相关子查询:子查询的执行,不依赖于外层父查询的任何属性值。这样子查询具有独立性,可独自求解,形成一个子查询计划先于外层的查询求解。

  4.子查询的类型——从特定谓词看

    a) [NOT] IN / ALL / ANY / SOME 子查询:语义相近,左边是操作数,右边是子查询,是最常见的子查询类型之一。

    b) [NOT] EXISTS 子查询:半连接语义,没有左操作数,右边是子查询,是常见的子查询之一。

  5.子查询的类型——从语句的构成复杂程度看

    a) SPJ子查询:由选择(Select)、投影(Projection)、连接(Join)操作组成的查询

    b) GROUP BY子查询:SPJ子查询加上分组、聚集操作组成的查询。

    c) 其它子查询:GROUP BY子查询中加上其它子句如Top-N,LIMIT / OFFSET 、集合、排序等操作。

  6.子查询的类型——从结果的角度看

    a) 标量子查询:子查询返回的结果集类型是一个简单值

    b) 单行单列子查询:子查询返回的结果集类型是零条或一条单元组。相似于标量子查询,但可能返回零条元组。

    c) 多行单列子查询:子查询返回的结果集类型是多条元组但只有一个简单列。

    d) 表子查询:子查询返回的结果集类型是一个表(多行多列)。

  7.为什么要作子查询优化呢?

    在数据库实现早期,查询优化器对子查询一般采用嵌套执行的方式,即对父查询中的每一行,都执行一次子查询,这样子查询会执行很多次。这种执行方式效率很低。

    对子查询进行优化,可能带能几个数量级的查询效率的提高。

    子查询转变为连接操作之后,会得到如下好处:a) 子查询不用执行很多次; b) 优化器可以根据统计信息来选择不同的连接方法和不同的连接顺序。

    子查询的连接条件、过滤条件分别变成了父查询的连接条件、过滤条件,优化器可以对这些条件进行下推,以提高执行效率。

  8.子查询优化方式

    a) 子查询合并:在某些条件下(语义等价:两个查询块产生同样的结果集(列一致) ),多个子查询能够合并成一个子查询(合并后还是子查询,以后可以通过其它技术消除掉子查询)。这样可以把多次表扫描、多次连接 减少为单次表扫描和单次连接。

    b) 子查询展开:又称子查询反嵌套,或称为子查询上拉

      把一些子查询置于外层的父查询中,作为连接关系与外层父查询并列,其实质是把某些子查询重写为等价的多表连接操作(展开后,子查询不存在了,外部查询变成了多表连接)。

      带来的好处是:有关的访问路径、连接方法和连接顺序可能被有效使用,使得查询语句的层次尽可能的减少。

      常见的IN / ANY / ALL / SOME / EXISTS 依据情况转变为半连接(SEMI JOIN),普通的子查询消除等情况属于此类。

    c) 聚集子查询消除:通常,一些系统支持的是标量聚集子查询消除。

 

  9.MySQL子查询优化(MySQL优化器优化)

    1.MySql可以优化什么格式的子查询

      1) 优化器支持对简单SELECT查询中的子查询优化:

        a) 简单select中的子查询,会被mysql优化器自动上拉到父层。

        b) 带有DISTINCT、ORDER BY、LIMIT操作的简单SELECT查询中的子查询。 

      2) 优化器不支持对如下情况的子查询进行优化

        a) 带有UNION操作。

        b) 带有GROUP BY、HAVING、聚集函数。

        c) 使用ORDER BY中带有LIMIT。

        d) 内表、外表的个数超过MySql支持的最大的表连接数。

    2.MySql支持哪些子查询的优化技术

      1) 不支持子查询合并技术

      2) 不能很好的支持子查询展开(子查询上拉)技术

      3) 不支持聚集子查询消除技术:MySQL认为聚集子查询只需要执行一次,得到结果后,把结果缓冲到内存中以供后续连接或过滤操等操作使用,没必要消除子查询。另外,如果聚集子查询在索引列上执行,则会更快得到查询结果,更能加快查询速度。

    3.MySQL支持对哪些类型的子查询进行优化 

      1) 不支持对EXISTS类型的子查询做进一步的优化(上拉子查询)。

      2) 支持对IN类型的子查询的优化,in子查询被优化为半连接。

        3) 支持对NOT IN 类型的子查询的优化,NOT IN 子查询被物化,但没有消除子查询。

      4) 支持对< ALL类型的子查询的优化,< ALL子查询被转换为 >= MAX运算。

      5) 支持对> ALL类型的子查询的优化,> ALL子查询被转换为 <= MIN运算

      5) 支持对= ALL类型的子查询的优化,= ALL子查询优化为用“EXISTS strategy”方式优化。

 

二、视图重写

  1.什么是视图重写?

    1) 查询语句中出现视图对象(先将视图转化为子查询,再进行优化)

    2) 查询优化后,视图对象消失

    3) 消失的视图对象的查询语句,融合到初始查询中

  2.MySQL视图重写准则

    1) MySQL支持对视图进行优化

    2) 优化方法是把视图转为对基表的查询,然后进行类似于子查询的优化。

    3) MySQL通常只能重写简单视图(SPJ简单查询的视图),复杂视图(非SPJ查询,如带有GROUP BY的视图)不能重写。

 

三、等价谓词重写

  等价谓词重写(主要就是使其能更好的利用索引,有些谓词是可以利用索引的)

    1) 把逻辑表达式重写成等价的且效率更高的形式。

    2) 优点:能有效提高查询执行效率

    3) LIKE 规则

      LIKE规则,是对LIKE谓词的等价重写,即改写LIKE谓词为其它等价的谓词,以更好地利用索引进行优化。

      例如:name LIKE "ABC%" => 重写为 name >= "ABC" AND name < "Abd"

      应用LIKE规则的好处:转换前针对LIKE谓词,只能进行全表扫描,如果name列上存在索引,则转换后可以进行索引扫描。

      另外,LIKE后的表达式,如果左边有通配符("%xxx%"),无法利用索引扫描;如果左边没有通配符("xxx%"),是可以利用索引进行扫描的。

    4) BETWEEN-AND规则

      改写between-and谓词为其它等价的谓词,以便更好的利用索引进行优化。

      例如:number BETWEEN 10 AND 20 => 重写为:number >= 10 AND number <= 20

      好处:如果建立了索引,则可以利用索引扫描代替between-and谓词限定的全表扫描,从而提高了效率。

    5) IN 转换OR规则

      IN 指IN操作符操作,不是IN子查询。

      如果IN不支持索引,而IN对应的列又有索引,将IN谓词等价重写为若干个OR谓词,可能会提高执行效率。

      IN 可以转换为OR,OR可以转为ANY,所以可以直接把IN转换为ANY。将IN谓词等价重写为ANY谓词,可能会提高效率。

      应用IN转换为ANY后效率是否能提高,依赖于数据库对于ANY操作的支持情况。

    6) OR 转换ANY规则

      OR转换为ANY,如果数据库支持,可以更好地利用MIN/MAX操作进行优化。(MySql5.6不支持)

    7) ALL/ANY 转换为聚集函数

      ALL/ANY转换为等价的聚集函数MIN/MAX,以更好的利用MIN/MAX操作进行优化。

      通常,聚集函数MAX()/MIN()等的执行效率一般都比ANY、ALL谓词的执行效率高,如果有索引存在,求解MAX/MIN的效率更高。

    8) NOT谓词的等价重写

      NOT(col != 2) =>  col = 2

      NOT(col = col2) =>  col != col2

      NOT(col > 2)  => col <= 2

      如果NOT操作的列上建立了索引,则可以用索引扫描代替原来的全表扫描,从而提高效率。

    9) OR重写并集规则

      为了能更好利用索引处理多个OR连接的查询,可以使用UNION分别求解然后合并结果集,这样可以快速利用索引进行扫描。(前提是OR对应的列有索引)

      SELECT * FROM tt WHERE c1 > 100 OR c2 < 10;  =>  SELECT * FROM tt WHERE c1 > 100 UNION (SELECT * FROM tt WHERE c2 < 10)

 

四、条件化简(条件优化技术)

  SQL语句中,条件分为对元组过滤的条件和对连接操作的过滤条件(即什么样的连接方式)

  1.条件下推

    把与单个表相关的条件,放到对单表进行扫描的过程中分析。

    数据库系统都支持条件下推,且无论条件对应的列对象有无索引,系统自动进行优化,不用人工介入。

    例如:SELECT * FROM A, B WHERE A.id < 10 AND A.m = B.m;  

      => 执行顺序:1.扫描A表,并带有A.id < 10 ,把A表作为嵌套循环的外表; 2.扫描B表,执行连接操作,并带有过滤条件A.m = B.m;不管两个条件的顺序如何,都会被下推成这个顺序。

  2.条件化简

    1) WHERE、HAVING、JOIN-ON条件由许多表达式组成,而这些表达式在某些时候彼此之间存在一定的联系

    2) 利用等式和不等式的性质,可以将WHERE、HAVING和ON条件化简。

    3) 不同数据库的实现可能不完全相同。

    4) 具体实现:

      a) 把HAVING条件并入WHERE条件(优化器不支持,自己转换)

        优点:便于统一、集中化简条件子句,节约多次化解时间。

        注意:不是任何情况下HAVING条件都可以并入WHERE条件,只有在SQL语句中不存在GROUP BY条件或聚集函数的情况下,才能将HAVING条件和WHERE条件进行合并。

        例子:SELECT * FROM t WHERE a > 5 HAVING b < 10  =》  SELECT * FROM t WHERE a > 5 AND b < 10;

      b) 去除表达式中的冗余括号(支持)

        优点:可以减少语法分析时产生的AND和OR树的层次,减少CPU的消耗

      c) 常量传递(支持)

        优点:对不同关系可以使得条件分离后有效实施“选择下推”,从而可以极大减小中间关系的规模;可以减少语法分析时间,因为会被优化器  优化成条件分离的形式。       

        例子:SELECT .... ... WHERE a = b AND a = 1;  =》  SELECT ... ... WHERE a = 1 AND b = 1;

        注意:操作符“=、<、>、<=、>=、<>、<=>、LIKE”中的任何一个,在“a [操作符] b”条件中都可能会发生常量传递。

      d) 消除死码(支持)

        优点:化简条件,将不必要的条件去除。

      e) 表达式计算(支持)

        对可以求解的表达式先进行计算,得出结果。

        例子:WHERE a = 1+2  =》  WHERE a = 3

      f) 等式变换(不支持,自己转换)

        化简条件,如反转关系操作符的操作数的顺序,从而改变某些表的访问路径。

        例子:WHERE -a = 3  =》 WHERE a = -3

        优点:如果a 上有索引,则可以利用索引扫描来加快访问。

      g) 不等式变换(不支持)

        化简条件,将不必要的重复条件去除。

      h) 布尔表达式变换

        优点:减少条件连接时的元组。

        1.谓词传递闭包(不支持,自己转换)

          一些比较操作符如“<、>”等,具有传递性,可以起到化简表达式的作用

          例子:a > b AND b > 2  =》  a > b AND b > 2 AND a > 2;这里 a > 2 是一个隐藏条件。这样把a > 2 和 b > 2分别下推到对应的关系上,就可以减少参与比较操作 a > b 的元组数了。

        2.布尔表达式被转换为一个等价的合取范式(CNF) (支持)

          任何一个布尔表达式都能被转换为一个等价的合取范式(CNF);

          合取范式格式为:c1 AND c2 AND ... AND cn ;其中,ck 称为合取项(1 < k < n),每个合取项是不包含AND的布尔表达式(即每个表达式不再嵌套AND条件)。

          优点:

            ①合取项只要有一个为假,整个表达式就为假,故代码中可以在发现一个合取项为假时,即停止其它合取项的判断,加快判断速度。

            ②因为AND操作符是可以交换的,所以优化器可以按照先易后难的顺序计算表达式,一旦发现一个合取项为假时,即停止其它合取项的判断,加快判断速度。

        3.索引利用(支持)

          如果一个合取项上存在索引,则先判断索引是否可用,如果能利用索引快速得出合取项的值,则能加快判断速度。同理,OR表达式中的子项也可以利用索引。

          

 

五、外连接消除、嵌套连接消除、连接消除

  外连接:LEFT [OUTER] JOIN ... ON ... / RIGHT [OUTER] JOIN ... ON ... 

  内连接:[INNER] JOIN ... ON ...

  1.外连接消除(即左右连接及全连接)

    1)为什么要进行外连接消除

      a) 查询优化器在处理外连接操作时所需执行的操作和时间多余内连接。

      b) 外连接消除后,优化器在选择多表连接顺序时,可以有更多更灵活的选择,从而可以选择更好的表连接顺序,加快查询执行的速度。

      c) 表的一些连接算法(如块嵌套连接和索引循环连接等)在将规模小的或筛选条件最严格的表作为“外表”(放在连接顺序的最前面,是多层循环体的外层循环),可以减少不必要的IO开销,能加快算法执行的速度。

      d) 外连接消除去掉的是外连接的语义,变形为内连接。 

    2)外连接消除的条件

       外连接消除,把外连接变为内连接:A LEFT/RIGHT JOIN B ON  =》  A JOIN B

       WHERE 子句中的条件满足“空值拒绝”(“reject-NULL”条件):

        WHERE条件可以保证从结果中排除外连接右侧(右表)生成的值为NULL的行(即条件确保应用在右表带有空值的列对象上时,条件不满足,条件的结果值为FALSE或UNKNOWEN,这样右表就不会有值为NULL的行生成),所以能使该查询在语义上等效于内连接。但左表不满足条件的数据也不会查出来,小心使用。

        例子:下面四个例子的效果一样,都能保证右表不为空,从而等效于内连接、。

          SELECT * FROM A LEFT JOIN B ON A.m = B.m WHERE B.m IS NOT NULL;

          SELECT * FROM A LEFT JOIN B ON true WHERE A.m = B.m;

          SELECT * FROM A LEFT JOIN B ON A.m = B.m WHERE A.m = B.m;

          SELECT * FROM A LEFT JOIN B ON A.m = B.m WHERE B.col ; WHERE条件后如果有跟右表相关的条件也会被优化成内连接(因为如果不满足连接条件,右表每列都为NULL了,保证了不会有空行出现)。

  2.连接消除

    去掉不必要的连接对象,则减少了连接操作。

    消除情况:

    1) 唯一键/主键作为连接条件,三表内连接可以去掉中间表(中间表的列只作为连接条件),可以消除主键表。

      例子:SELECT A.*, C.* FROM A, B, C WHERE A.a = B.a AND B.a = C.a;  =》 SELECT A.*, C.* FROM A, C WHERE A.a = C.a;

    2) 一些特殊的形式,可以消除连接操作(可消除的表除了作为连接对象外,不出现在任何子句中)

      例子:SELECT A.a FROM A, B; 可消除B表

  3.嵌套连接消除

    连接存在多个层次,用括号标识连接的优先次序。

    嵌套连接消除,就是消除嵌套的连接层次(去掉括号),把多个层次的连接减少为较少层次的连接,尽量“扁平化”。

    嵌套连接消除的是连接的层次,这是一种连接的语义顺序的变化。

 

 六、数据库的约束规则与语义优化

  1.数据完整性(Data Integrity)

    指数据的精确性(Accuracy)和可靠性(Reliability)。

    作用:1.防止用户向数据库中添加不合语义的数据。2.利用基于DBMS的完整性控制机制来实现业务规则,易于定义,容易理解,而且可以降低应用程序的复杂性,提高应用程序的运行效率。同时,基于DBMS的完整性控制机制是集中管理的,因此此应用程序更容易实现数据库的完整性。

    数据完整性分为四类:

      1)实体完整性(Entity Integrity):自己

        一个关系对应现实世界中的一个实体集。——ER模型

        现实世界中的实体具有某种唯一性标识。——主键

        主关键字是多个属性的组合,则所有主属性均不得取控制。——隐含的索引。

      2)域完整性(Domain Integrity):自己的局部(字段)

        保证数据库字段取值的合理性

        属性值应是域中的值:检查(check)、默认值(default)、不为空(not null)、可为空(null)等等。

      3)参照完整性(Referential Integrity):自己与其它实体的关系(主外键)

        参照完整性是定义建立在关系之间联系的主关键字与外部关键字引用的约束条件。

      4)用户自定义完整性(User-defined Integrity):用户增加的限制(如非空约束等)

  2.语义优化

    1.语义转换:因为完整性限制等的原因使得一个转换成立的情况称为语义转换。

    2.语义优化:因为语义转换形成的优化称为语义优化

      语义转换其实是根据完整性约束等信息对“某特定语义”进行推理,进而得到一种查询效率不同但结果相同的查询。

      语义优化是从语义的角度(SQL语句所表达的含义、意义)对SQL进行优化,不是一种形式上的优化,所以其优化的范围,可能覆盖其它类型的优化范围。根据完整性约束,对查询语句进行语义理解,推知一些可优化的操作。

    3.语义优化常见的方式

      1) 连接消除:对一些连接操作先不必评估代价,根据已知信息(主要依据完整性约束等,但不全是依据完整性约束)能推知结果或得到一个简化的操作。

      2) 连接引入:增加连接有助于原始关系变小或原关系的选择率降低。

      3) 谓词引入:根据完整性约束信息,引入新谓词,如引入基于索引的列,可能使得查询更快。

      4) 检测空集回答:查询语句中的谓词与约束相悖,可以推知条件结果为FALSE,也许最终的结果集能为空。(如:a 列限制在100-200之间,查询a < 90则能立即推知条件不成立)

        5) 排序优化:ORDER BY操作通常由索引和排序(set)完成,如果能够利用索引,则排序操作可省略;另外,结合分组等操作,考虑ORDER BY操作的优化。

      6) 唯一性使用:利用唯一性、索引等特点,检查是否存在不必要的DISTINCT等操作。

 

七、非SPJ优化

  1.GROUP BY优化

    1) 分组转换技术:对分组操作、聚集操作与连接操作的位置进行交换

      a) 分组操作下移:GROUP BY操作可能较大幅度减少关系元组的个数,如果能够对某个关系先进行分组操作,然后再进行表之间的连接,很可能提高连接效率。这种优化方式是把分组操作提前执行。下移的含义,是在查询树上,让分组操作尽量靠近叶子节点,使得分组操作的节点低于一些选择操作。

      b) 分组操作上移:如果连接操作能够过滤掉大部分元组,则先进行连接操作,后进行GROUP BY操作,可能提高分组操作的效率。这种优化方式是把分组操作置后执行。上移的含义和下移相反。 

    2) MySQL的GROUP BY优化:MySQL对于GROUP BY的处理,通常采用的方式是扫描整个表、创建一个临时表以执行分组操作。MySQL不支持分组转换技术。对于GROUP BY的优化,尽量利用索引。

      利用索引的条件:分组子句中的列对象源自同一个BTREE索引(不支持利用HASH索引进行优化)的全部或前缀部分的部分有序的键(分组使用的索引列与索引建立的顺序不匹配则不能使用索引)。     

  2.ORDER BY优化

    ORDER BY 如果操作的列不是主键或索引等,会创建一个临时表(Using temporary、Using flesort)

    1) 排序消除:优化器在生成执行计划前,将语句中没有必要的排序操作消除(如利用索引),避免在执行计划中出现排序操作或由排序导致的操作(如在索引列上排序,可以利用索引消除排序操作)

    2) 排序下推:把排序操作尽量下推到基表中,有序的基表进行连接后的结果符合排序的语义,这样能避免在最终的大的连接结果集上执行排序操作。

  3.DISTINCT优化

    DISTINCT操作的列,如果该列有索引(唯一性约束)或者为主键,则直接使用索引排序;否则会使用一张临时表(Using temporary),先去重,再排序(可以看到输出结果是根据该列排好序的)。

    1) DISTINCT消除:如果表中存在主键、唯一约束、索引等,则可以消除查询语句中的DISTINCT 

    2) DISTINCT推入:生成含DISTINCT的反半连接查询执行计划时,先进行反半连接再进行DISTINCT操作;也许先执行DISTINCT操作再执行反半连接,可能更优。

    3) DISTINCT迁移:对连接操作的结果执行DISTINCT,可能把DISTINCT移到一个子查询中优先进行

  总结:GROUP BY / ORDER BY / DISTINCT 优化尽量利用索引、主键、唯一性约束,这样可以不创建临时表。

  4.LIMIT优化

    1) LIMIT对单表扫描的影响:如果索引扫描可用且花费低于全表扫描,则用索引扫描实现LIMIT(LIMIT取出很少量的行,否则优化器更倾向于使用全表扫描)

    2) LIMIT对排序的影响:如果LIMIT和ORDER BY子句协同使用,当取到LIMIT设定个数的有序元组数后,后续的排序操作将不再进行。

    3) LIMIT对去重的影响:如果LIMIT和DISTINCT子句协同使用,当取到LIMIT设定个数的唯一元组数后,后续的去重操作将不再进行。

    4) LIMIT受分组的影响:如果LIMIT和GROUP BY子句协同使用,GROUP BY按索引有序计算每个组的总数的过程中,LIMIT操作不必计数直到下一个分组开始。

    5) LIMIT 0:直接返回空结果集。

    6) MYSQL支持对不带HAVING的子句进行优化。

  5.常见的一些优化规则

    1) 在索引键上执行排序操作,通常利用索引的有序性按序读取数据而不进行排序。

    2) 选择率低于10%时,利用索引的效果通常比读取表数据的效果好。

    3) 当表的数据量较少时,全表扫描可能优于其它方式(如索引)。

 

八、物理查询优化

  1.什么是物理查询优化

    逻辑查询优化:解决的是如何找出SQL语句等价的变换形式,使得SQL执行更高效。

    物理查询优化解决的问题:

      1) 从可选的单表扫描方式中,挑选什么样的单表扫描方式是最优的。

      2) 两个表做连接时,如何连接最优。

      3) 多个表连接,连接顺序有多重组合,哪种连接顺序是最优的。

      4) 多个表连接,连接顺序有多种组合,是否要对每种组合都探索?如果不全部探索,怎么找到最优的一种组合。

    物理查询优化把逻辑查询执行计划变为物理操作符,供执行器执行。

  2.物理查询优化技术

    1) 代价估算模型:物理查询优化的核心

      公式:总代价 = I/O代价 (数据读取) + CPU代价 (数据计算处理)

      MySQL的代价估算模型: 总代价 = I/O代价 + CPU代价 + Memory代价 + Remote代价

      COST = pages * a_page_cpu_time + W * T;

      pages:计划运行时访问的页面数; a_page_cpu_time:每个页面读取的时间花费; pages * a_page_cpu_time 的乘积反映了I/O花费。

      T:访问的元组数,反映了CPU花费(存储层是以页面为单位,数据以页面的形式被读入内存,每个页面上可能有多条元组,访问元组需要解析元组结构,才能把元组上的字段读出,这消耗的是CPU)。如果是索引扫描,则还会包括索引读取的花费。

      W:权重因子,表明I/O到CPU的相关性,又称选择率。选择率用于表示在关系R中,满足条件“A col” 的元组数与R的所有元组数N的比值。

    2) 单表扫描

      单表扫描是完成表连接的基础。

      单表扫描算法:

        应用原则:尽量少获取元组,用什么取什么,不要把所有的(行或列)都取出来。

        1) 顺序扫描:从物理存储上按照存储顺序直接读取表的数据;当无索引可利用,或访问表中的大部分数据,或表的数据量很小,使用顺序扫描效果较好。

        2) 索引扫描:根据索引键读索引,找出物理元组的位置;根据从索引中找到的位置,从存储读取数据页面;索引扫描可以将元组按排序的顺序返回;索引扫描有选择率(低于10%)存在,读数据花费的I/O会显著减少;如果选择率很高的话,不适宜使用索引扫描。

        3) 只读索引扫描:根据索引键读索引,索引中的数据能够满足条件判断,不需要读取数据页面;比索引扫描少了读取数据的I/O花费

        4) 行扫描:用于直接定位表中的某一行。对于元组,通常为元组增加特殊的列,可以通过特殊的列计算出元组的物理位置,然后直接读取元组对应的页面,获取元组。

    3) 两表连接

      两表连接算法:

        1) 嵌套循环连接算法:适用于左右连接、内连接、半连接等等。

        2) 归并(排序)连接算法:步奏:为两个表创建可用内存缓冲区数为M的M个子表,每个子表排好序;然后读入每个子表的第一块到M个块中,找出其中最小的先进行两个表的元组的匹配,找出次小的匹配,...;依次完成其它子表的两表连接。

        3) Hash连接算法:用连接列作为Hash的关键字,对内表进行Hash运算建立Hash表,然后对外表的每个元组的连接列用Hash函数求值,值映射到内表建立好的Hash表就可以连接了;否则,探索外表的下一个元组。

    4) 多表连接

      多表连接要解决的问题:

        1) 多表连接的顺序:表的不同的连接顺序,会产生许多不同的连接路径;不同的连接路径有着不同的效率。

        2) 多表连接的搜索空间:因为多表连接的顺序不同,产生的连接组合会有多种,如果这个组合的数目巨大,连接次数会达到一个很高的数量级,最大可能的连接次数时N!(N的阶乘)。所有的连接可能构成一个巨大的“搜索空间”。如何减小搜索空间,在一个可接受的时间范围内,高效地生成查询执行计划将成为一个难点。

 

九、MySql索引的优化、利用

  1.索引的优点:

    提高少量数据的获取/检索速度。(比如获取某个用户)

  2.索引的缺点:

    1) 占用存储空间

    2) 多个索引耗费索引的挑选时间

    3) 降低写操作的性能,需要实时维护索引

    4) 并发情况下索引的维护高度复杂

  3.什么时候不使用索引

    1) 数据的重复度高,即 选择率高。

    2) 选择率高于10%,不建议使用索引。

    3) 表的数据量较少,全表的扫描速度可能快于索引扫描。

  4.数据库选择索引的原则

    1) 代价估算模型计算代价,选择小代价的方式

    2) 启发式规则排除或强制选择某类索引。

  5.MySQL支持的索引

    1)B-Tree:PRIMARY KEY、UNIQUE、INDEX、FULL TEXT(全文索引)

    2)Hash:MEMORY Tables(内存表)

      支持B-Tree的引擎:InnoDB、MyISAM、MEMORY/HEAP、NDB

      支持Hash的引擎:MEMORY/HEAP、NDB  

      B-Tree和Hash索引支持的操作符:=、<=>、IN()、IS NULL、IS NOT NULL ;

      B-Tree支持的索引:>、<、>=、<=、BETWEEN...AND...、!=、<>、LIKE(LIKE 表达式前不能有通配符,"xxx%") ;

  6.索引使用例子

    1)Like索引的利用情况:为了更好的利用索引,前面最好不要有通配符。

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第3张图片

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第4张图片

    

    2) MySQL优化器对<>、!=操作的优化

      MySQL对于=操作符可以利用索引。

      但是使用<>、!=时,MySQL认为取出的数据量大,即选择率高,所以放弃了使用索引,看第二张图。

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第5张图片

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第6张图片

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第7张图片

    3) 对>、<操作符的影响

      总的来说就是,如果操作符的选择率过高,则会放弃使用索引,而使用全表扫描,这种情况使用索引反而减慢了速度。

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第8张图片

    4) 索引列有表达式计算,MySQL无法对表达式进行转化,则索引不可用;所以不要在索引列上使用表达式。

      MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术_第9张图片

    5) 其它

      a) 如果两个长度不一样,不会使用索引:char(10) = varchar(10) != char(8) != varchar(6)

      b) 查看索引使用的情况:SHOW STATUS LIKE "HANDLER_READ%";

        handler_read_key的值高:索引查询多,查询效率越高;

        handler_read_rnd_next的值高:随机查询多,查询效率越低。

 

!!!

转载于:https://www.cnblogs.com/chiangchou/p/mysql-6.html

你可能感兴趣的:(MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术)