什么是DDL、DML、DQL
DDL(数据定义语言),用来定义(创建删除修改)数据库对象(数据库、表、字段)
DML(数据操纵语言),用来对数据库表中的数据进行增删查改(insert、delete、select、update),DQL(数据库查询语言),用来查询数据库表中的记录
DCL(数据控制语言),用来创建数据库用户、控制数据库访问权限等,常用关键字有 GRANT、REVOKE 等
了解过索引吗(什么是索引)?
索引是帮助mysql高效获取数据的数据结构(有序)。mysql InnoDB索引的底层实现是B+树。
B树和B+树
B树:是一种多路平衡查找树,相对于二叉树,b树每个节点可以有多个分支
以一颗最大度数(max-degree)为5的b树为例,该b树的每个节点最多可以存储4个key
b+树是b树的优化,非叶子节点只存储指针,不存储数据,叶子节点存储数据。叶子节点之间是一个双向循环链表。
MySQL的InnoDB引擎采用的B+树的数据结构来存储索引的优点
1、阶数更多,路径更短
2、磁盘读写代价B+树更低,非叶子节点只存储指针,叶子阶段存储数据
3、B+树便于扫库和区间查询,叶子节点是一个双向链表
面试题:索引(index)是帮助MySQL高效获取数据的数据结构(有序)提高数据检索的效率,降低数据库的IO成本(不需要全表扫描)
通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。
什么是聚簇索引?什么是非聚簇索引
聚簇索引:将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据,必须有且只有一个,物理上有序。
聚集索引选取规则:
-
如果存在主键,主键索引就是聚集索引。
-
如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
-
如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置(id),可以多个,逻辑上有序,物理上无序
聚集索引和非聚集索引详解
回表查询
通过非聚集索引找到对应的主键值,然后拿着主键值到聚集索引中查找整行的数据,这个过程就是回表查询。
上述图中,select * … 通过二级索引查询不到全部的数据,需要回表查询,因此尽量避免使用select *
覆盖索引:是指查询使用了索引且需要返回的列,在该索引中全部能找到,不需要回表查询。
索引创建原则
- 针对数据量大且查询频繁的表建立索引(单表数据超过10w)*
- 针对常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引 *
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,索引的效率越高
- 若是字符串类型的字段,字段的长度较长,可以建立前缀索引
- 尽量使用联合索引,减少单索引,联合索引很多时候是覆盖索引,节省内存空间,避免回表查询,提高效率。*
- 控制索引的数量,索引不是越多越好,索引越多,维护索引结构的代价就越大,会影响增删改的效率。*
- 若索引列不能存储null值,请在创建表时使用not null约束。当优化器知道每列是否包含null值时,它可以更好的确定哪个索引最有效地用于查询。
索引失效情场景:
假设name,status,address字段是一个组合索引 idx_nsa
1、违反最左前缀法则(最左前缀法则是指查询从索引的最左列开始,不跳过索引中的列)
# 符合最左前缀法则情况
where name = 'xxx'
where name = 'xxx' and status = 1
where name = 'xxx' and address = 'xxx'
where name = 'xxx' and status = 1 and address = 'xx'
#违反最左前缀法则情况
where status = 1 and address = 'xx'
2、范围查询,右边的列索引失效
# status 范围查询,address索引失效
where name = 'xxx' and status > 1 and address = 'xx'
3、在索引列上使用运算操作或使用函数,该索引列失效
# 在name列上使用了substring ,索引失效
where substring(name,3,2) = 'xx'
# 在id列上使用操作运算符 ,索引失效
where id + 1 = 2
4、字段类型不同
# 字符串不加单/双引号,造成索引失效
where address = xx
5、以%开头的模糊查询可能会使索引失效。若是尾部模糊匹配,索引不会失效
# 可能会使索引失效
where address like '%xxx'
# 索引不会失效
where address like 'xxx%'
6、select *
# 查询使用了select * 且查询条件不是索引列
select * from table_name where sex = 1
7、列对比
select * from user where id=height
8、使用or关键字
where name = 'xxx' or status = 1
9、not in 和 not exists (聚集索引不会失效,非聚集索引会失效)
# 索引不会失效
where id not in(1,2)
# 如果是组合索引且符合最左前缀法则,索引也不会失效
where name not in('t','b')
# 索引失效
where status not in(1,2)
面试题:谈谈你对sql优化的经验
表的设计优化(参考阿里开发手册《嵩山版》)
- 根据实际情况选择合适的数值类型(tinyint;int;bigint),
- 根据实际情况选择合适的字符串类型(char;varchar)char是定长的,效率高;varchar是可变长度的,效率稍低
- …
sql语句优化
-
select语句必须指明字段(禁止使用select *)
-
sql语句避免索引失效的写法
-
尽量使用union all 代替 union;(union all和union的区别:取结果的交集,union对两个结果集进行并集操作,不包括重复行,相当于distinct,同时进行默认规则的排序;union all:对两个结果集进行并集操作,包括重复行,即所有的结果全部显示,不管是不是重复。)
-
join优化 能用inner join 就不用left/right join ;若必须使用,要与小表为驱动
-
内连接会对两个表优化,优先把小表放外边,大表放里边。left/right join 不会调整顺序。
超大数据分页问题
优化思路:一般分页查询时,通过覆盖索引能够比较好地提高性能,可以通过覆盖索引+子查询的方式进行优化。
示例:
select * from stu s,(select id from stu order by id limit 9000000,10) t where s.id = t.id
面试题:了解mysql事务吗
mysql事务
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作视为一个不可分割的整体一起向系统提交或撤销操作请求,即这些操作要么同时成功;要么同时失败。
事务的特性ACID
-
原子性(Atomicity):事务是不可分割的最小操作单元,要么全成功,要么全失败
-
一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态
-
隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
-
持久性(Durability):事务一旦提交或回滚,它对数据库的数据的改变时永久性的
并发事务带来哪些问题?怎么解决这些问题?mysql的默认隔离级别?
并发事务问题
脏读:一个事务读取到了另一个事务尚未提交的数据,也就是读取到了"脏数据"。如果后续未提交的事务回滚了,则读取到的数据就是无效的。脏读会导致数据不一致,因此需要避免。
不可重复读:一个事务在同一个时间点内多次读取同一行数据,但是读取到的数据不一致。这是因为在读取过程中,另一个事务修改了该行数据并提交了事务。不可重复读也会导致数据不一致,因此也需要避免。
幻读:一个事务在同一个时间点内多次执行相同的查询,但是返回的结果集不一致。这是因为在查询过程中,另一个事务插入了符合查询条件的新数据并提交了事务。幻读也会导致数据不一致,因此也需要避免。
隔离级别:读未提交、读已提交、可重复读、串行化(低到高)
这四个概念都是数据库中的事务隔离级别,用来控制事务之间的隔离性和数据一致性。
- 读未提交(Read Uncommitted):最低的隔离级别,一个事务可以读取到另一个事务尚未提交的数据,也就是脏读。读未提交级别可以提高并发性,但是会导致数据不一致。
- 读已提交(Read Committed):一个事务只能读取到已经提交的数据,避免了脏读的问题。但是在同一个事务中,多次读取同一行数据可能会出现不一致的情况,也就是不可重复读。
- 可重复读(Repeatable Read):一个事务在同一个时间点内多次读取同一行数据,读取到的数据是一致的,避免了不可重复读的问题。但是在同一个事务中,多次查询可能会出现不一致的情况,也就是幻读。
- 串行化(Serializable):最高的隔离级别,通过强制事务串行执行来避免脏读、不可重复读和幻读的问题。但是串行化会导致并发性降低,因为多个事务需要串行执行。
总结