mysql一些查询性能问题的记录

蜀山剑神

一个600多万条记录的大表,两条几乎相同的查询语句,仅排序有区别:


sql> SELECT *

FROM t_admin_log

WHERE imei = '3f073c2150aa4bfd'

ORDER BY id

LIMIT 100

[2019-10-09 15:48:51] 100 rows retrieved starting from 1 in 3s 104ms (execution: 3s 62ms, fetching: 42ms)

sql> SELECT *

FROM t_admin_log

WHERE imei = '3f073c2150aa4bfd'

ORDER BY id DESC

LIMIT 100

[2019-10-09 15:49:00] 100 rows retrieved starting from 1 in 370ms (execution: 95ms, fetching: 275ms)

数据位于表的靠后位置。

可以看到,倒序比正序的速度快很多,原因应该是需要扫描的数据量比较少吧。


另一个例子:


sql> SELECT *

FROM t_admin_log

WHERE imei = '3f073c2150aa4bfd'

ORDER BY id DESC

LIMIT 10

[2019-10-09 15:54:23] 10 rows retrieved starting from 1 in 143ms (execution: 119ms, fetching: 24ms)

sql> SELECT *

FROM t_admin_log

WHERE imei = '3f073c2150a6a4bfd'

ORDER BY id DESC

LIMIT 10

[2019-10-09 15:54:36] 0 rows retrieved in 3s 963ms (execution: 3s 946ms, fetching: 17ms)

两个查询语句只有imei有区别,前一个是存在的,后一个是不存在的,查询结果也相差好多。推测是imei存在时,由于limit 10,只要找到10条就返回了;如果不存在,就会从后向前一直找,直到表的开头才发现原来没有这项数据,所以花费的时间就很长。


所以,查询性能并不只和数据量有关,还和数据的分布有关。假如某个日志表有一亿条数据,但是都是id自增的,时间为插入的时间。那么查询最近的数据是非常快的。而如果不幸表里没有符合查询条件的数据,那么查起来就比较慢了。

那么,我觉得有一个思路,对单个大表,假如是有序的,那么每隔一定距离就添加一个标记,比如日志表按天为标记,记录下对应的日志id和日期,存入单独的表。后续查询时,假如我们知道起始日期,那么就可以根据日期查找标记表中的id,在以id为限定范围进行查询,这样速度就很快了。比如一个大型应用的日志记录,某用户注册日期是2019年10月1日,标记表中2019年10月1日对应的id是50000000,那么对所以该用户的查询都可以加上限定条件:where id>50000000,这样就避免了limit的最后一页对后续的5千万条数据进行扫描。


当然综合来看,如果能分表,查询性能肯定更好些,但是结构上也会变复杂了。

主 楼 发布于:2019-10-09 16:19:49回复
傻傻式想你68

嗨!收到我的短信没有?还发什么呆,笑一下,好吗?你笑起来很好看。

2 楼 发布于:2019-10-21 10:01:18
回复
身影归去

在这迷人的季节里,心情难以平复,总挂念着远方的你!我愿养一只白鸽,让它每天飞到你的上空,哪怕能做的只是简简单单一个动作……在你头上拉一堆屎

3 楼 发布于:2022-03-21 19:55:01
回复
神歆518

涨姿势了

4 楼 发布于:2022-09-18 06:36:21
回复
沉默的街角

长得帅的才有青春,像我们这样的只有大学了

5 楼 发布于:2022-12-29 09:56:21
回复
艾丝帆

我轻轻地来的,正如我轻轻地走,挥一挥匕首,不留下一个活口

6 楼 发布于:2024-06-26 03:43:01
回复

发表回复: