子选择使复杂的查询真的很慢
Posted
技术标签:
【中文标题】子选择使复杂的查询真的很慢【英文标题】:subselect makes complex query really slow 【发布时间】:2013-06-03 21:22:12 【问题描述】:所以我想为一个项目做以下事情。
我有 3 张桌子。前两个现在关心我们(第三个是为了更好地理解):
author id, name
authorship id, id1, id2
paper id, title
authorship 将作者与论文联系起来,authorship.id1 指的是 author.id,authorship.id2 指的是 paper.id。
我想做的是制作一个图,其中每个作者都有一个节点,边由两个作者之间的共同论文数量决定。
w=1 - union_of_common_papers/intersection_of_common_papers
所以我已经构建了(在 *** 的帮助下)一个 sql 脚本,它返回所有共同作者的夫妇以及普通论文的并集和交集的数量。之后,我将使用 java 中的数据。如下:
SELECT DISTINCT a1.name, a2.name, (
SELECT concat(count(a.id2), ',', count(DISTINCT a.id2))
FROM authorship a
WHERE a.id1=a1.id or a.id1=a2.id) as weight
FROM authorship au1
INNER JOIN authorship au2 ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1
INNER JOIN author a1 ON au1.id1 = a1.id
INNER JOIN author a2 ON au2.id1 = a2.id;
这完成了我的工作并返回如下列表:
+-----------------+---------------------+---------+
| name | name | weight |
+-----------------+---------------------+---------+
| Kurt | Michael | 161,157 |
| Kurt | Miron | 138,134 |
| Kurt | Manish | 19,18 |
| Roy | Gregory | 21,20 |
| Roy | Richard | 74,71 |
....
我可以看到 2 个数字 a,b 其中 b 是交集 b-a 是普通论文的并集。
但这需要很多时间。 所有的开销都来自这个额外的子选择
(SELECT concat(count(a.id2), ',', count(DISTINCT a.id2))
FROM authorship a
WHERE a.id1=a1.id or a.id1=a2.id) as weight
如果没有此行,所有记录 (1M+) 都会在不到 2 分钟的时间内返回。 这行 50 条记录需要超过 1.5 分钟
我通过命令行在linux上使用mysql
有什么想法可以优化它吗?
作者拥有约 130,000 条记录 作者身份 ~1,300,000 条记录 查询应返回约 1,200,000 条记录这是explain为此查询返回的内容。不知道怎么用。
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+
| 1 | PRIMARY | a1 | ALL | PRIMARY | NULL | NULL | NULL | 124768 | Using temporary |
| 1 | PRIMARY | au1 | ref | NewIndex1,NewIndex2 | NewIndex1 | 5 | dblp.a1.ID | 4 | Using where |
| 1 | PRIMARY | au2 | ref | NewIndex1,NewIndex2 | NewIndex2 | 5 | dblp.au1.id2 | 1 | Using where |
| 1 | PRIMARY | a2 | eq_ref | PRIMARY | PRIMARY | 4 | dblp.au2.id1 | 1 | |
| 2 | DEPENDENT SUBQUERY | a | ALL | NewIndex1 | NULL | NULL | NULL | 1268557 | Using where |
+----+--------------------+-------+--------+---------------------+-----------+---------+--------------+---------+-----------------+
【问题讨论】:
【参考方案1】:您应该能够直接从外部查询中的联接中获取数据。
您可以通过计算不同的id2
来计算共同论文的数量,这对于两位作者来说都是相同的。
您可以将论文总数计算为每个作者的不同论文数减去共同论文数(否则,这些将被计算两次):
SELECT a1.name, a2.name,
COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as CommonPapers,
COUNT(distinct au1.id2) + COUNT(distinct au2.id2) - COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as TotalPapers
FROM authorship au1 INNER JOIN
authorship au2
ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 INNER JOIN
author a1
ON au1.id1 = a1.id INNER JOIN
author a2
ON au2.id1 = a2.id
group by a1.name, a2.name;
在您的数据结构中,id1
和 id2
是糟糕的名称。你考虑过idauthor
和idpaper
之类的东西吗?
上面的查询正确地计算了交集,但不是总数,因为初始的内部连接。解决这个问题的一种方法是full outer join
,但这在 MySQL 中是不允许的。我们可以通过额外的子查询来做到这一点:
SELECT a1.name, a2.name,
COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end) as CommonPapers,
(ap1.NumPapers + ap2.NumPapers - COUNT(distinct case when au1.id2 = au2.id2 then au1.id2 end)
) as TotalPapers
FROM authorship au1 INNER JOIN
authorship au2
ON au1.id2 = au2.id2 AND au1.id1 <> au2.id1 INNER JOIN
author a1
ON au1.id1 = a1.id INNER JOIN
author a2
ON au2.id1 = a2.id inner join
(select au.id1, count(*) as numpapers
from authorship au
) ap1
on ap1.id1 = au1.id1 inner join
(select au.id1, count(*) as numpapers
from authorship au
) ap2
on ap2.id1 = au2.id1 inner join
group by a1.name, a2.name;
【讨论】:
您对 ids 名称是完全正确的。我现在正在检查您的建议。 不,它真的不起作用。似乎永远在奔跑。我已将限制设置为 5。 您在author(id)
和authorship(id2, id1)
上有索引吗?他们可能会有所帮助。你确实有很多行数据。如果其中一篇论文有 1000 位作者,那么数据真的会成倍增加。
带有完全连接解决方法的第二个建议返回空集。
感谢第一个运行非常短的时间 ~ 5 分钟。我不能使用 distinct 并且必须分组,这让我很困扰。至于常见的 COUNT(distinct au1.id2) 与 COUNT(distinct au2.id2) 相同,与普通论文总数相同。再次非常感谢,剩下的我会自己解决。以上是关于子选择使复杂的查询真的很慢的主要内容,如果未能解决你的问题,请参考以下文章
什么可能导致 Tkinter/Python 中打开的文件对话框窗口在用户选择文件后关闭速度真的很慢?
时序数据库新手,从TimescaleDB for Grafana中选择数据速度慢,查询复杂