Mysql学习笔记

Mysql 常见数据类型及所占字节

INT 4
BIGINT 8
DECIMAL(M,D) M+2
DATETIME 8
TIMESTAMP 4
CHAR(M) M
VARCHAR(M) M

分析SQL执行效率

  • 查看慢查询日志

    1. 开启慢查询日志
      slow_query_log=on 决定是否开启
    2. 设置阈值
      long_query_time 默认10s
      min_examined_row_limit(默认值 0)设置的值并且扫描记录数不小于
      log_slow_admin_statements = on 设置管理语句
      log_queries_not_using_indexes = on 设置不使用索引的语句都记录
    3. 确定日志路径
  • show processlist 查看正在执行的慢查询

    show processlist 命令判断正在执行的慢查询

    show processlist\G
  • 使用 explain 分析慢查询

条件字段有索引,为什么查询也这么慢?

  1. 函数操作
  2. 隐式转换(当操作符与不同类型的操作对象一起使用时,就会发生类型转换以使操作兼容。某些转换是隐式的),sql字段类型varchar 加引号
  3. 模糊查询,不能以’%‘开头
  4. 范围查询,避免查询的范围过大
  5. 计算操作,最好将计算结果放到代码里,其次将计算放到等号后边

让order by、group by查询更快

参数:
1.max_length_for_sort_data:如果觉得排序效率比较低,可以适当加大 max_length_for_sort_data 的值,让优化器优先选择全字段排序。当然不能设置过大,可能会导致 CPU 利用率过低或者磁盘 I/O 过高;

  1. sort_buffer_size:适当加大 sort_buffer_size 的值,尽可能让排序在内存中完成。但不能设置过大,可能导致数据库服务器 SWAP

mysql 的排序方式:通过有序索引直接返回数据;通过filesort进行排序
filesort 内存排序还是磁盘排序?通过trace 分析sql是否使用了临时文件,没有则是内存排序

  • MySQL 通过 max_length_for_sort_data 这个参数来控制排序,在不同场景使用不同的排序模式,从而提升排序效率
  • 多个字段排序的情况,如果要通过添加索引优化,得注意排序字段的顺序与联合索引中列的顺序要一致
  • 对于先等值查询再排序的语句,可以通过在条件字段和排序字段添加联合索引来优化此类排序语句

换种思路写分页查询

  1. 根据自增且连续主键排序的分页查询
select * from t1 order by a limit 99000,2;
  1. 查询根据非主键字段排序的分页查询优化
select * from t1 f inner join (select id from t1 order by a limit 99000,2)g on f.id = g.id;

对于其它一些复杂的分页查询,也基本可以按照这两个思路去优化,尤其是第二种优化方式。第一种优化方式需要主键连续,而主键连续对于一个正常业务表来说可能有点困难,总会有些数据行删除的,但是占用了一个主键 id。

为何count(*)这么慢

  1. count(a) 和 count(*) 的区别

    对 a 字段为 null 的这一行不做统计。而 count(*) 无论是否包含空值,都会统计

  2. MyISAM 引擎和 InnoDB 引擎 count(*) 的区别

    MyISAM 会维护表的总行数,放在磁盘中,如果有 count(*) 的需求,直接返回这个数据
    InnoDB 就会去遍历普通索引树,计算表数据总量

  3. count(1) 比 count(*) 快吗? 执行计划都是一样的
  4. 哪些方法可以加快 count()

    • show table status:能快速获取结果,但是结果不准确;
    • 用 Redis 做计数器:能快速获取结果,比 show table status 结果准确,但是并发场景计数可能不准确;
    • 增加 InnoDB 计数表:能快速获取结果,利用了事务特性确保了计数的准确,也是比较推荐的方法。

数据库忽然断电会丢数据吗?

Redo log 称为重做日志,用于记录事务操作变化,记录的是数据被修改之后的值
Redo log 由两部分组成:innodb_flush_log_at_trx_commit 来控制 redo log buffer 更新到 redo log file 的时机

  • 内存中的重做日志缓冲(redo log buffer)
  • 重做日志文件(redo log file)

binlog 记录了所有的 DDL(数据定义语句)和 DML(数据操纵语句),但是不包括 select 和 show 这类操作

  • sync_binlog=0,表示每次提交事务都只write,不fsync
  • sync_binlog=1,表示每次提交事务都会执行fsync
  • sync_binlog=N(N>1),表示每次提交事务都write,累积N个事务后才fsync

只要 innodb_flush_log_at_trx_commit 和 sync_binlog 都为 1(通常称为:双一),就能确保 MySQL 机器断电重启后,数据不丢失

如何预防SQL注入

产生的原因:程序对用户输入的数据没有进行严格的过滤,导致攻击者增加一些特殊字符,从而改变传输到 MySQL 中的 SQL。
SQL 注入危害:会导致攻击者非法入侵系统,或者盗取数据,甚至清空数据等
预防:

  • 控制输入变量的格式
  • 转义特殊字符(addslashes)
  • 使用预处理 pdo

主键是否需要设置为自增

  1. 主键和聚集索引的关系

    • 在 InnoDB 中,聚集索引不一定是主键,但是主键一定是聚集索引:原因是如果没有定义主键,聚集索引可能是第一个不允许为 null 的唯一索引,如果也没有这样的唯一索引,InnoDB 会选择内置 6 字节长的 ROWID 作为隐含的聚集索引。
    • InnoDB 的数据是按照主键顺序存放的,而聚集索引就是按照每张表的主键构造一颗 B+ 树,它的叶子节点存放的是整行数据
    • 每张 InnoDB 表都有一个聚集索引,但是不一定有主键
  2. 是否有必要设置自增

    • 如果主键是随机的,那么写入数据时很可能会导致数据页频繁分裂,从而导致写入效率低和页空间浪费。
-如果设置主键是自增,那么每一次都是在聚集索引的最后增加,当一页写满,就会自动开辟一个新页,不会有聚集索引树分裂这一步效率会比随机主键高很多
    

InnoDB替代MyISAM的重要原因

  • InnoDB 支持事务:适合在并发条件下要求数据一致的场景。
  • InnoDB 支持行锁:有效降低由于删除或者更新导致的锁定。

解释一下脏读和幻读

  • 脏读:读取未提交的事务。
  • 幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据

事务隔离级别

  • Read uncommitted(读未提交): 在该隔离级别,所有事务都可以看到其它未提交事务的执行结果。可能会出现脏读。
  • Read Committed(读已提交,简称: RC):一个事务只能看见已经提交事务所做的改变。因为同一事务的其它实例在该实例处理期间可能会有新的 commit,所以可能出现幻读。
  • Repeatable Read(可重复读,简称:RR):这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。消除了脏读、不可重复读,默认也不会出现幻读。
  • Serializable(串行):这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。

普通索引和唯一索引有哪些区别


- 普通索引的字段可以写入重复的值,而有唯一索引的字段不可以写入重复的值
- 数据修改时,普通索引可以用 Change Buffer,而唯一索引不行。
- 数据修改时,唯一索引在 RR 隔离级别下,更容易出现死锁。
- 查询数据是,普通索引查到满足条件的第一条记录还需要继续查找下一个记录,而唯一索引查找到第一个记录就可以直接返回结果了,
- 但是普通索引多出的查找次数所消耗的资源多数情况可以忽略不计


MySQL是否需要开启查询缓存

  1. 解释几个参数

    • have_query_cache:服务器在安装时是否已经配置了高速缓存
    • query_cache_limit:单条查询能够使用的缓存区大小
    • query_cache_min_res_unit:查询缓存分配内存块的最小单位
    • query_cache_size:缓存区的大小,单位为 MB
    • query_cache_type:缓存类型,有三个值可选:0 或者 off:关闭缓存 1 或者 on:打开缓存 2 或者 demand:只缓存带有 sql_cache 的 select 语句。
  2. 如果线上环境中 99% 以上都是只读,很少更新,可以考虑全局开启 QC,也就是设置 query_cache_type 为 1
  3. 如果希望缓存的是几张更新频率很低的表,其它表不考虑使用查询缓存,就可以考虑将 query_cache_type 设置成 2 或者 DEMAND

联合索引有哪些讲究

联合索引:是指对表上的多个列进行索引。适合 where 条件中的多列组合,在某些场景可以避免回表

  • 对于 a、b 两个字段都做为条件时,查询是可以走索引的;
  • 对于单独 a 字段查询也是可以走索引的。但是对于 b 字段单独查询就走不了索引了
可以完整用到联合索引的情况
  1. 联合索引各字段都做为条件时,各字段的位置不会影响联合索引的使用
  2. 联合索引前面的字段使用了范围查询,后面的字段做为条件时仍然可以使用完整的联合索引
  3. 联合索引前面的字段做为条件时,对后面的字段做排序可以使用完整的联合索引
  4. 对联合索引的字段同时做排序时
只能使用部分联合索引的情况
  1. 当条件只包含联合索引的前面部分字段时,可以用到部分联合索引
  2. 联合索引 idx_a_b_c(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c) 三种索引,称为联合索引的最左原则
不能使用联合索引的情况
  1. 如果只使用联合索引后面的字段做为条件查询,则使用不了联合索引(联合索引最左匹配)
  2. 对联合索引后面的字段做排序操作,也使用不了联合索引
  3. c 字段单独做条件使用不了索引
  4. 如果第一个字段在条件中没有出现,那么联合索引的后面所有字段作为条件都无法使用这个联合索引

Btree 索引和 HASH 索引有什么区别

两者区别:

  • Btree 索引可能需要多次运用折半查找来找到对应的数据库;
  • HASH 索引是通过 HASH 函数,计算出 HASH 值,在表中找出对应的数据。

优缺点对比:

  • 大量不同数据等值精确查询,HASH 索引效率通常比 B+TREE 高;
  • HASH 索引不支持模糊查询、排序、范围查询和联合索引中的最左匹配原则,而这些 Btree 索引都支持。

MVCC怎么实现的?

undo log 是逻辑日志,将数据库逻辑地恢复到原来的样子,所有修改都被逻辑地取消了

InnoDB 每一行数据都有一个隐藏的回滚指针,用于指向该行修改前的最后一个历史版本,这个历史版本存放在 undo log 中。如果要执行更新操作,会将原记录放入 undo log 中,并通过隐藏的回滚指针指向 undo log 中的原记录。其它事务此时需要查询时,就是查询 undo log 中这行数据的最后一个历史版本

MVCC 最大的好处是读不加锁,读写不冲突,极大的增加了 MySQL 的并发性,通过 MVCC,也保证了事务 ACID 中的 I(隔离性)特性

哪些情况需要考虑分库分表

1.MySQL 分库分表拆分方法

- 垂直拆分
    有多个业务,每个业务单独分到一个实例里面
    在一个实例中有多个库,把这些库分别放到单独的实例中
        在一个库中存在过多的表,把这些表拆分到多个库中
    把字段过多的表拆分成多个表,每张表包含一部分字段
- 水平拆分
    - 把同一张表分为多张表结构相同的表,每张表里存储一部分数据。而拆分的算法也比较多,常见的就是取模、范围、和全局表等

2.哪些情况需要考虑分库分表

你可能感兴趣的:(mysql优化)