4、影响SQL性能的要素
MySQL数据库的性能不止受到性能参数和底层硬件条件的影响,在这两个条件一定的情况下,开发人员对SQL语句的优化能力更能影响MySQL数据库的性能。由于MySQL中不同数据库引擎对SQL语句的处理过程不尽相同,所以对SQL语句的优化就一定要首先确定使用的数据库引擎的类型。例如MyISAM引擎中统计某一个数据表的总行数时,只需要读取出已保存好的数据总行数就OK了。但InnoDB引擎要完成这个动作,就必须进行table scan/index scan,而是否为被扫描的字段创建了索引又直接影响了扫描速度。本文我们和读者一起来讨论一下InnoDB数据引擎下SQL语句常见的工作方式和优化规则。
4-1、索引我们都知道无论使用哪种主流的关系型数据库,为SQL查找语句所依据的字段创建索引要比不创建索引时的性能高出几个数量级(当然这也要看SELECT查询语句的具体写法)。那么为什么会出现这样的情况呢?我们又依据什么样的原理来创建数据库的索引呢?本小节将首先为读者进行原理性描述。
4-1-1、B树同样由于本文的定位,所以我们并不会讨论怎样使用脚本创建索引等基本操作问题。而是直接进行InnoDB数据库引擎中索引原理的讲述。InnoDB中数据库字段的索引采用树结构进行组织,这种树本质上是为了解决数据检索问题的平衡N阶树,又被称为B树。B树及其变体是大学《数据结构》课程中的基础知识,本人虽然工作许多年但始终对《数据结构》这门课程中的主要知识烂熟于心,并认为它和《 离散数学》一样已经成为笔者大学时期学习过的,对笔者实际工作帮助最大的两门课程。
为了帮助读者回忆起B树及其变体的基本结构,也为了后续内容能够正常铺开。我们非常需要使用相当的篇幅对它进行介绍。那么首先使用下图回答树结构的几个基本概念:节点、深度、子树等。
B树是一颗平衡的多叉检索树,它具有以下性质:
所谓检索树是指这样的树:树中任意非叶子节点A作为根节点的子树,其左子树上节点中的元素值均小于或等于节点A中元素的值;其右子树上节点中的元素值均大于或等于节点A中元素的值。检索树又称为排序树、有序树,如果将检索树降维成表结构则同样可以使用二分查找法进行节点检索,且时间复杂度基本不变。
如果不加任何构造限制,那么在树结构中检索元素的时间复杂度可能为O(n)。这显然失去了检索树的意义,如果一颗检索树能够保证树的高度H限制在节点数N的对数阶范围内(H=O(logn)),这样的检索树就称为平衡树。在编程实践中只要保证树中任意两个子树深度差的绝对值不大于1,就可以保证前述条件成立。另外B树中对深度差绝对值做了更严格的规定,即所有叶子结点都位于同一深度。
一颗B树的非叶子节点能够最多关联的子节点数量称为阶数。B树中的阶数至少为3,因为当阶数为2时B树进行节点分裂就可能会出现某叶子节点没有任何元素的情况。
树中每个非根节点所包含的元素个数 j 满足:(N/2) - 1 <= j <= N - 1,其中N表示B树的阶数。例如阶数为3的B树每一个非叶子结点能够存储的元素个数可能为 0个、1个和2个(但0个元素没有任何检索意义,还会造成树中任意两个子树深度差的绝对值改变)。
树中一个节点可关联的子节点数量比以上文字中提到的元素最大个数多1。也就是说阶数为3的B树每个节点最多可关联3个子节点。
上图展示了一颗3阶B树,它的每个节点最多可以有3个子节点,并且每个子节点中最多有2个元素。可以观察到B树满足检索树的基本规则:凡是比给定元素值大的所有元素,都作为该元素的子元素排列在该元素的左子树上;凡是比给定元素值大的所有元素,都作为该元素的子元素排列在该元素的右子树上。这样一来开发人员就可以使用和二分查找法类似的查找方式定位要查询的元素,或者在插入一个新元素前定位到新元素将要进行插入的位置。
下图演示了在B树中依次添加元素时的分裂和节点间关联过程,这些元素的值依次增大分别是:3、5、7、9、14、13、15、16、18、22、25、31、33。在实际应用开发中,虽然我们并不能保证插入B树的元素值都是增加的,但是对B树的插入操作过程却是相同的(两者的区别只是定位的将要插入新元素的位置不一样):
4-1-2、变体B+树