MySQL:左JOIN和orderby的组合很慢
有两个表:MySQL:左JOIN和orderby的组合很慢,mysql,join,left-join,query-performance,Mysql,Join,Left Join,Query Performance,有两个表:posts(~5000000行)和关系(~8000行) 帖子栏目: ------------------------------------------------- | id | source_id | content | date (int) | ------------------------------------------------- --------------------------- | source_id | user_id | ----
posts
(~5000000行)和关系(~8000行)
帖子
栏目:
-------------------------------------------------
| id | source_id | content | date (int) |
-------------------------------------------------
---------------------------
| source_id | user_id |
---------------------------
关系
列:
-------------------------------------------------
| id | source_id | content | date (int) |
-------------------------------------------------
---------------------------
| source_id | user_id |
---------------------------
我编写了一个MySQL查询,用于从帖子
中获取与特定用户相关的10个最新行:
SELECT p.id, p.content
FROM posts AS p
LEFT JOIN relations AS r
ON r.source_id = p.source_id
WHERE r.user_id = 1
ORDER BY p.date DESC
LIMIT 10
但是,执行它需要约30秒
我已经在关系中为(source\u id,user\u id)
,(user\u id)
和(source\u id)
,(date)
,(date,source\u id)
设置了索引
解释
结果:
如何优化查询?试试这个
SELECT p.id, p.content FROM posts AS p
WHERE p.source_id IN (SELECT source_id FROM relations WHERE user_id = 1)
ORDER BY p.date DESC
LIMIT 10
您可以在posts表的date列上添加索引,我相信这将有助于加快订单的速度
在使用一些额外的where语句进行排序之前,您还可以尝试减少结果的数量。例如,如果你知道有可能有十个记录与正确的用户ID今天,你可以限制日期,直到今天(或N天回来取决于你的实际数据)。< / P> < P>我会考虑以下:-< /P>
首先,您只需要与用户相关的文章中最近的10行。因此,内部联接
应该很好
SELECT p.id, p.content
FROM posts AS p
JOIN relations AS r
ON r.source_id = p.source_id
WHERE r.user_id = 1
ORDER BY p.date DESC
LIMIT 10
如果要获取不具有关系
映射的记录,则需要左连接。因此,执行LEFT JOIN
会导致对左表进行完整的表扫描,根据您的信息,左表包含约5000000行。这可能是您查询的根本原因
为进一步优化,考虑将<<代码> 子句移动到<<代码> < /Cord>子句> < /P>
SELECT p.id, p.content
FROM posts AS p
JOIN relations AS r
ON (r.source_id = p.source_id AND r.user_id = 1)
ORDER BY p.date DESC
LIMIT 10
WHERE子句将外部联接呈现为仅内部联接(因为在外部联接的伪记录中,user_id将始终为null,而不是1)
如果您真的希望这是一个外部连接,那么它是完全多余的,因为posts
中的每个记录在关系中都有或没有匹配项。你的问题将是
select id, content
from posts
order by "date" desc limit 10;
如果您不希望这是一个真正的外部联接,而是希望在关系中匹配
,那么我们讨论的是表中的存在,存在
或在
子句中,因此:
select id, content
from posts
where source_id in
(
select source_id
from relations
where user_id = 1
)
order by "date" desc
limit 10;
在关系(user\u id,source\u id)
上应该有一个索引,按照这个顺序,我们可以先选择user\u id
1,然后得到所有所需source\u id
的数组,然后再进行查找
当然,你还需要一个关于posts(source\u id)
的索引,因为source\u id
是一个id。你甚至可以通过一个复合索引posts(source\u id,date,id,content)
来加快速度,这样就不必再读取表本身了——所有需要的信息都已经在索引中了
更新:以下是相关的存在查询:
select id, content
from posts p
where exists
(
select *
from relations r
where r.user_id = 1
and r.source_id = p.source_id
)
order by "date" desc
limit 10;
我会尝试使用关系综合指数:
INDEX source_user (user_id,source_id)
并将查询更改为:
SELECT p.id, p.content
FROM posts AS p
INNER JOIN relations AS r
ON ( r.user_id = 1 AND r.source_id = p.source_id )
ORDER BY p.date DESC
LIMIT 10
执行它需要更长的时间(60秒)。子查询总是比join慢。我认为它很慢,因为它可能包含重复的行。无论如何。。感谢您将其呈现为内部连接!尝试将WHERE替换为AND。请发布“解释选择…”的结果再仔细考虑一下,您可能需要在r.user_id上单独添加一个索引,并从关系和左连接中选择posts@JanPapenbrock将WHERE替换为,并返回与用户无关的结果。已将解释结果添加到帖子中。抱歉,忘了提及–在posts
中已有date
索引。我明白你的意思,但是,没有什么可以限制它——日期可以是任意的。作者提到,在筛选(user\u id)和排序(date)列上同时使用多列索引可能会产生比单独使用多列索引更好的结果。您可能考虑了source\u id
,而不是user\u id
,因为它位于另一个表中。我为(source\u id,date)
添加了一个索引,但是性能仍然很差。哎呀!这是在深夜使用堆栈溢出时发生的情况。我还以为他们在同一张桌子上呢。这给了我一个想法:如果user_id和source_id是1对1的关系,那么您可以修改您的模式,将user_id与source_id切换。或者,您可以对这两个表进行非规范化(请参阅)。我认为这取决于您多么希望这个查询运行得更快。希望这有帮助!我尝试了你的两个建议,但是,仍然是30秒的死刑。哇。。这太令人惊讶了。我对综合指数有点不确定。我曾经因为综合指数而表现不佳。因此,我会盲目地尝试删除关系处的(source\u id,user\u id)
和帖子处的(date,source\u id)
的复合索引。我还尝试了不同的索引变体,但这些都没有任何效果。可能我脑海中唯一想到的是,如果你的查询像“批处理”一样,每30秒执行一次?你能看到explain
计划是否有任何改进吗?explain
对于你的查询是完全相同的。没有批量的东西,因为如果我取消订单,它就像闪电一样快。这个问题在某种程度上是错误的。谢谢你,但是我以前有过这样的回答:-对性能没有影响。哦,我没有看到这个。那么您确实有提到的索引,但查询仍然很慢?我认为这是MySQL中的一大缺陷。你用的是旧版本吗?我将添加相关的EXISTS
查询,可能MySQL在中遇到了问题。是的,我尝试了您建议的索引。与存在的相同
。MySQL版本–最新版本,SSD服务器。我尝试通过删除orderby