如何简化SQL查询

时间:2012-08-07 23:06:07

标签: php mysql sql

我需要简化此查询,因为持有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`

table1table2约有25.000行。

我想把查询在table1上执行第一个查询,而不是循环所有结果并为每个结果做一个查询,但我认为效率太低。

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

编辑:

这是解释:

enter image description here

EDIT2:

我无法添加索引原因字段IDCATcode在每个表中都不是唯一的...每个表中都有更多行ID CATcode

EDIT3:

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

2 个答案:

答案 0 :(得分: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条件应该在INNER JOIN之后使用ON - 在这个实例中您实际上不需要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组合索引(composite index)可能会提高您的效果。

答案 1 :(得分: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)

然后确保您拥有查询可以使用的索引,例如table2.NIGHTS。您可以使用explain command来确定查询使用的索引。