到西安刚好十天,早八点,晚九点,每周工作六天,感觉整个人都不好了;
对了,抽空去了趟大雁塔,毕竟住在景区,一公里路程。
ps: 音乐喷泉很不错!
上图,上图;
在公司楼上拍的;
对了,要开始sql优化了!
一、优化场景
我所在的项目组在做国家xxxxx风险分析技术平台的接入、核验、分析工作,没错就是P2P理财,小额贷款等金融平台了,我主要负责数据服务工作,具体就是各种指标的分析,接口服务了。
要做指标分析,就要进行数据的查询等操作。
数据存储引擎: mysql,至于为什么要用mysql,可能是前期数据量不是太大,MySQL完全可以胜任。不过在我来西安之前已经准备用hive+mysql+Hbase了。
数据量大小:目前接入平台已经超过40家了,以中等规模计算,一家平台半年流水数据达到2000万条,也就是一张表大概4000万数据的样子。
数据如何存储:1、按平台分库存储 2、每个平台按时间分表存储(年、月)
索引如何:我们都知道查询速度取决于索引是否合理,优化前索引很不合理,几乎没有用到索引。
分析统计方式:MySQL存储过程+视图
分析统计时间:每天早上九点(避免与其他统计分析冲突)
二、开始优化
1、 避免出现 大小写不统一的情况
错误的写法:
SELECT id From t where name = 'zhangsan';
复制
正确的写法:
SELECT id FROM t WHERE name = 'zhangsan';
复制
在我们看来没有区别,只是大小写不一样而已,但mysql认为是两个不同的SQL,要进行解析,生成两个不同的执行计划。
因此,必须要使相同的查询语句保持一致,一个空格也不能多。
2、 根据字段类型,调整相应的查询条件;
比如 age 类型为 int, 那么
错误的写法:
# 这是字符串的写法,虽然也能查询出数据,但查询效率很低。
SELECT name FROM t WHERE age = '18';复制
正确的写法:
SELECT name FROM t WHERE age = 18;
复制
3、 避免出现对字段进行NULL的判断,这个会使MySQL放弃索引进行全表扫描。
错误的写法:
SELECT id FROM t WHERE name IS NULL;
复制
这里需要注意的是,在数据库设计的时候要注意不要给数据库留NULL, 尽量使用NOT NULL 进行填充,比如: varchar用""填充。
ps:我就没那么幸运了,全部的varchar都是用NULL填充,很受伤。
4、 不要使用 SELECT * FROM 查询,应使用具体的字段查询,尽量不要返回无用的字段。
5、 WHERE 语句优化:
单独把WHERE 条件放在一起;
5.1、相同场景的WHERE条件应该相同,例如:
SELECT id From t where name = 'zhangsan' AND age = 18;
SELECT id From t where age = 19 AND name = 'zhangsan';复制
虽然查询结果一样,但肯定会造成索引用不到的情况。
5.2、尽量不要在查询中用到OR, 如果一个字段有索引,另一个没有,就会造成全表扫描的。
SELECT id FROM t WHERE num=10 OR name = 'zhangsan';
复制
可以这样写:
SELECT id FROM t WHERE num = 10
UNION ALL
SELECT id FROM t WHERE name = 'zhangsan';复制
5.3、尽量不要在WHERE语句中用 != ,<>, 会导致全表扫描
5.4、IN 和 NOT IN 也要注意,否则会导致全表扫描,可以用 EXISTS 代替 IN(当然,前表小于后表时用):这条以后会做一个专题。
SELECT num FROM a WHERWE EXISTS(SELECT 1 FROM b WHERE num=a.num);
复制
5.5、避免在WHERE子句中对字段进行操作,包括表达式,函数等。
错误的写法:
SELECT id FROM t WHERE num/2 = 100;
复制
正确的写法:
SELECT id FROM t WHERE num = 100*2;
复制
6、 避免使用很复杂的SQL, 如果太复杂,查询会变慢,并且过几天你看不懂,别人也看不懂。越简单的SQL被重用的可能性越高。复杂的SQL只要一个字符发生变化,mysql就会重新去解析。
一般我的查询嵌套不会超过两层。
解决办法:临时表 暂存中间结果
优点:
1、简化SQL
2、暂存临时结果,二次利用,避免多次扫描主表,减少锁,减少阻 塞,提高了并发性能。
缺点: 慎重使用临时表可以极大的提高系统性能(网上说的),这个目前 没有意识到,以后优化的时候可以考虑。
目前我的查询语句中用到了大量的临时表,临时表存储在内存中,查询效率大大提高。
临时表显式删除,先 TERUNCATE table ,然后 DROP table ,这样可以避免系统表的较长时间锁定,释放内存,减少系统开销。
7、对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。
8、进行大量INSERT操作时,先禁用索引,待插入完成后在打开,避免插入的时候进行索引排序。
禁用索引:
ALTER TABLE t DISABLE KEYS;
复制
重新打开:
ALTER TABLE t ENABLE KEYS;
复制
三、索引创建(以后做一个索引的专题)
1、尽量使用联合索引,在常用的字段以及可辨识大的字段上创建索引
2、与WHERE,GROUP BY,ORDER BY 等解合,按顺序创建索引,这就需要相同场景的WHERE条件应该相同,因为聚合索引时最左前缀原则,只有WHERE子句顺序相同的时候才能用到。
3、不要在每个列上创建索引,索引不要超过五个。
4、不要在建立的索引的数据列上进行下列操作:
避免对索引字段进行计算操作
避免在索引字段上使用not,<>,!=
避免在索引列上使用IS NULL和IS NOT NULL
避免在索引列上出现数据类型转换
避免在索引字段上使用函数
避免建立索引的列中使用空值。
5、索引的建立要经过严格的评估。
四、高级篇:用了视图也可以使用索引
网上大量的文章讲视图不能用到索引,但由于我分表的业务场景,必须要用到视图,绕不过去就考虑视图也利用索引。
视图的建立:避免使用全部建立视图,应根据业务场景,配合表的索引,创建视图。不关心视图用不用到索引,只要我们创建视图的查询语句能用到索引,就可以了。
这样视图就可以用到索引了,亲测有效。
五、SQL优化查询工具
可以查看SQl执行计划:EXPLAIN
结束了;以后会做相应的专题。