这一段时间一直在学习关系型数据库,准备写一个小专题来总结一下这一段时间的学习结果。
话说数据库优化一直是SQL型数据库的热门问题,包括从网络I/O方面,从硬盘I/O方面,从CPU计算方面等等很多手段,都可以对数据库进行优化。
这篇文章主要总结了如何建立合适的索引提升查询速度,如何通过优化SQL提升语句执行速度。
当然这些探讨都是浅尝辄止的,如果有任何谬误,希望大家指出。
首先聚合索引是提升查询速度的最有效的手段。基于聚合索引的性质,我们可以了解到,数据库的物理存储顺序是按照聚合索引顺序排列的,而通过聚合索引的B+树,我们可以迅速的查找到任何一行的全部信息,注意是全部信息。
不了解聚集索引的同学可以参考我的 数据库(3)数据库索引这篇文章。
在Mysql中,InnoDB引擎会默认主键索引为聚集索引,所以建立一个表时,我们应该优先设立一个主键,后面所有基于主键的WHERE条件查询语句
都会使用到这个聚集索引。
主键索引的选取,可以参考以下原则:
CREATE TABLE test(
id INT PRIMARY KEY,
# 其他字段
);
同时需要特别注意的是,如果在一个表有很多数据的情况下,添加了主键,那么会导致这个表重新对硬盘上的存储结构做调整,这是一个费时的过程,所以推荐在建表时就建立主键,从而获得聚集索引。
我们知道,对于数据的查询,一般是通过条件查询(WHERE语句
),而如果条件查询中的字段上没有建立索引的话,就会进行一次全表扫描,这是非常耗时的操作。
CREATE TABLE test(
id INT,
name VARCHAR(20)
); // 假设test表没有任何索引
SELECT name FROM test WHERE id=100; // 这条语句会导致全表查询,然后再进行where语句筛选(没有支持ICP的情况下)
这时候我们需要对id
字段建立索引
CREATE INDEX index_name
ON table_name (id)
这样再进行查询语句就会使用B+树进行索引查询得到id=100
的索引叶节点,然后根据查到的聚合索引的值,进行二次查找得到name
更好的解决方案是建立一个组合索引
CREATE INDEX index_name
ON table_name (id,name)
这样就不需要进行二次查询,而是直接完全通过索引B+树的叶子节点内容久能得到name
其实在上一篇文章中已经说过这个东西了,这里再拿出来说一下的原因是,有些索引你虽然建立了,但数据库不见得会用到这种查询手段。
比如说你建立了一个表:
CREATE TABLE test(
name_1 CHAR(20),
name_2 CHAR(20),
name_3 CHAR(20),
INDEX index_1 (name_1,name_2,name_3)
);
建立了一个组合索引(name_1,name_2,name_3)
然后你美滋滋的进行了一波查询:
SELECT name_1 FROM test WHERE name_1='haha';
SELECT name_1 FROM test WHERE name_2='wuwu';
SELECT name_1 FROM test WHERE name_3='yingyingying';
SELECT name_1 FROM test WHERE name_1='haha' AND name_2='wuwu';
SELECT name_1 FROM test WHERE name_1='haha' AND name_3='yingyingying';
我们逐条来分析这些语句会如何使用索引进行查询:
name_1
在建立的索引里,而条件语句中WHERE name_1='haha'
也在索引里,而且符合最左前缀规则,索引毫无疑问,这次查询会直接使用索引查询,而且查询数据在索引叶子节点里,查询效率是很高的。name_1
在建立的索引里,而条件语句中WHERE name_2='wuwu'
也在索引里,但不符合最左前缀原则,这种查询不会使用到B+树的优秀特性,而是会进行全索引查询,然后再比较WHERE语句条件name_1
在建立的索引里,条件语句WHERE name_1='haha' AND name_2='wuwu'
字段在索引里,而且符合最左前缀原则,因此会利用B+树的性质进行查询,效率是很高的。WHERE name_1='haha' AND name_3='yingyingying'
条件语句违背了最左前缀原则,需要进行全索引查询,而且这种写法会进行两次WHERE语句条件的比较,效率及其低下。可以看到,建立组合索引优化查询语句时,一定要考虑到最左前缀原则,否则你的索引建立的可以说毫无意义。
什么是无意义的索引?
基本上就是和上面体到的原则冲突的索引类型:
DML(INSERT,UPDATE,DELETE)
性能的,如果一条语句查询语句一天都用不到几次,你却为它建立了繁杂的索引,那么将会导致数据表很不科学。对于这方面我是真的不敢信口开河,因为我也只是处于学习阶段,因此也只总结一些常见的优化手段。
这是显而易见的一条原则,我们知道B树这种数据结构实在是太适合数据库存储了,查询性能比起顺序查询高出太多倍了,因此如果能利用到自己建立的索引,那么就会极大的提升查询语句的性能。
SQL什么条件会使用索引?
当字段上建有索引时,通常以下情况会使用索引,在WHERE语句中:
INDEX_COLUMN = x
INDEX_COLUMN > x
INDEX_COLUMN >= x
INDEX_COLUMN < x
INDEX_COLUMN <= x
INDEX_COLUMN between x and x
INDEX_COLUMN in (x,y,...,z)
INDEX_COLUMN like 'x' 或者 'x%'(后导模糊查询)
T1. INDEX_COLUMN=T2. COLUMN1(两个表通过索引字段关联)
以上x,y,z代表任何和INDEX_COLUMN同一类型的数据
可以看到几乎是和能使用索引查询的情况对立的。总结就是
distinct在查询一个字段或者很少字段的情况下使用,会避免重复数据的出现,给查询带来优化效果。
但是查询字段很多的情况下使用,则会大大降低查询效率。
这样会减少I/O查询的次数。
这样会减少网络I/O的压力,避免一次传输数据过多导致速度变慢。
JDBC中的批处理了解一下,批量插入比起循环插入性能高太多了(当然这还和编程语言已经网络有关)
参考资料: