记录一些慢sql优化技巧
- 在很大的数据量中获取是否有过n次xx行为。
假设有一个很大的订单表order, 我们想知道一个用户是否有进行过5次充值。- 有用户id的索引
正常可以写
一般来说,由于有用户id的索引,这个查询的性能不会很低。当有某一个用户有很多个订单时,这个查询就会变慢,比如id为2的用户有10000+订单,那么status=xxxx的这个条件就要对比10000+次。select count(1) from `order` where uid = xxxxx and status = xxxx
优化写法
这样写的话我们只需要指定n的大小就可以知道用户是否有进行过n次充值。当用户订单数量很大时也是最多只进行n次条件判断即可。select 1 from `order` where uid = xxxxx and status = xxxx limit 1 offset n
- 有用户id的索引
- 获取一定时序条件下的某些数据
假设现在需要知道一个用户在最近5天的订单- 有用户索引
- 没有时间索引
正常可以写
由于没有时间索引,这个sql只会用到用户id的索引。select xxx from `order` where uid = xxxxx and order_time = xxxx and status = xxx
一般来说,如果是对于订单生成时间之类的的数据,应该给时间加上索引,因为这个字段比较重要,会经常查询
但是有可能我们要查的是用户订单异常的时间,退款的时间,一些不经常查的数据,这个字段上没有索引,想要加索引这个表又比较大,性价比很低。这里仅仅只讨论时间没有索引的情况
由于我们限制的时间是时序的,要查询的是近5天的数据,那么我们可以简单的对历史数据统计一下。
可以按月或者按半年来分,由此来改造上述sql# id是order表的主键 订单生成时间是xxxxxxx时, id = xxxx 订单生成时间是xxxxxxx时, id = xxxx ··· ···
此处的id取从上面分析的最合适的一个id,这样索引的使用就从用户id索引变成了用户id索引和主键索引的index_merge状态,当这个用户有很多订单时可以少扫描很多行。select xxx from `order` where uid = xxxx and order_time = xxxx and status = xxx and id > xxx