如何加快这个查询

时间:2012-05-31 07:14:49

标签: mysql query-optimization

我使用了这个查询,mysql花了太长时间才给出结果。行数为1.6百万。

SELECT DISTINCT TB.ID,  Latitude, Longitude,
    111151.29341326*SQRT(pow(-6-`Latitude`,2)
        +pow(106-`Longitude`,2)*cos(-6*0.017453292519943)
        *cos(`Latitude`*0.017453292519943)) as Distance  
FROM `tablebusiness` AS TB, `tablecity` AS TC, `businessestag` AS BC,
    `businessesdistricts` AS BD, `tabledistrict` AS TD, 
     (SELECT ID, 
         (SELECT Title 
            FROM `tablebusiness` As TBuild 
           WHERE TBuild.ID = TBB.Building) As BuildingTitle 
      FROM `tablebusiness` As TBB) AS TBuilding  
WHERE TB.City = TC.City AND BC.BusinessID = TB.ID AND BD.BusinessID = TB.ID 
  AND TD.ID = BD.District AND TBuilding.ID = TB.ID 
  AND (`Title` LIKE '%%' OR `Street` LIKE '%%'  OR TB.City LIKE '%%' 
       OR Country LIKE '%%' OR Tag LIKE '%%' OR TD.District LIKE '%%' 
       OR TBuilding.BuildingTitle LIKE '%%') 
  AND (-6.0917668133836 < `Latitude` AND `Latitude` < -5.9082331866164 
       AND 105.90823318662 < `Longitude` AND `Longitude` < 106.09176681338)  
ORDER BY Distance LIMIT 0, 100

即使行数是160万的查询部分,也就是

AND (-6.0917668133836 < `Latitude` AND `Latitude` < -5.9082331866164 AND 105.90823318662 < `Longitude` AND `Longitude` < 106.09176681338) 

极大地限制了行数。似乎mysql不会通过搜索

来优化查询
AND (-6.0917668133836 < `Latitude` AND `Latitude` < -5.9082331866164 AND 105.90823318662 < `Longitude` AND `Longitude` < 106.09176681338) first.

我通过移动前面的纬度经度方面来改变查询

SELECT DISTINCT TB.ID,  Latitude, Longitude,
    111151.29341326*SQRT(pow(-6-`Latitude`,2)
        +pow(106-`Longitude`,2)*cos(-6*0.017453292519943)
        *cos(`Latitude`*0.017453292519943)) as Distance  
FROM `tablebusiness` AS TB, `tablecity` AS TC, `businessestag` AS BC,
    `businessesdistricts` AS BD, `tabledistrict` AS TD, 
     (SELECT ID, 
         (SELECT Title 
            FROM `tablebusiness` As TBuild 
           WHERE TBuild.ID = TBB.Building) As BuildingTitle 
      FROM `tablebusiness` As TBB) AS TBuilding
WHERE (-6.0917668133836 < `Latitude` AND `Latitude` < -5.9082331866164 
       AND 105.90823318662 < `Longitude` AND `Longitude` < 106.09176681338) 
  AND TB.City = TC.City AND BC.BusinessID = TB.ID AND BD.BusinessID = TB.ID 
  AND TD.ID = BD.District AND TBuilding.ID = TB.ID 
  AND (`Title` LIKE '%%' OR `Street` LIKE '%%'  OR TB.City LIKE '%%' 
       OR Country LIKE '%%' OR Tag LIKE '%%' OR TD.District LIKE '%%' 
       OR TBuilding.BuildingTitle LIKE '%%')
ORDER BY Distance LIMIT 0 ,100

它仍然很慢。

那我该怎么办?

4 个答案:

答案 0 :(得分:1)

只能通过索引搜索查询的某些部分。所以你必须有一个索引。由于MySQL具有(地理)空间数据的扩展,因此您应该查找它并使用R树索引。对于两列,这是最有效的范围限制。

答案 1 :(得分:1)

您是否在朗讯和经度栏上有BTree索引?

答案 2 :(得分:1)

explain select ...show create table tablebusiness \G说什么?

MySQL如何使用index for range queries有一些限制,请务必仔细阅读。

根据我对许多用例的经验,在MySQL中使用b-tree索引比空间索引更有效。我建议将经度和纬度改为整数(乘以适当的数字得到“小数”,并确保你有一个跨越两列(alter table tablebusiness add index latlon (latitude,longitude))的索引。

答案 3 :(得分:1)

您真的需要在FROM子句中包含tablebusiness表三次吗?我重写了这个并使用了JOIN。检查您的WHERE条件。什么是Title LIKE&#39; %%&#39;?试试这个简化的查询 -

SELECT
  TB.ID,
  Latitude,
  Longitude,
  111151.29341326 * SQRT(POW(-6 - `Latitude`, 2) + POW(106 - `Longitude`, 2) * COS(-6 * 0.017453292519943) * COS(`Latitude` * 0.017453292519943)) AS Distance
FROM
  `tablebusiness` AS TB
  JOIN `tablecity` AS TC
    ON TB.City = TC.City
  JOIN `businessestag` AS BC
    ON BC.BusinessID = TB.ID
  JOIN `businessesdistricts` AS BD
    ON BD.BusinessID = TB.ID
  JOIN `tabledistrict` AS TD
    ON TD.ID = BD.District
  LEFT JOIN `tablebusiness` TBuilding
    ON TBuilding.ID = TB.ID
WHERE
  (`Title` LIKE '%%' OR `Street` LIKE '%%' OR TB.City LIKE '%%' OR Country LIKE '%%'
    OR Tag LIKE '%%' OR TD.District LIKE '%%' OR TBuilding.BuildingTitle LIKE '%%')
  AND (-6.0917668133836 < `Latitude` AND `Latitude` < -5.9082331866164 
    AND 105.90823318662 < `Longitude` AND `Longitude` < 106.09176681338) 
ORDER BY
  Distance
LIMIT
  0, 100

在JOIN和WHERE子句中使用的字段上添加索引也会加快查询速度。