我有两个表,每个表包含6M行。我尝试使用内部联接加入这两个,但查询运行了2天而没有完成。加入是(注意我使用count(*)
只是为了让我能够运行解释,我实际上在CTAS中使用join
):
SELECT count(*)
FROM table1 t1,
table2 t2
WHERE t1.col1 = t2.colA
AND t1.col2 = t2.colB;
经过一番调查后,我发现以下查询运行良好:
SELECT count(*)
FROM
(SELECT *
FROM table1) t1,
(SELECT *
FROM table2) t2
WHERE t1.col1 = t2.colA
AND t1.col2 = t2.colB;
除了表之间的唯一区别,我使用子查询SELECT * FROM table
;
运行解释计划表明后一个查询在选择table2时正在构建索引。而第一个查询使用连接缓冲区(块嵌套循环)。
当然MySQL非常聪明,可以确定这两个查询实际上是相同的,并且对两个查询都一样吗?我不明白为什么需要索引,因为无论如何都需要对两个表进行全面扫描。这些是临时/暂时表,所以如果我确实放了一个索引,它实际上就是执行这个连接。
有没有办法通过MySQL配置解决这个问题?
答案 0 :(得分:1)
你需要至少有一个表的索引,甚至是
create index Temp1 on Table2 ( colA, colB )
因此,表1中的查询加入到表2中,因此即使表1中的表扫描都在表1中,您也需要它来快速查找表2中匹配的记录。如果NEITHER有索引,然后这样想。对于Table1中的每条记录,扫描表2中的所有记录并获取与ColA,ColB匹配的所有记录。现在,返回表1中的SECOND记录...返回表2中的所有记录,直到找到匹配为止。
由于你有6M的记录,你几乎可以在性能上扼杀一头牛(可以这么说)。通过索引,即使在SECOND表上,当查询在第一个记录上时,它可以立即跳转到与ColA,ColB匹配的行,并且一旦完成这些A / B记录,它就会返回到第一个表
现在,其他开销效率。如果您在各自的Col1,Col2和ColA,ColB上都有索引的BOTH表,那么引擎将在其内存/缓存中为每个公共区域提供整个记录块,而不必继续返回原始数据页其他元素反复出现。
因此,即使您认为它可能不实用,处理大型表查询仍然很好。此外,如果第一个表中的多个记录具有相同的Col1,Col2值,但是对于表中的其他列具有不同的其他值,并且类似地在多个ColA,ColB的第二个表中,您将获得笛卡尔结果。请考虑以下情况
Table1
Col1 Col2 OtherColumn
X Y blah1
X Y blah2
X Y blah3
Table2
ColA ColB OtherColumn
X Y second blah1
X Y second blah2
X Y second blah3
像你这样的简单查询
SELECT count(*)
FROM table1 t1,
table2 t2
WHERE t1.col1 = t2.colA
AND t1.col2 = t2.colB;
将导致计数为9.您有6M记录和可能的笛卡尔结果?希望这能澄清您可能遇到的一些问题。