我有以下JOIN查询:
SELECT
table1.*,
table2.*
FROM
Table1 AS table1
LEFT JOIN
Table2 AS table2
USING
(col1)
LEFT JOIN
Table3 as table3
USING
(col1)
WHERE
3963.191 *
ACOS(
(SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180))
+
(COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180))
) <= 10
AND
table1.col1 != '1'
AND
table1.col2 LIKE 'A'
AND
(table1.col3 LIKE 'X' OR table1.col3 LIKE 'X-Y')
AND
(table2.col4 = 'Y' OR table2.col5 = 'Y')
在 0.15秒下执行。
但是,如果我只是添加:
ORDER BY
table1.col6 DESC
执行时间超过 3秒。
查询中的所有列均为已编入索引,包括table1.col6
中使用的ORDER BY
。
我尝试了this solution,但它没有用。
如何使用ORDER BY
快速运行此查询。
修改
结果EXPLAIN EXTENDED
没有 ORDER BY
:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table1 ALL PRIMARY,col2,col3 NULL NULL NULL 140101 72.61 Using where
1 SIMPLE table2 eq_ref PRIMARY,col4,col5 PRIMARY 4 table1.col1 1 100 Using where
1 SIMPLE table3 eq_ref PRIMARY PRIMARY 4 table1.col1 1 100 Using where
EXPLAIN EXTENDED
WITH ORDER BY
的结果:
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE table1 ALL PRIMARY,col2,col3 NULL NULL NULL 140101 72.61 Using where; Using filesort
1 SIMPLE table2 eq_ref PRIMARY,col4,col5 PRIMARY 4 table1.col1 1 100 Using where
1 SIMPLE table3 eq_ref PRIMARY PRIMARY 4 table1.col1 1 100 Using where
编辑2:
查询中所有列的数据类型(根据要求):
col1: int(11)
col2: char(1)
col3: varchar(3)
col4: char(1)
col5: char(1)
col6: int(11)
latitude: varchar(25)
longitude: varchar(25)
所有3个表(table1,table2和table3)都是MyISAM
。
答案 0 :(得分:1)
这不是一个解决方案,但它可能有所帮助:避免使用'*'指定所需的列并明确指定它们。当你使用*来指定所有列时,MySQL必须做更多的工作,在数据排序时分流数据,因此更有可能做一个文件输出,这很慢。
此外,索引对MySQL可以轻松订购数据的影响很小或没有影响,但您应该检查它是否使用BTREE索引,因为它们更有可能保持相对良好的秩序。
最糟糕的是,如果您还没有这样做,可能需要阅读MySQL手册对ORDER BY optimisation的评论。我看不到任何适用的东西,但你可能会看到我遗漏的东西。
答案 1 :(得分:1)
我能想到解决此问题的另一种方法是将表更改为默认订单 - 然后从查询中删除order by
。
答案 2 :(得分:0)
如果您的查询速度与您指示的一样快,我预计它会返回一个相当小的数据集。如果是这种情况,我会按原样包装你的,然后将ORDER BY OUTIDE放在... ...
select
PreQuery.*
from
( Your Entire Query Without the order by clause ) as PreQuery
order by
PreQuery.Col6 Desc
这样,外部查询与现有索引无关,只返回数据...然后该结果将按原始结果应用顺序。
希望能为你解决问题。
答案 3 :(得分:0)
除了我的其他答案提供将现有查询包装在select中之外,然后对结果进行排序。这是查询的另一个选项......如果我的解释不正确,请纠正我。
你正在对表2进行LEFT-JOIN,但由于where子句,要求Col4或Col5 ='Y',因此表示INNER JOIN(表1和表2中必须存在记录)。
类似地,你的表3加入表1,但是限制了距离&lt; = 10,所以LEFT-JOIN并不真正准确,因为它是WHERE的一部分,表示需要。
所以,我修改过的查询如下所示。我基本上将“WHERE”组件移动到相应的表JOIN命令。如果你真的DID意味着拥有LEFT-JOIN并希望所有表1记录表2 /表3的记录,那么你可以简单地将它们改为LEFT JOIN。
SELECT STRAIGHT_JOIN
T1.*,
T2.*
FROM
Table1 AS T1
JOIN Table2 AS T2
ON T1.Col1 = T2.Col1
AND ( T2.Col4 = 'Y' OR T2.Col5 = 'Y' )
JOIN Table3 as T3
ON T1.Col1 = T3.Col1
AND 3963.191
* ACOS( (SIN(PI() * $usersLatitude / 180) * SIN(PI() * T3.latitude / 180))
+ ( COS(PI() * $usersLatitude / 180) * COS(PI() * T3.latitude / 180)
* COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)
)
) <= 10
WHERE
T1.Col2 LIKE 'A'
AND ( T1.col3 LIKE 'X' OR T1.col3 LIKE 'X-Y')
AND T1.Col1 != '1'
ORDER BY
T1.Col6
如果直接应用order by子句,则将第6列添加到表1的索引
On Table 1, I would have an index on ( Col2, Col3, Col1, Col6 )
On Table 2 on ( Col1, Col4, Col5 )
On Table 3 on ( Col1 ) <-- assume already had this.
答案 4 :(得分:0)
为什么在非通配符值上执行LIKE
?这将使计划者变得更加悲观。但大多数情况下,您需要查看查询计划程序显示的内容。
另外,您最近在桌子上做过ANALYZE
吗?如果行统计信息已关闭,则规划人员将做出糟糕的选择。