[汇总]MySQL优化经验和理论
innodb,它是我们建表的首选存储引擎
为什么 MySQL 索引要使用 B+树而不是其它树形结构?比如 B 树?
那么可以算出一棵高度为2的B+树,能存放1170*16=18720条这样的数据记录。根据同样的原理我们可以算出一个高度为3的B+树可以存放:1170*1170*16=21902400条这样的记录。
一款SQL自动检查神器,再也不用担心SQL出错了!Yearning
两类非常隐蔽的全表扫描,不能命中索引
第一类:“列类型”与“where值类型”不符,不能命中索引,会导致全表扫描(full table scan)。
第二类:相join的两个表的字符编码不同,不能命中索引,会导致笛卡尔积的循环计算(nested loop)。
explain结果中的type字段,ref,ALL等不一样的值究竟是什么含义?常见的type结果及代表的含义,并且通过同一个SQL语句的性能差异,说明建对索引多么重要。
记一次神奇的 sql 查询经历,group by 慢查询优化!
- COUNT有几种用法?
- COUNT(字段名)和COUNT(*)的查询结果有什么不同?
- COUNT(1)和COUNT(*)之间有什么不同?
- COUNT(1)和COUNT(*)之间的效率哪个更高?
- 为什么《阿里巴巴Java开发手册》建议使用COUNT(*)
- MySQL的MyISAM引擎对COUNT(*)做了哪些优化?
- MySQL的InnoDB引擎对COUNT(*)做了哪些优化?
- 上面提到的MySQL对COUNT(*)做的优化,有一个关键的前提是什么?
- SELECT COUNT(*) 的时候,加不加where条件有差别吗?
- COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的?
一次SQL查询优化原理分析:900W+数据,从17s到300ms
、可参考《阿里巴巴Java开发手册(泰山版)》第五章-MySQL数据库、(二)索引规约、第7条:【推荐】利用延迟关联或者子查询优化超多分页场景。说明:MySQL并不是挑过offeset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的底下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。正例:先快速定位需要获取的id段,然后再关联:SELECT a.* FROM 表1 a,(select id from 表1 where 条件 LIMIT 100000,20) b where a.id = b.id;
阿里不让多表join?我偏要!
就是快速造数据。你可以自己先写脚本造数据,看看我是怎么造数据的,就知道我的技巧了。
一款SQL自动检查神器,再也不用担心SQL出错了,自动补全、回滚等功能大全
Yearning MYSQL
频繁插入(insert)的业务,用什么存储引擎更合适?
虽然MyISAM只支持表锁,但高并发select与insert的业务场景,上述机制使得MyISAM的表锁依然有非常强劲的性能。
- insert ignore into
- on duplicate key update
- replace into
源表中有100万条数据,其中有50万created_time和item_name重复。要把去重后的50万数据写入到目标表。
从 MySQL 5.6 开始,InnoDB 开始支持全文检索。
核心思想是:用一个或多个查询条件(查询条件要求至少输入一个)得到临时表,每个查询条件如果查到集合,就更新这张临时表,最后汇总的时候,只需判断这个临时表是否有值。
-
用 EXISTS 或 NOT EXISTS 代替 -
用JOIN 代替
主要原因是由于我们使用了 order by id asc 这种基于 id 的排序写法,优化器认为排序是个昂贵的操作,所以为了避免排序,并且它认为 limit n 的 n 如果很小的话即使使用全表扫描也能很快执行完,所以它选择了全表扫描,也就避免了 id 的排序(全表扫描其实就是基于 id 主键的聚簇索引的扫描,本身就是基于 id 排好序的)
如果这个选择是对的那也罢了,然而实际上这个优化却是有 bug 的!实际选择 idx_uid_stat 执行会快得多(只要 28 ms)!网上有不少人反馈这个问题,而且出现这个问题基本只与 SQL 中出现 order by id asc limit n
这种写法有关,如果 n 比较小很大概率会走全表扫描,如果 n 比较大则会选择正确的索引。