这个问题对我来说有点复杂,我无法用一句话来解释它,因此标题似乎很含糊。
我的MySQL数据库中有3个表,其结构如下所示:
+-----+--------+ | wid | word | +-----+--------+ | 1 | foo | | 2 | bar | | 3 | hello | +-----+--------+
+-----+-------+ | pid | word | +-----+-------+ | 1 | 1 | | 1 | 2 | | 1 | 3 | | 2 | 1 | | 2 | 3 | +-----+-------+
+----------+--------+ | pid_from | pid_to | +----------+--------+ | 1 | 2 | | 1 | 3 | | 1 | 4 | | 2 | 1 | | 2 | 3 | +----------+--------+
我想找出多少论文包含单词W,并列举论文也包含单词W(对于列表中的每个单词)
我使用两个内部联接来完成这项工作,但是当单词流行时-50s以上似乎非常慢(如果单词很少使用则非常快-0.1s以下),这是我的代码
SELECT COUNT(*) FROM ( SELECT a.pid_from, a.pid_to, b.word FROM paper_citation_relation AS a INNER JOIN paper_word_relation AS b ON a.pid_from = b.pid INNER JOIN paper_word_relation AS c ON a.pid_to = c.pid WHERE b.word = 2 AND c.word = 2) AS d
如何更快地执行此操作?我的查询效率不够吗?还是有关数据量的问题?
我只能提出一种解决方案,即删除paper_word_relation
表中少于2个单词。 (大约400万个单词仅出现一次)
谢谢!
答案 0 :(得分:1)
如果仅考虑获取计数,则不应该首先将结果获取到派生表中,然后将行计数出去。这个可以创建不必要的临时表,以在内存中存储大量数据。您可以直接计算行数。
我还认为您需要计算唯一数量的论文。由于paper_citation_relation
表中的多对多关系,单张纸可能会出现重复的行 。
SELECT COUNT(DISTINCT a.pid_from)
FROM paper_citation_relation AS a
INNER JOIN paper_word_relation AS b ON a.pid_from = b.pid
INNER JOIN paper_word_relation AS c ON a.pid_to = c.pid
WHERE b.word = 2 AND c.word = 2
为了提高性能,您将需要进行以下索引编制:
(pid_from, pid_to)
表中paper_citation_relation
上的综合索引。(pid, word)
表中paper_word_relation
上的综合索引。 我们可能还可能通过减少一个联接并在 AND/OR
中使用基于条件HAVING
的过滤来进一步优化查询。不过,您将需要对其进行基准测试。
SELECT COUNT(*)
FROM (
SELECT a.pid_from
FROM paper_citation_relation AS a
INNER JOIN paper_word_relation AS b
ON (a.pid_from = b.pid OR
a.pid_to = b.pid)
GROUP BY a.pid_from
HAVING SUM(a.pid_from = b.pid AND b.word = 2) AND
SUM(a.pid_to = b.pid AND b.word = 2)
)
答案 1 :(得分:0)
在第一个1:n
联接之后,您将多次获得相同的pid_to
,而下一个联接不再是1:n
而是n:m
,从而在联接之前创建了可能巨大的中间结果最后DISTINCT
。它与CROSS JOIN类似,但流行词(例如10 * 10与1000 * 1000行。
您必须在加入之前删除重复项,这应该返回与@MadhurBhaiya的答案相同的数字
SELECT Count(*) -- no more DISTINCT needed
FROM
(
SELECT DISTINCT cr.pid_to -- reducing m to 1
FROM paper_citation_relation AS cr
JOIN paper_word_relation AS wr
ON cr.pid_from = wr.pid
WHERE wr.word = 2
) AS dt
JOIN paper_word_relation AS wr
ON dt.pid_to = wr.pid -- 1:n join again
WHERE wr.word = 2
如果要计算被引用的论文数,则需要首先从pid
获得pid_from
(pid_to
或paper_citation_relation
)的不同列表然后加入特定的单词。
SELECT Count(*)
FROM
( -- get a unique list of cited or citing papers
SELECT pid_from AS pid -- citing
FROM paper_citation_relation
UNION -- DISTINCT by default
SELECT pid_to -- cited
FROM paper_citation_relation
) AS dt
JOIN paper_word_relation AS wr
ON wr.pid = dt.pid
WHERE wr.word = 2 -- now check for the searched word
由此返回的数字可能会稍高(无论引用还是引用,它都计入论文)。