0

我需要简化此查询,因为保存 mysql 的服务器无法在设置的时间限制内执行此操作。

SELECT `B`.*,
       `C`.`name`,
       DATE_ADD(`B`.`SAILING-DATE`, INTERVAL `B`.`NIGHTS` DAY) AS dataEnd 

FROM `table1` AS B 
INNER JOIN `table2` AS A 
INNER JOIN `table3` AS C

WHERE `B`.`ID`=`A`.`ID` 
AND `B`.`CAT`=`A`.`CAT` 
AND `C`.`code`=`A`.`code`
AND (`B`.`NIGHTS`>=$aNumber AND `B`.`NIGHTS`<=$anotherNumber) 
// where are other AND like this on `table1`

在哪里table1并且table2有大约 25.000 行。

我想 suddivide 执行第一个查询的查询table1,而不是循环所有结果并对每个结果进行一次查询,但我认为效率太低。

有人能帮我吗?谢谢!!!

编辑:

这是解释:

在此处输入图像描述

编辑2:

我不能添加索引导致字段IDCAT并且code在每个表中都不是唯一的.. 在每个表中都有更多具有相同ID CATcode

编辑3:

我认为最好将所有内容划分为更简单的子查询..有人可以给我一个想法吗?谢谢!

4

2 回答 2

3

您可以尝试的一件事是:

SELECT `B`.*, 
       `C`.`name`, 
       DATE_ADD(`B`.`SAILING-DATE`, INTERVAL `B`.`NIGHTS` DAY) AS dataEnd  

FROM (SELECT * 
         FROM `table1` 
         WHERE table1.NIGHTS >=$aNumber AND table1.NIGHTS <=$anotherNumber) AS B  
INNER JOIN `table2` AS A  ON `B`.`ID`=`A`.`ID` AND `B`.`CAT`=`A`.`CAT`
INNER JOIN `table3` AS C  ON `A`.`code` = `C`.`code`

这将有效地预过滤 table1 中的行,仅选择那些Nights满足您所需条件的行,从而减少其他表上连接所涉及的数量。

另请注意,您的 JOIN 条件应该在使用 ON 的 INNER JOIN 之后 - 在这种情况下,您实际上不需要 WHERE 子句。

您应该调查的另一件事是查询计划 - 有关详细信息,请参阅EXPLAIN命令。

在这种情况下,您可能会从 ID、CAT 和 CODE 列上的索引中受益,但是,不要只是为所有内容添加索引,而是首先检查 EXPLAIN 的输出以查看最佳节省的位置 - 添加索引将有插入数据时的成本。

编辑:

好的,所以子查询执行得很好,但是您担心无法预过滤 table1 的情况。首先,让我们修改您的原始查询,然后尝试:

SELECT B.*, 
       C.name, 
       DATE_ADD(B.SAILING-DATE, INTERVAL B.NIGHTS DAY) AS dataEnd  

FROM table1 AS B  
INNER JOIN table2 AS A  ON (B.ID=A.ID AND B.CAT=A.CAT)
INNER JOIN table3 AS C  ON (A.code = C.code)

我想知道您的原始查询的奇怪格式(连接条件应该真正遵循您要加入的表)是否在某种程度上使 MySql 感到困惑。我还删除了不需要的反引号,并且在我看来,这使查询更难阅读(和输入)。

如果性能不符合您的预期,请在 table1 和 table2 上发布SHOW INDEX的结果。可能是在 table1 中的 ID 和 CAT 以及 table2 中的 ID 和 CAT 组合上添加索引(复合索引)可能会提高您的性能。

于 2012-08-07T23:12:00.390 回答
1

首先将连接条件放在连接中,以帮助数据库对查询做出正确解释。这可能不会产生性能差异,但至少查询会更容易为人类解释。

您不需要在查询中的别名周围加上反引号。你现在没有到处都有它们,所以要保持一致并在任何地方添加它们,或者删除它们。

SELECT B.*,
       C.`name`,
       DATE_ADD(B.`SAILING-DATE`, INTERVAL B.`NIGHTS` DAY) AS dataEnd 

FROM `table1` AS B 
INNER JOIN `table2` AS A ON B.`ID`=A.`ID` AND B.`CAT`=A.`CAT`
INNER JOIN `table3` AS C ON C.`code`=A.`code`
WHERE (B.`NIGHTS`>=$aNumber AND B.`NIGHTS`<=$anotherNumber)

然后确保您有查询可以使用的索引,例如 on table2.NIGHTS。您可以使用该explain命令来确定查询使用了哪些索引。

于 2012-08-07T23:14:34.433 回答