基于慢位置的搜索结果查询

时间:2012-11-27 21:08:27

标签: mysql sql

我有一个查询,用于查找按位置排序的结果。结果还必须考虑增值税,因此这也在查询中。遗憾的是,查询可能会在未缓存时运行4秒以上。任何人都可以发现任何明显的问题或建议我可以采取哪些措施来改善它吗?

只是为了澄清查询中发生的事情:

  • 使用lat / long
  • 计算距离为欧氏距离
  • incvat字段用于显示包含增值税时的价格
  • WHEN / THEN语句用于将价格0置于最底层

查询:

SELECT * , ROUND( SQRT( POW( ( 69.1 * ( company_branch_lat - 52.4862 ) ) , 2 ) + POW( ( 53 * ( company_branch_lng - - 1.8905 ) ) , 2 ) ) , 1 ) AS distance, 
    hire_car_day + ( hire_car_day * 0.2 * ! hire_car_incvat ) AS hire_car_day_incvat, 
    hire_car_addday + ( hire_car_addday * 0.2 * ! hire_car_incvat ) AS hire_car_addday_incvat, 
    hire_car_week + ( hire_car_week * 0.2 * ! hire_car_incvat ) AS hire_car_week_incvat, 
    hire_car_weekend + ( hire_car_weekend * 0.2 * ! hire_car_incvat ) AS hire_car_weekend_incvat
FROM hire_car
LEFT JOIN company_branch ON company_branch_id = hire_car_branchid
LEFT JOIN hire_cartypelink ON hire_cartypelink_carhireid = hire_car_id
LEFT JOIN users ON company_branch_userid = user_id
WHERE 1 
GROUP BY hire_car_id
HAVING distance <=30
ORDER BY CASE hire_car_day_incvat
WHEN 0 
THEN 40000 
ELSE hire_car_day_incvat
END , distance ASC 
LIMIT 0 , 30

2 个答案:

答案 0 :(得分:2)

您可以使用mysql空间扩展并将纬度和经度保存为点数据类型,并使其成为空间索引。这样,您可以沿曲线重新排列坐标并减小尺寸并保留空间信息。您可以使用空间索引作为边界框来过滤查询,然后使用harvesine公式来选择最佳结果。您的边界框应该大于圆的半径。 Mysql使用具有一些空间索引的rtree,我的例子是关于z曲线或希尔伯特曲线:https://softwareengineering.stackexchange.com/questions/113256/what-is-the-difference-between-btree-and-rtree-indexing。 然后,您可以将地理坐标直接插入点列:http://dev.mysql.com/doc/refman/5.0/en/creating-spatial-values.html。或者您可以使用几何数据类型:http://markmaunder.com/2009/10/10/mysql-gis-extensions-quick-start/。然后你可以使用像这样的MBRcontains函数:http://dev.mysql.com/doc/refman/4.1/en/relations-on-geometry-mbr.html或任何其他函数:http://dev.mysql.com/doc/refman/5.5/en/functions-for-testing-spatial-relations-between-geometric-objects.html。因此,您需要一个边界框。 以下是一些例子:

以下是点数据类型的简单示例:

    CREATE SPATIAL INDEX sx_place_location ON place (location)

    SELECT  * FROM    mytable
    WHERE   MBRContains
           (
           LineString
                   (
                   Point($x - $radius, $y - $radius),
                   Point($x + $radius, $y + $radius)
                   )
           location
           )
    AND Distance(Point($x, $y), location) <= $radius

我不确定它是否有效,因为它使用带有边界框函数的半径变量。在我看来,MBRwithin有点简单,因为它不需要任何参数:Mysql: Optimizing finding super node in nested set tree

答案 1 :(得分:0)

你正在使用GROUP BY语句和HAVING,虽然我没有在查询中的任何地方看到任何聚合函数。我建议你重新编写这样的查询,看看它是否有任何区别

SELECT * , ROUND( SQRT( POW( ( 69.1 * ( company_branch_lat - 52.4862 ) ) , 2 ) + POW( ( 53 * ( company_branch_lng - - 1.8905 ) ) , 2 ) ) , 1 ) AS distance, 
hire_car_day + ( hire_car_day * 0.2 * ! hire_car_incvat ) AS hire_car_day_incvat, 
hire_car_addday + ( hire_car_addday * 0.2 * ! hire_car_incvat ) AS hire_car_addday_incvat, 
hire_car_week + ( hire_car_week * 0.2 * ! hire_car_incvat ) AS hire_car_week_incvat, 
hire_car_weekend + ( hire_car_weekend * 0.2 * ! hire_car_incvat ) AS hire_car_weekend_incvat
FROM hire_car
LEFT JOIN company_branch ON company_branch_id = hire_car_branchid
LEFT JOIN hire_cartypelink ON hire_cartypelink_carhireid = hire_car_id
LEFT JOIN users ON company_branch_userid = user_id
WHERE ROUND( SQRT( POW( ( 69.1 * ( company_branch_lat - 52.4862 ) ) , 2 ) + POW( ( 53 * ( company_branch_lng - - 1.8905 ) ) , 2 ) ) , 1 ) <= 30
ORDER BY CASE hire_car_day_incvat
WHEN 0 
THEN 40000 
ELSE hire_car_day_incvat
END , distance ASC 
LIMIT 0 , 30