实际的业务sql中,往往要涉及多个表进行关联查询,这里既可以使用子查询,也可以使用表连接,一般我们认为子查询方式的查询层次较多,且关联时的结果集较大,所以性能会差一些,执行计划器会对子查询进行逻辑优化,将子查询上提到父查询中,与父查询合并,过滤出较小的结果集再进行关联
子查询类型是否支持优化
写法优化any,some,exists,not exists基本支持,in部分情况支持,all,not in不支持.
- 连接优化裁剪 利用left join消除无用的连接,当连表查询时,只输出左表字段,且连接条件的右表字段具有唯一性,那么可以使用left join消除部分连接
- union all 代替 unionunion all不会进行去重,union会去重,如果在明确查询结果不存在重复数据时,union all的效率会高很多
- 避免使用select * 首先,如果select的字段被索引字段覆盖,那么可能就会使用仅索引扫描,这种扫描性能会更高一些。其次,select字段的多少直接影响着结果集数据包的大小,对于前台来说数据包越大,返回就越慢。还有对于一些复杂的查询,比如涉及子查询、连接、分组、聚合、排序等,过程中如果select字段过多,那么大概率会影响sql整体使用的work_mem,超出work_mem时则需使用磁盘,性能更低。
单表索引不应该超过5个。复合索引字段数量一定不可超过4个。复合索引字段数量多主要有以下2个影响:1.字段数量越多,对查询的要求越苛刻。查询必须按照索引的命中规则来安排。2.字段数量越多,索引的体积越大。数据的扇出度(单次IO能得到的数据条数)越低,IO效率也越低,而且索引被更新的概率越大,由于二级索引大部分情况下是随机更新,所以会引起B 树的平衡维护操作。
- ESR原则
E 即Equal。查询中等于条件的字段优先考虑。S 即Sort,排序字段其次考虑。R 即Range,范围查询字段最后考虑 在经常用于查询的字段上创建索引,在经常用于连接的字段上创建索引,在经常用于排序的字段上创建索引
- 在选择性好的字段上创建索引
低基数字段不应该建立单独的索引。(该字段的不重复值个数低于总行数的 10%的称为低基数字段)。比如性别字段,只有男、女两种取值,认为选择性不好,不建议创建索引分布不均匀的字段不应该建立索引。如果一定需要,应该避免使用分布较高的值作为查询条件。分布不均匀指不同的列值占总体的比例差异很大(通常超过50%),即某一个列值或者某几个列值在整个数据集合中占比非常大。例如幼儿园学生年龄分段:年龄段占比3~5:95% ,6~8:3%, 9~12:1%,12~20:1%,20以上0%
- 适当创建联合索引,并将选择性好的字段作为第一个字段
- 对于频繁更新的表避免创建过多索引
高频更新字段不应该建立索引,高频更新字段,会以更新频率同步去更新索引。这会引起索引的删除、插入操作。频繁地删除索引上的数据,索引页会造成大量的空洞,进而引发树的平衡维护。
- 不建议在小表上创建索引
- 一定不可存在冗余索引。
例如 同时存在 idx_A_B(A,B) ,idx_A(A) 两个索引
- 索引单行长度不应该 超过200字节
InnoDB是如何存储和查询数据的按数据页16K计算,我们期望单个索引页至少应该存纳70个索引。默认的innodb的页上会留有1/16的空闲区域。这个空闲区域的主要作用是减少树的平衡操作。
MySQL把数据存储和查询操作抽象成了存储引擎,不同的存储引擎,对数据的存储和读取方式各不相同。MySQL支持多种存储引擎,并且可以以表为粒度设置存储引擎。因为支持事务,我们最常使用的是InnoDB。
- 虽然数据保存在磁盘中,但其处理是在内存中进行的。为了减少磁盘随机读取次数,InnoDB采用页而不是行的粒度来保存数据,即数据被分成若干页,以页为单位保存在磁盘中。InnoDB的页大小,一般是16KB。
- 各个数据页组成一个双向链表
每个数据页中的记录按照主键顺序组成单向链表;每一个数据页中有一个页目录,方便按照主键查询记录。
- 数据页的结构如下:
页目录通过槽把记录分成不同的小组,每个小组有若干条记录。如图所示,记录中最前面的小方块中的数字,代表的是当前分组的记录条数,最小和最大的槽指向2个特殊的伪记录。有了槽之后,我们按照主键搜索页中记录时,就可以采用二分法快速搜索,无需从最小记录开始遍历整个页中的记录链表。
如果要搜索主键(PK)=15的记录:先二分得出槽中间位是(0 6)/2=3,看到其指向的记录是12<15,所以需要从#3槽后继续搜索记录;再使用二分搜索出#3槽和#6槽的中间位是(3 6)/2=4.5取整4,#4槽对应的记录是16>15,所以记录一定在#4槽中;再从#3槽指向的12号记录开始向下搜索3次,定位到15号记录。
- B 树
B 树的特点包括:1.最底层的节点叫做叶子节点,用来存放数据;2.其他上层节点叫作非叶子节点,仅用来存放目录项,作为索引;3.非叶子节点分为不同层次,通过分层来降低每一层的搜索量;4.所有节点按照索引键大小排序,构成一个双向链表,加速范围查找。因此,InnoDB使用B 树,既可以保存实际数据,也可以加速数据搜索,这就是聚簇索引。如果把上图叶子节点下面方块中的省略号看作实际数据的话,那么它就是聚簇索引的示意图。由于数据在物理上只会保存一份,所以包含实际数据的聚簇索引只能有一个,这也就是为什么主键只能有一个的原因。
- InnoDB会自动使用主键
(唯一定义一条记录的单个或多个字段)作为聚簇索引的索引键(如果没有主键,就选择第一个不包含NULL值的唯一列)。上图方框中的数字代表了索引键的值,对聚簇索引而言一般就是主键。
- 我们再看看B 树如何实现快速查找主键。
比如,我们要搜索PK=4的数据,通过根节点中的索引可以知道数据在第一个记录指向的2号页中,通过2号页的索引又可以知道数据在5号页,5号页就是实际的数据页,然后再通过二分法查找页目录马上可以找到记录的指针。
- 为了实现非主键字段的快速搜索,就引出了二级索引,也叫作非聚簇索引、辅助索引。
二级索引,也是利用的B 树的数据结构,如下图所示: