聚集、非聚集、联合索引
-
A1: 聚集索引(主键索引)所有ROW都会按照主键索引进行排序
-
A2: 非聚集索引即普通索引加上字段
-
A3: 几个字段组成的索引
-
A4: 聚集索引在物理上连续,非聚集索引在物理上不连续,但在逻辑上连续
-
A5: 聚集索引影响物理存储顺序,而非聚集索引不影响
-
A6: 聚集索引插入慢,查询快,非聚集索引反之
-
A7: 索引是通过二叉树来描述的,聚集索引的子叶节点也是数据节点,而非聚集索引子叶节点仍是索引节点
自增主键有哪些问题
- A1: 分表分库的时候可能会出现重复情况(可使用uuid替代)
- A2: 产生表锁
- A3: id耗尽
索引无效的情况
- A1: 以
%
开头的LIKE
语句,模糊匹配 - A2:
OR
前后字段未同时使用索引 - A3: 数据类型隐式转换(varchar->int)
查询优化
- A1: 在
WHERE
和ORDER BY
所涉及的列上加上索引 - A2:
SELECT
避免使用*
,SQL语句全部大写 - A3: 避免
WHERE
对索引列上进行IS NULL
判断,替换成IS NOT NULL
- A4:
IN
和NOT IN
会导致全表扫描,替换为EXISTS
或NOT 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 作为聚簇索引
-
非聚簇索引 将索引和数据分开,找到索引后通过对应的地址找到数据行
事务四大特性
-
原子性: 要么全部成功,要么全部失败
-
一致性: 事务执行之前和执行之后都必须处于一致性状态
-
隔离性: 与隔离级别有关
-
持久性: 一旦提交,对数据库的改变就是永久的
事务隔离级别
-
Read Commit 一个事务只能读取其他事务已提交的数据 重复读取
-
Read Uncommit 所有事务可以读取其他事务未提交的数据,脏读
-
Repeated Read 默认
-
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),也即非锁定读