Treasure / Mysql QA

Created Wed, 06 Apr 2022 00:00:00 +0000
2982 Words

聚集、非聚集、联合索引

  • A1: 聚集索引(主键索引)所有ROW都会按照主键索引进行排序

  • A2: 非聚集索引即普通索引加上字段

  • A3: 几个字段组成的索引

  • A4: 聚集索引在物理上连续,非聚集索引在物理上不连续,但在逻辑上连续

  • A5: 聚集索引影响物理存储顺序,而非聚集索引不影响

  • A6: 聚集索引插入慢,查询快,非聚集索引反之

  • A7: 索引是通过二叉树来描述的,聚集索引的子叶节点也是数据节点,而非聚集索引子叶节点仍是索引节点

自增主键有哪些问题

  • A1: 分表分库的时候可能会出现重复情况(可使用uuid替代)
  • A2: 产生表锁
  • A3: id耗尽

索引无效的情况

  • A1: 以%开头的LIKE语句,模糊匹配
  • A2: OR 前后字段未同时使用索引
  • A3: 数据类型隐式转换(varchar->int)

查询优化

  • A1: 在WHEREORDER BY所涉及的列上加上索引
  • A2: SELECT避免使用*,SQL语句全部大写
  • A3: 避免WHERE对索引列上进行IS NULL判断,替换成IS NOT NULL
  • A4: INNOT IN会导致全表扫描,替换为EXISTSNOT EXISTS
  • A5: 避免在索引上进行计算
  • A6: WHRER使用OR会放弃索引进而全表扫描

CHAR和VARCHAR的区别

  • A1: 存储和检索方式不同
  • A2: CHAR长度在创建时候指定(1~255),在存储时尾部全部填充空格

主键索引和唯一索引的区别

  • A1: 主键是一种约束
  • A2: 主键一定包含一个唯一索引,反之不成立
  • A3: 主键索引不允许包含空值,而唯一索引可以
  • A4: 一张表只能有一个主键索引,而唯一索引可以有多个

CPU飙升问题排查

  • A1: top命令观察mysqld
  • A2: 若是,则show processlist查看是否是 SQL 的问题,
  • A3: 若是,则检查执行计划是否准确,是否索引确实,数据是否太大
  • A4: kill上述线程,加索引,改内存,改SQL并重跑
  • A5: 若不是,可能是短时间有大量连接,可以限制最大连接数

如何创建索引

  • A1:

    CREATE INDEX indexName ON table; #创建普通索引
    
    DROP INDEX indexName ON table;
    
  • A2: 唯一索引和普通索引的区别是唯一索引值不允许重复

    CREATE UNIQUE INDEX indexName ON table;
    
    ALTER TABLE table ADD [UNIQUE|PRIMARY KEY] indexName; #修改表
    
    # 直接在创建时指定 
    
  • A3:

    SHOW INDEX from talbe; #显示表中的索引
    

索引

提高数据库表访问速度的一种数据结构,索引是一个文件,它需要占物理空间

优缺点

+ 加快数据查找速度,加快分组和排序的速度
+ 占用空间,降低增删改的效率,因为索引是动态维护的

何时不用

+ `where` 中用不到的字段

+ 表记录较少

+ 经常增删改

+ 区分不高的字段

+ 参与列计算的列

结构

hash表和b+树(默认)

B+树

B+树更适应磁盘特性,相比于B树减少了I/O的读写次数,而B+树的非叶子节点只存key,因此单页可以存储更多的key,一次读入内存的需要查找的key就更多,因为数据只存在叶子节点上,查询效率为O(logN),
而B树非叶子节点缓存了数据,只能通过中序遍历按序遍历,B+树叶子节点使用链表进行连接,所以遍历所有数据只需要遍历一边叶子节点,效率更高

虽然hash索引查找更快,但存储时时无序的,所以无法排序,并且不支持模糊查找,也不支持范围查找

分类

  • 主键索引 唯一非空索引,列不允许重复

  • 组合索引 在多个字段上创建的索引,需要遵从最左前缀原则,即在查询条件中,只有使用了组合索引的第一个字段,索引才会被使用

  • 唯一索引 列值唯一但可以为空 sql alter table talbe_name add unique(field...)

  • 普通索引 基本索引类型,没有唯一限制,允许为null

```sql
    alter table table_name add index index_name(field...)
```
  • 全文索引 主要用来查询文本中的关键字,只能在 char,varchar,text上使用(innodb不支持全文索引) sql alter table table_name add fulltext(field)

原理

索引用来快速查询具有特定值的记录,如果没有索引,一般而言需要遍历整张表

  • 将创建了索引的列的内容进行排序

  • 对排序内容生成倒排表

  • 在倒排表内容上拼接数据地址链

  • 查询的时候先拿到倒排表,去除数据地址链,从而难道具体数据

聚簇索引和非聚簇索引的区别

  • 聚簇索引 将索引和数据放到了同一行,找到了索引也就找到了数据,无须进行回表查询操作

    innodb 必然会有一个聚簇索引,通常是主键,若没有,则优先选择非空的唯一索引,若也没有,则会创建一个隐藏的 row_id 作为聚簇索引

  • 非聚簇索引 将索引和数据分开,找到索引后通过对应的地址找到数据行

事务四大特性

  1. 原子性: 要么全部成功,要么全部失败

  2. 一致性: 事务执行之前和执行之后都必须处于一致性状态

  3. 隔离性: 与隔离级别有关

  4. 持久性: 一旦提交,对数据库的改变就是永久的

事务隔离级别

  1. Read Commit 一个事务只能读取其他事务已提交的数据 重复读取

  2. Read Uncommit 所有事务可以读取其他事务未提交的数据,脏读

  3. Repeated Read 默认

  4. Serializable 串行化

隔离级别所带来的问题

  • 脏读 事务A读到了其他事务未提交的数据

  • 不可重复读 事务A读到了其他事务多次修改的数据,导致结果不一样

  • 幻读 事务A读到了其他事务修改的新数据,而在之前并没有这个数据

重复读和幻读的区别在于前者是修改,后者是插入或者删除,sql标准中规定的RR级别不能消除幻读,但mysql的RR可以,原因在于间隙锁Gap lock

|:-:|:-:|:-:|:-:| |隔离级别/问题|脏读|不可重复读|幻读| |RU|√|√|√| |RC|×|√|√| |RR|×|×|√| |SE|×|×|×|

MVCC

行锁

操作只锁住某一行,不能其它行有影响,它是一种排它锁(写锁)防止其他事务修改当前事务的操作数据,(innodb)默认锁机制 特点是开销大,加锁慢,会出现死锁,锁的颗粒最小,并发最高,冲突最低

表锁

操作时会锁定整张表,(myisam)的默认机制

特定是开销小,加锁快,不会出现死锁,锁的颗粒大,并发低,冲突高

页锁

操作是锁住一页数据(16kb) 特定是介于行锁和表锁之间,会出现死锁,并发度一般

读写锁

处理并发读读和写时,通常使用共享锁(读锁)和排他锁(写锁)

  • 读锁时共享的,相互之间不会阻塞,多个事务同一时刻能获取同一资源,但是不可修改数据

  • 写锁时排他的,其他事务不能获取这条数据的读锁和写锁

  • 加锁的sql

    • select * form table // 不加锁

    • update/insert/delete // 加排他锁

    • select * form table where id // id如果是索引,就加排他锁

    • select * form table where id lock in share mode // 共享锁

死锁

当多个事务以不同的顺序锁定资源,或者同时锁定同一个资源都会产生死锁

解决思路

+ innodb 可以自动检测死锁,使用一个事务回滚,另一个事务继续

+ 设置超时等待参数 `innodb_local_wait_timeout`

如何避免

+ 不同业务并发访问多个表时,编写相同的顺序访问

+ 在事务中如果更新记录,使用排他锁

binlog redolog undolog relaylog

binlog

  事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。

  这里与redo log很明显的差异就是redo log并不一定是在事务提交的时候刷新到磁盘,redo log是在事务开始之后就开始逐步写入磁盘。

  因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的,但是在开启了bin_log的情况下,对于较大事务的提交,可能会变得比较慢一些。

用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。

用于数据库的基于时间点的还原。

redolog

事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。

确保事务的持久性。redo日志记录事务执行后的状态,用来恢复未写入data file的已成功事务更新的数据。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。

undolog

事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性

保证数据的原子性,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读

relaylog