记录一次MySQL SQL语句优化

今天有一个客户说,他拉取流水记录总是超时。

我打开数据库一看,流水记录表有900万数据。为了方便描述问题,我们假设这张表的名字叫 t_flow。

其实拉取记录的语句很简单。

SELECT * FROM `t_flow` WHERE `time` > timestamp AND `userid`=my_userid OR `uuid`=my_userid ORDER BY `time` DESC LIMIT 0,10;

在900万条数据的情况下,执行这条语句花了7秒多。这张表的各个列的索引都已建立

我一眼看到了`userid`=my_userid OR `uuid`=my_userid这个地方。 这是项目里面为了方便,同事设计的,不管my_userid是UUID还是真的userid都可以用同一个函数。好在我们的userid是6位,而uuid是10多位。所以我做了一个优化。 先判断my_userid是uuid还是userid,这样少了一个OR。 时间缩短到了5秒多。

伪代码如下

if(my_userid.length == 6){
    SELECT * FROM `t_flow` WHERE `time` > timestamp AND `userid`=my_userid ORDER BY `time` DESC LIMIT 0,10;
}
else{
    SELECT * FROM `t_flow` WHERE `time` > timestamp AND `uuid`=my_userid ORDER BY `time` DESC LIMIT 0,10;
}

但是5秒多也不行啊。才这么点数据。于是我去掉了LIMIT,发现,去掉LIMIT后,执行就只需要2秒多了。

百思不得其解。我于在网上搜索了许久的关于SQL语句中添加了LIMIT反而更慢的问题,仍未找到答案。

由于有900多万条,而我用的是SELECT *,我怀疑是这里有问题,导致WHERE语句在查找的时候,消耗了太多内存。

于是我做了一个新版本。

SELECT * FROM `t_flow` WHERE `uuid` IN( SELECT `uuid` FROM `t_flow` WHERE `time` > timestamp AND `userid`=my_userid OR `uuid`=my_userid) ORDER BY `time` DESC LIMIT 0,10;

先查找出uuid,再直接获取uuid的内容。这样有一个好处就是,在进行 time > timestamp筛选的时候,只拿出了uuid,减少了内存开销。 

因为我们的MYSQL服务器的内存有限,如果大量的内存开销就会触发内存页面置换,从而导致花更多的时间。

最后本条语句执行只花了400ms,由于只是一个数据统计功能,所以免强算达标。

发布了230 篇原创文章 · 获赞 542 · 访问量 118万+

猜你喜欢

转载自blog.csdn.net/qq_36720848/article/details/103635231