mysql 学习笔记(实践篇)

实践篇

09 | 普通索引和惟一索引

  • 查询过程:性能几乎无差异
  • 更新过程:普通索引 更新的目标页不在内存中可使用到change buffer。建议使用普通索引。html

    change buffer:当须要更新一个数据页时,若是数据页在内存中就直接更新,而若是这个数据页尚未在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操做缓存在 change buffer 中,这样就不须要从磁盘中读入这个数据页了。在下次查询须要访问这个数据页的时候,将数据页读入内存,而后执行 change buffer 中与这个页有关的操做。经过这种方式就能保证这个数据逻辑的正确性。
  • redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 change buffer 主要节省的则是随机读磁盘的 IO 消耗。

10 | MySQL为何有时候会选错索引

  • explain 查询语句执行状况

  • show index 能够查看索引基数

  • 优化器的选择主要基于扫描行数(mysql使用采样统计计算,非准确数字)判断

  • analyze table t 能够优化查询分析

  • 索引选择异常和处理mysql

    • force index 强行选择一个索引(通常不须要,只有在查询分析判断问题时使用,基本仍是使用mysql内部优化器机制)
    • 更新语句,如使用 order by b,a 就会使用a,b索引
    • 业务沟通,删除没必要要的查询索引
    • *

11 | 怎么给字符串字段加索引?

  • 前缀索引,定义好长度,就能够作到既节省空间,又不用额外增长太多的查询成本。alter table SUser add index index2(email(6));
  • 前缀索引长度:创建索引时关注的是区分度,区分度越高越好。由于区分度越高,意味着重复的键值越少。所以,咱们能够经过统计索引上有多少个不一样的值来判断要使用多长的前缀。sql

    mysql> select 
      count(distinct left(email,4))as L4,
      count(distinct left(email,5))as L5,
      count(distinct left(email,6))as L6,
      count(distinct left(email,7))as L7,
    from SUser;
  • 使用前缀索引极可能会损失区分度,因此你须要预先设定一个能够接受的损失比例,好比 5%。而后,在返回的 L4~L7 中,找出不小于 L * 95% 的值,假设这里 L六、L7 都知足,你就能够选择前缀长度为 6。
  • 前缀索引就用不上覆盖索引对查询性能的优化
  • 对身份证相似的索引,若是用前缀的话,区分度过低,就不合适,解决方案有几种。数据库

    • 使用身份证倒序存储,reverse()
    • 增长整形的hash字段,如crc32()
    • *

12 | 为何个人MySQL会“抖”一下?

  • 更新主要是写内容和日志,更新内容会先存入内存(没有同步的叫脏页),等时机(4种状况)再写入磁盘。缓存

    1. redo log 写满了。这时候系统会中止全部更新操做,把 checkpoint 往前推动,redo log 留出空间能够继续写
    2. 内存不足。当须要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用。若是淘汰的是“脏页”,就要先将脏页写到磁盘。
    3. 系统空闲
    4. 系统重启
  • InnoDb使用刷新内存机制。InnoDB 用缓冲池(buffer pool)管理内存

image.png

  • InnoDB 的刷盘速度就是要参考这两个因素:一个是脏页比例,一个是 redo log 写盘速度。

image.png
image.png
image.png


13 | 为何表数据删掉一半,表文件大小不变?

  • 将innodb_file_per_table 设置为 ON,表数据是单独的文件ibd,drop table后会删除文件,并回收空间,不然不行。
  • 记录复用:删除记录的空间,符合条件的数据下次插入时候会使用
  • 数据页复用:删除后整个数据页被标记为可复用。
  • 插入数据:若是当前数据页已满,则会数据页分裂,可能形成数据空洞。
  • 重建表:
    image.png

14 | count(*)这么慢,我该怎么办?

  • Myisam 有一个地方专门记录总数
  • InnoBb 由于是事物,并发等属性,不能直接获取,只能经过遍历最小的那颗索引树实现。
  • count(*)、count(主键 id) 和 count(1) 都表示返回知足条件的结果集的总行数;而 count(字段),则表示返回知足条件的数据行里面,参数“字段”不为 NULL 的总个数。
  • 尽可能使用count(*)
    • *

16 | “order by”是怎么工做的?

  • 全字段排序:并发

    • 须要查询的字段 初始化 放入sort_buffer。
    • sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。若是要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但若是排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。
  • rowid排序:socket

    • 设置 max_length_for_sort_data 大小,若是单行数据太大,使用rowid排序,rowid排序须要结果再回表查询
  • mysql默认使用全字段排序,原则尽可能使用内存,尽可能少回表。

17 | 如何正确地显示随机消息?

  • order by rand() 使用了内存临时表,内存临时表排序的时候使用了 rowid 排序方法。要尽可能避免使用该方法。
  • image.png
  • 扫描行数是C+(Y1+1)+(Y2+1)+(Y3+1)
  • 进一步优化:
  • image.png

18 | 为何这些SQL语句逻辑相同,性能却差别巨大?

  • 索引字段作函数操做,会破坏索引值的有序性。
  • 隐式类型转换:mysql 默认比较会把字符串转换成数字。若是数字转换成字符串,优化器会默认添加函数,因此破坏索引。需使用 where id=''的单引号。
  • 隐式字符编码转换:函数

    • mysql> select d.* from tradelog l , trade_detail d where d.tradeid=CONVERT(l.tradeid USING utf8) and l.id=2;

19 | 为何我只查一行的语句,也执行这么慢

  • 第一类:简单查询长时间不返回工具

    • 等MDL锁,等flush,等行锁
    • show processlist
    • image.png
    • MySQL 启动时须要设置 performance_schema=on,相比于设置为 off 会有 10% 左右的性能损失。经过查询 sys.schema_table_lock_waits 这张表,咱们就能够直接找出形成阻塞的 process id,把这个链接用 kill 命令断开便可。
  • 第二类:查询慢oop

    • 慢查询日志
    • lock in share mode 的 SQL 语句,是当前读,所以会直接读到 1000001 这个结果。
    • select * from t where id=1 这个语句,是一致性读,所以须要从 1000001 开始,依次执行 undo log,执行了 100 万次之后,才将 1 这个结果返回
    • *

20 | 幻读是什么,幻读有什么问题?

  • innoDB 间隙锁,next-key lock。

22 | MySQL有哪些“饮鸩止渴”提升性能的方法?

  • 第一种方法:先处理掉那些占着链接可是不工做的线程。
  • 第二种方法:减小链接过程的消耗。
  • 慢查询性能问题
  • QPS 突增问题
  • 全量回归测试工具(pt-query-digest
    • *

23 | MySQL是怎么保证数据不丢的?

  • redo log 和 binlog 都是顺序写,磁盘的顺序写比随机写速度要快;* 组提交机制,能够大幅度下降磁盘的 IOPS 消耗。
  • IO瓶颈解决方法:

    • image.png
  • 一般咱们说 MySQL 的“双 1”配置,指的就是 sync_binlog 和 innodb_flush_log_at_trx_commit 都设置成 1。也就是说,一个事务完整提交前,须要等待两次刷盘,一次是 redo log(prepare 阶段),一次是 binlog。
  • 2,15,23章节redo log,bin log 和crash safe.

24 | MySQL是怎么保证主备一致的?

  • 主备切换,binlog格式

    • statement:可能引发不一致
    • row:全量信息,能够恢复全部数据。缺点,占用空间大。
    • mixed:有风险的sql语句,会使用row格式记录。
  • MariaDB 的flashback 工具:恢复数据误操做。

25 | MySQL是怎么保证高可用的?

  • 主备延迟的几种状况

    • 主备机器性能
    • 备库压力偏大(查询等等)
    • 大事物
  • 策略

    • 可靠性优先策略
    • 可用性优先策略

31 | 误删数据后除了跑路,还能怎么办?

  • sql_safe_updates=On 更新或删除强制带where
  • 设置有效的全量备份点。经过binlog恢复数据
  • 权限帐号管理。

32 | 为何还有kill不掉的语句?

  • 缘由1:更改状态,发信号给block线程。
  • 缘由2:大查询回滚,DDL,大事务,逻辑耗时长。
  • 解决办法:影响系统环境

    • 增长并行线程数量 innodb_thread_concurrency
    • 减轻IO系统压力
  • 客户端链接超多表数据库使用-A(不用-q)

33 | 我查这么多数据,会不会把数据库内存打爆?

  • 全表扫描是边算边发,经过socket receive buffer栈。
  • InnoDB全表扫描有淘汰机制,LRU.

34 | 到底可不可使用join?

  • 使用 join 语句,性能比强行拆成多个单表执行 SQL 语句的性能要好;
  • 若是使用 join 语句的话,须要让小表(where过滤后数据量小的)作驱动表。
  • 被驱动表能用索引最好,不然使用内存判断(Block Nested-Loop Join)
相关文章
相关标签/搜索