MySQL数据库快问快答

前言

今天楼主给你们列一下关于数据库几个常见问题的要点,若是你们对其中的问题感兴趣,能够自行扩展研究。前端

1. UNION ALL 与 UNION 的区别

  • UNION和UNION ALL关键字都是将两个结果集合并为一个。mysql

  • UNION在进行表连接后会筛选掉重复的记录,因此在表连接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。sql

  • 而UNION ALL只是简单的将两个结果合并后就返回。数据库

  • 因为UNION须要排序去重,因此 UNION ALL 的效率比 UNION 好不少。segmentfault

2. TRUNCATE 与 DELETE 区别

  • TRUNCATE 是DDL语句,而 DELETE 是DML语句。
  • TRUNCATE 是先把整张表drop调,而后重建该表。而 DELETE 是一行一行的删除,因此 TRUNCATE 的速度确定比 DELETE 速度快。
  • TRUNCATE 不能够回滚,DELETE 能够。
  • TRUNCATE 执行结果只是返回0 rows affected,能够解释为没有返回结果。
  • TRUNCATE 会重置水平线(自增加列起始位),DELETE 不会。
  • TRUNCATE 只能清理整张表,DELETE 能够按照条件删除。
  • 通常情景下,TRUNCATE性能比DELETE好一点。

3. TIMESTAMP 与 DATETIME 的区别

相同点缓存

  • TIMESTAMP 列的显示格式与 DATETIME 列相同。显示列宽固定在19字符,而且格式为YYYY-MM-DD HH:MM:SS

不一样点性能

  • TIMESTAMP
    • 4个字节存储,时间范围:1970-01-01 08:00:01~2038-01-19 11:14:07
    • 值以UTC格式保存,涉及时区转化,存储时对当前的时区进行转换,检索时再转换回当前的时区。
  • DATETIME
    • 8个字节存储,时间范围:1000-10-01 00:00:00~9999-12-31 23:59:59
    • 实际格式存储,与时区无关。

4. 什么是联合索引

两个或更多个列上的索引被称做联合索引,联合索引又叫复合索引。mysql索引

5. 为何要使用联合索引

  • 减小开销:建一个联合索引(col1,col2,col3),实际至关于建了(col1),(col1,col2),(col1,col2,col3)三个索引。减小磁盘空间的开销。
  • 覆盖索引:对联合索引(col1,col2,col3),若是有以下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL能够直接经过遍历索引取得数据,而无需回表,这减小了不少的随机io操做。覆盖索引是主要的提高性能的优化手段之一。
  • 效率高:索引列越多,经过索引筛选出的数据越少。有1000W条数据的表,有以下sql select from table where col1=1 and col2=2 and col3=3,假设假设每一个条件能够筛选出10%的数据,若是只有单值索引,那么经过该索引能筛选出1000W*10%=100w条数据,而后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,而后再排序,再分页;若是是联合索引,经过索引筛选出1000w*10%*10%*10%=1w,效率获得明显提高。

6. MySQL 联合索引最左匹配原则

  • 在 MySQL 创建联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。
  • MySQL 会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整。
  • = 和 in 能够乱序,好比a = 1 and b = 2 and c = 3 创建(a,b,c)索引能够任意顺序,mysql的查询优化器会帮你优化成索引能够识别的形式。

7. 什么是汇集和非汇集索引

  • 汇集索引就是以主键建立的索引。
  • 非汇集索引就是以非主键建立的索引。

8. 什么是覆盖索引

  • 覆盖索引(covering index)指一个查询语句的执行只用从索引页中就可以取得(若是不是汇集索引,叶子节点存储的是主键+列值,最终仍是要回表,也就是要经过主键再查找一次),避免了查到索引后,再作回表操做,减小I/O提升效率。
  • 能够结合第10个问题更容易理解。

9. 什么是前缀索引

前缀索引就是对文本的前几个字符(具体是几个字符在建立索引时指定)建立索引,这样建立起来的索引更小。可是MySQL不能在ORDER BY或GROUP BY中使用前缀索引,也不能把它们用做覆盖索引。优化

建立前缀索引的语法:spa

ALTER TABLE table_name ADD
KEY(column_name(prefix_length))
复制代码

10. InnoDB 与 MyISAM 索引存储结构的区别

  • MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。
  • 而在InnoDB中,表数据文件自己就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,所以InnoDB表数据文件自己就是主索引,因此必须有主键,若是没有显示定义,自动为生成一个隐含字段做为主键,这个字段长度为6个字节,类型为长整型。
  • InnoDB的辅助索引(Secondary Index,也就是非主键索引)存储的只是主键列和索引列,若是主键定义的比较大,其余索引也将很大。
  • MyISAM引擎使用B+Tree做为索引结构,索引文件叶节点的data域存放的是数据记录的地址,指向数据文件中对应的值,每一个节点只有该索引列的值。
  • MyISAM主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是惟一的,辅助索引能够重复,(因为MyISAM辅助索引在叶子节点上存储的是数据记录的地址,和主键索引同样,因此不须要再遍历一次主键索引)。

简单的说:

  1. 主索引的区别:InnoDB的数据文件自己就是索引文件。而MyISAM的索引和数据是分开的。

  2. 辅助索引的区别:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没有多大区别。

11. 为何尽可能选择单调递增数值类型的主键

  • InnoDB中数据记录自己被存于主索引(B+树)的叶子节点上。这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放,所以每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的结点和位置,若是页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页。

  • 若是使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引结点的后续位置,当一页写满,就会自动开辟一个新的页,这样就会造成一个紧凑的索引结构,近似顺序填满。因为每次插入时也不须要移动已有数据,所以效率很高,也不会增长不少开销在维护索引上。

  • 若是使用非自增主键,因为每次插入主键的值近似于随机,所以每次新纪录都要被插入到现有索引页的中间某个位置,此时MySQL不得不为了将新记录查到合适位置而移动元素,甚至目标页可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增长了不少开销,同时频繁的移动、分页操做形成了大量的碎片,获得了不够紧凑的索引结构,后续不得不经过 OPTIMIZE TABLE 来重建表并优化填充页面。

简单的说:

索引树只能定位到某一页,每一页内的插入仍是须要经过比较、移动插入的。因此有序主键能够提高插入效率。

12. 建表时,int 后面的长度的意义

int占多少个字节,已是固定的了,长度表明了显示的最大宽度。若是不够会用0在左边填充,但必须搭配zerofill使用。也就是说,int的长度并不影响数据的存储精度,长度只和显示有关。

13. SHOW INDEX 结果字段表明什么意思

  • Table

    • 表名。
  • Non_unique

    • 0:该索引不含重复值。
    • 1:该索引可含有重复值。
  • Key_name

    • 索引名称,若是是注解索引,名称老是为PRIMARY
  • Seq_in_index

    • 该列在索引中的序号,从 1 开始。例如:存在联合索引 idx_a_b_c (a,b,c),则a的Seq_in_index=1,b=2,c=3。
  • Column_name

    • 列名。
  • Collation

    • 索引的排列顺序:A(ascending),D (descending),NULL (not sorted)。
  • Cardinality

    • 一个衡量该索引的惟一程度的值,可使用ANALYZE TABLE(INNODB) 或者 myisamchk -a(MyISAM)更新该值。
    • 若是表记录太少,该字段的意义不大。通常状况下,该值越大,索引效率越高。
  • Sub_part

    • 对于前缀索引,用于索引的字符个数。若是整个字段都加上了索引,则显示为NULL
  • Null

    • YES:该列容许NULL值。
    • '':该列不容许NULL值。
  • Index_type

    • 索引类型,包括(BTREE, FULLTEXT, HASH, RTREE)。

14. 如何解决like'%字符串%'时索引失效?

  • LIKE问题:like 以通配符开头 ('%abc...'),mysql索引失效会变成全表扫描的操做。
    • 罪魁祸首是%,不是LIKELIKE 条件是 type = range 级别
    • %xxx%:全表扫描
    • %xxx:全表扫描
    • xxx%:range
  • 解决办法
    • 使用覆盖索引,能够由 ALL 变为INDEX,为啥呢?覆盖索引以后就能使用使用索引进行全表扫描。这里要注意一下,使用符合索引的时候,命中一个字段就能够,不用所有命中。

15. MySQL高效分页

  • 存在SQL:SELECT * FROM ttl_product_info ORDER BY id LIMIT N,M。其中 LIMIT N,M 存在的问题最大:取出N+M行,丢弃前N行,返回 N ~ N+M 行的记录,若是N值很是大,效率极差(表记录1500w,N=10000000,M=30 须要9秒)。
  • 解决办法:SQL:SELECT id FROM ttl_product_info WHERE id > N LIMIT M,id 列是索引列,id > N属于 range 级别,效率天然高,而后从位置开始取30条记录,效率极高(表记录1500w,N=10000000,M=30,须要0.9毫秒)。
  • 固然想要实现上述效果的前提是:
    1. id是惟一索引,并且单调递增。
    2. N 的值是上一次查询的记录的最后一条id,(须要前端保存一下,不能直接用传统的方法得到)
    3. 不支持跨页查询,只能按照第1,2,3,4页这样查询逐页查询。

总结

为了保持文章结构的完整性,这里强行加上一段总结。。。

参考文章:

相关文章
相关标签/搜索