Mysql 在联接之前对两个表执行SELECT

Mysql 在联接之前对两个表执行SELECT,mysql,select,join,inner-join,Mysql,Select,Join,Inner Join,我没有太多使用JOIN的经验,也不是MySQL方面的专家 我要做的是在执行联接之前对两个表进行选择。为此,我尝试使用括号,但语法不正确 例如,在不执行“在联接之前选择”的情况下: DELETE tbA.* FROM tbA INNER JOIN tbB ON tbA.id_tbB = tbB.id_tbB WHERE tbB.dateCol<'2014-01-01 00:00:00' 这是可行的,但需要花费太多的时间。我试图做的事情,但没有成功,是这样的: DELETE tbA.* FR

我没有太多使用JOIN的经验,也不是MySQL方面的专家

我要做的是在执行联接之前对两个表进行选择。为此,我尝试使用括号,但语法不正确

例如,在不执行“在联接之前选择”的情况下:

DELETE tbA.* FROM tbA
INNER JOIN tbB
ON tbA.id_tbB = tbB.id_tbB
WHERE tbB.dateCol<'2014-01-01 00:00:00'
这是可行的,但需要花费太多的时间。我试图做的事情,但没有成功,是这样的:

DELETE tbA.* FROM (SELECT * FROM tbA WHERE tbA.id_tbB<=id_max)
INNER JOIN (SELECT * FROM tbB WHERE tbB.id_tbB<=id_max)
ON tbA.id_tbB = tbB.id_tbB
WHERE tbB.date<'2014-01-01 00:00:00'
SELECT tbA_filter.* FROM (SELECT tbA.* FROM tbA WHERE tbA.id_tbB<=id_max) AS tbA_filter 
INNER JOIN (SELECT * FROM tbB WHERE tbB.id_tbB<=id_max AND tbB.date<'2014-01-01 00:00:00') AS tbB_filter
ON tbA_filter.id_tbB = tbB_filter.id_tbB
WHERE tbA_filter.id_tbB<=id_max
我试图把它综合到基本问题上。。。如果有人认为我应该提供更多信息,我想做什么,索引,外键,。。。我很乐意这样做,但基本上我只想知道如何在内部联接之前对两个表进行选择

我想这样做是因为我的表有大量的记录表A~1亿,表B~40000。在这两个表上执行select将把记录数量减少到10%,并有望显著减少内部连接,从而减少整个查询

有人能指出错误吗?谢谢

怎么样

DELETE FROM tbA WHERE (select tbB.date from tbB where tbA.id_tbB = tbB.id_tbB) > '2014-01-01 00:00:00'
或者另一个

DELETE FROM tbA WHERE tbA.id_tdB IN (
     select tbB.id_tbB from tbB where tbB.date > '2014-01-01 00:00:00'
)

如果您在tbA中的id_tdB上有索引或外键,我假设最后一个是最快的。

您所做的应该是有效的,您只是缺少一些重要的语法元素。您可以在SELECT上进行联接,这是一个称为派生表的虚拟表。您必须命名派生表,以便引用它。无法从派生表中删除,因为它是虚拟表,它只存在于内存中。因此,您需要在选择中放置一个物理表

试着这样做:

DELETE tbA FROM tbA 
INNER JOIN (SELECT * FROM tbB WHERE tbB.id_tbB<=id_max AND tbB.date<'2014-01-01 00:00:00') AS tbB_filter
ON tbA.id_tbB = tbB_filter.id_tbB
WHERE tbA.id_tbB<=id_max

派生表可以使事情变得更快,因为它会先过滤,然后将选择加载到内存中。因为它是一个派生表,所以它没有索引,所以如果派生表太大,它实际上会减慢速度。仅从派生表中选择所需的字段,以保持较低的内存占用。您始终可以在最后进行额外的连接,以获得所需的其他字段。

好吧,我猜问题的实际答案或至少是其中一个:

如何在联接之前对两个表执行选择

是通过使用虚拟表。。。比如:

DELETE tbA.* FROM (SELECT * FROM tbA WHERE tbA.id_tbB<=id_max)
INNER JOIN (SELECT * FROM tbB WHERE tbB.id_tbB<=id_max)
ON tbA.id_tbB = tbB.id_tbB
WHERE tbB.date<'2014-01-01 00:00:00'
SELECT tbA_filter.* FROM (SELECT tbA.* FROM tbA WHERE tbA.id_tbB<=id_max) AS tbA_filter 
INNER JOIN (SELECT * FROM tbB WHERE tbB.id_tbB<=id_max AND tbB.date<'2014-01-01 00:00:00') AS tbB_filter
ON tbA_filter.id_tbB = tbB_filter.id_tbB
WHERE tbA_filter.id_tbB<=id_max
但是,如果它是一个删除操作(如我的示例中所示),则不可能删除,因为删除虚拟表上的内容是没有用的,因为它是一个虚拟表,而不是真正的原始表


<>重要的是要考虑虚拟表没有索引…因此,尝试使用两个没有索引的表进行连接可能并不明智,因为这将花费很长时间,尤其是在具有难以置信的大量行的表上。

将where子句移动到连接本身如何?我不确定执行计划是否正在执行加入大型cartesean,然后在加入之前进行筛选或筛选。。。例如从tbA.id_tbB=tbB.id_tbB和tbB.datecol上的tbA内部连接tbB中删除tbA.*谢谢您的评论。但是,在您的建议中,我没有看到条件tbB.id\u tbB我猜是从tbB中选择tbB.date,其中tbA.id\u tbB=tbB.id\u tbB将首先执行,对吗?在这种情况下,WHERE子句引用tbA。。。这不会失败吗?如果我没有犯语法错误,我认为这两个都不会失败:是的,tbA中的id\u tbB实际上是指向tbB.id\u tbB的外键。我会尝试让你知道我正在等待最后一个实验完成,然后我需要重新导入整个数据库并重试。谢谢@beiller的建议,这就是我得到的。第一个是关于语法的。第二个可行,需要1100秒才能完成。与我在问题中建议的不使用任何SELECT-before-JOIN相比,它需要869,因此实际上需要更长的时间。我真的不知道为什么,但在我看来,在你的建议中,我们正在做一个关于tbB的选择,一个in子句而不是JOIN子句。我认为,由于tbA没有在IN之前应用SELECT子句,IN子句将取tbA中的1亿行原始行中的每一行,可能这就是为什么?有趣。也许可以尝试选择tbB.id\u tbB from tbB where tbB.date>“2014-01-01 00:00:00”,看看需要多长时间。有关于tbB.date的索引吗?在我看来,你说tbB的争吵更少。另外,你的解释也没有太多意义,因为时差没有显著差异。我比较了三种不同的:THK,以获得你的建议@Brent。我已经试过了,而且成功了。这花了839秒。然而,与完全不使用问题文本中建议的任何select相比,869秒并不是真正意义上的显著改进。在我看来,在您的示例中,我们只是在tbB中进行选择,但仍然尝试使用tbA中的1亿条记录进行连接。我不知道改进是否来自于从tbB中的40000行到虚拟表tbB_过滤器中的4000行。我认为一个更大的改进应该来自于对tbA的选择。让我知道你的想法和想法 bA SELECT非常简单,我认为将其分离不会有多大作用。MySQL应该在加入之前在tbA上应用WHERE过滤器。您可以尝试将WHERE条件移动到JOIN条件中。此外,仅为tbB_过滤器选择id_tbB字段,而不是*。您应该使用SELECT而不是DELETE测试性能。