MySQL 通过 /mysql/bin/mysqld 启动

uft8 作为 unicode 的子集,在 MySQL 的世界里就是 uft8mb3,当然 emoji 需要 uft8mb4

MySQL 会缓存查询,不过不会缓存一些系统函数以及系统表 (比如:mysql 、information_schema、 performance_schema) 的查询结果

MySQL 5.7.20 开始不再推荐使用缓存,并在 MySQL 8.0 删除

如果你发现很难权衡用什么存储引擎,或者对存储引擎没有太多了解,那么直接用默认的 InnoDB 吧

InnoDB 在 MySQL 5.6 以及以后的版本中,大多数的 DDL 语句都不会锁表了。相对的,如果用的之前的版本,都是会锁的

InnoDB 是行存储的 (默认 Compact 行格式),存下的是每一行的原始数据和额外信息,比如:VARCHAR 这种变长字段实际用的长度,null 值列表(如果没有 null 值也就没有这个列表),trx_id 事务 id

InnoDB 默认会给主键创建一个 B+ 树作为聚簇索引,其中,聚簇索引的叶子节点包含了所有的用户数据

InnoDB 对非主键创建的 B+ 树索引的叶子节点包含主键和索引列,这种索引称为二级索引。其中一个二级索引只有一个 B+ 树,即使是联合索引

InnoDB 当 where 条件只为一个二级索引列的时候,会在索引叶子节点找到主键,然后通过主键的聚簇索引找到真实记录,这个过程称为回表

InnoDB 对非主键的联合索引采取按照联合索引前边的列排序,如果命中,则按照这个顺序往后。比如:针对一个表 user_posts (id, user_id, post_id) 的联合索引 index_on_user_id_post_id。这里我们称为前缀匹配规则

更多详情见 官方文档

1
2
3
4
5
6
7
8
#有效
select * from user_posts where user_id = 343 and post_id = 121
#有效
select * from user_posts where user_id = 343
#无效
select * from user_posts where post_id = 121
#无效
select * from user_posts where user_id = 343 or post_id = 121

InnoDB 创建的联合索引时,尽量让区分度高的列在左边

在业务上有唯一保证的列或者联合列时,一定用唯一索引,杜绝脏数据的产生

一个表上索引建的越多,就会占用越多的存储空间,在增删改记录的时候性能就越差

InnoDB 对于含有索引列的模糊匹配,只会在前缀确认的情况下才会生效

InnoDB 对于 order by 含有索引列的查询是能够通过索引排序的,不过这不包含:1. 混用 ASC 与 DESC 的时候 2. 含有非索引列的时候 3. 联合索引顺序不遵循则前缀匹配规则

InnoDB 对于一个使用到索引的搜索条件和没有使用该索引的搜索条件使用 OR 连接起来后是无法使用该索引的

InnoDB 对于含有多个引列,并且每个列都有二级索引的查询,一般的做法是不断通过二级索引找到 B+ 树的叶子节点之后进行多次回表操作。某些特殊情况下会先合并索引,只进行一次回表操提升性能。不过,既然都用到多个列了,那么直接用联合索引就好了

MySQL inner join 的 on 语句,本质上和 where 是一样的。也就是说可以把一个 inner join 换成 where 的写法

MySQL 的 join 使用的是 嵌套循环连接 算法,在这个算法中,被 join 的表 (被驱动表) 如果数目大且没有索引,性能会急剧下降。这种情况如果实在无法避免,可以试着把 join buffer 参数调大,同时避免使用 select * 使不必要的数据占用空间

尽量让所有的查询都能做到 explain 下来至少 range,最好是 ref 甚至 consts

InnoDB 对任何一条记录进行写的改动的时候,会同时把当前的 trx_id 也写入

MySQL 默认开启 REPEATABLE READ 事务隔离级别,这种方式原本是会有幻读问题的。快照读通过 undo log 解决,当前读通过 gap lock 解决。

MySQL MVCC 中读操作分为快照读和当前读

  • 快照读:读到的是已经提交了的事务。比如 select .. where
  • 当前读:读到的永远是最新的内容,比如有一个事务修改了一个记录且没有提交。比如 update .. where