标签:ref 分享 eid sele 速度 tle 公司 orm 设计
公司订单系统每日订单量庞大,有很多表数据超千万。公司SQL优化这块做的很不好,可以说是没有做,所以导致查询很慢。
节选某个功能中的一句SQL EXPLAIN查看执行计划,EXPLAIN + SQL 查看SQL执行计划
一个索引没用到,受影响行接近2000万,难怪会慢。
原来的SQL打印出来估计有好几张A4纸,我发个整理后的简版。
SELECT
COUNT(t.w_order_id) lineCount,
SUM(ROUND(t.feel_total_money / 100, 2)) AS lineTotalFee,
SUM(ROUND(t.feel_fact_money / 100, 2)) AS lineFactFee
FROM
w_orders_his t
WHERE 1=1
AND DATE_FORMAT(t.create_time, ‘%Y-%m-%d‘) >= STR_TO_DATE(#{beginTime},‘%Y-%m-%d‘)
AND DATE_FORMAT(t.create_time, ‘%Y-%m-%d‘) <= STR_TO_DATE(#{endTime},‘%Y-%m-%d‘)
AND t.pay_state = #{payState}
AND t.store_id LIKE ‘%#{storeId}%‘
limit 0,10
这条sql需求是在两千万的表中捞出指定时间和条件的订单进行总数总金额汇总处理。
优化sql需要根据公司的业务,技术的架构等,且针对不同业务每条SQL的优化都是有差异的。
AND DATE_FORMAT(t.create_time, ‘%Y-%m-%d‘) >= STR_TO_DATE(#{beginTime},‘%Y-%m-%d‘)
AND DATE_FORMAT(t.create_time, ‘%Y-%m-%d‘) <= STR_TO_DATE(#{endTime},‘%Y-%m-%d‘)
我们知道sql中绝对要减少函数的使用,像左边DATE_FORMAT(t.create_time, ‘%Y-%m-%d‘) 是绝对禁止使用的,如果数据库有一百万数据那么就会执行一百万次函数,非常非常影响效率。右边STR_TO_DATE(#{beginTime},‘%Y-%m-%d‘)的函数会执行一次,但还是不建议使用函数。所以去掉函数直接使用 >=,<= 或BETWEEN AND速度就会快很多,但有的数据库设计时间字段只有日期没有时间,所以需要在日期后面拼接时间如:"2017-01-01" + " 00:00:00"。
更好的办法是用时间戳,数据库中存时间戳,然后拿时间戳去比较,如:BETWEEN ‘开始时间时间戳‘ AND ‘结束时间时间戳‘
AND t.store_id LIKE ‘%#{storeId}%‘
这句使用了LIKE并且前后匹配,前后匹配会导致索引失效,一般情况下避免使用,应该改成 AND t.store_id LIKE ‘#{storeId}%‘
一般利用好索引,根据主键、唯一索引查询某一条记录,就算上亿数据查询也是非常快的。但这条sql需要查询数据统计需要用到COUNT和SUM,所以可以建立联合索引。
联合索引有一点需要注意:key index (a,b,c)可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 ,当最左侧字段是常量引用时,索引就十分有效。
所以把必要字段排放在左边key index(create_time,w_order_id,feel_total_money,feel_fact_money,payState,storeId)
结果
优化之前大概几分钟,现在是毫秒级。其实改的东西也不多,避免在语句上踩雷,善用EXPLAIN查询SQL效率。
有时间我会举点别的SQL优化的例子
说几点平常可以优化的地方
参考
EXPLAIN type(从上到下,性能从差到好)
MYSQL 五大引擎
一般需要事物的设为InnoDB,其他设为MyISAM
标签:ref 分享 eid sele 速度 tle 公司 orm 设计
原文地址:https://www.cnblogs.com/zyiii/p/8821421.html