这个代码在一个小桌子上工作得很好,但是我有一个有180万条记录的表,所以我的搜索时间大约是12秒。我在client_id和customername上通过Phpmyadmin在我的表上创建了一个b-tree索引,速度没有变化。我的表包含116列。我是否需要将表分解为多个表并使用join命令?我见过join命令,但之前从未使用过它。如果是这样,有人可以给出一个简单的例子
$stmt = $conn->prepare("SELECT *, ( 3959 * acos( cos( radians(:currentlat) ) * cos( radians( lat ) ) * cos( radians( longitude ) - radians(:currentlon) )
+ sin( radians(:currentlat) ) * sin( radians( lat ) ) ) ) AS distance FROM $live_table
WHERE (companyname like :name )
AND
is_active != :active_switch
HAVING distance < :mydistance ORDER BY client_id desc LIMIT $start, $limit");
$stmt->bindValue(':name' , "%$name%", PDO::PARAM_STR);
$stmt->bindValue(':currentlat' , "$currentlat", PDO::PARAM_STR);
$stmt->bindValue(':currentlon' , "$currentlon", PDO::PARAM_STR);
$stmt->bindValue(':mydistance' , "$mydistance", PDO::PARAM_STR);
$stmt->bindValue(':active_switch' , "$active_switch", PDO::PARAM_STR);
答案 0 :(得分:0)
查询速度慢的一个重要原因是HAVING DISTANCE < :mydistance
子句。这会迫使你的MySQL服务器计算到每一行的距离,然后过滤它们,并可能导致你的megarow表的全表扫描。
您可能应该在WHERE子句中使用边界框计算。我们的想法是从您的桌子中排除位于南,北,东或西太远的行,使其落在:mydistance
范围内。这是一个好主意,因为您的查询可以使用lat
列上的索引来排除大量行。它看起来像这样:
...
WHERE (companyname like :name )
AND
is_active != :active_switch
AND lat BETWEEN :currentlat - (:mydistance / 69.0 )
AND :currentlat + (:mydistance / 69.0 )
AND long BETWEEN :currentlong - (:mydistance / (111.045 * COS(RADIANS(latpoint))))
AND :currentlong + (:mydistance / (111.045 * COS(RADIANS(latpoint))))
HAVING distance < :mydistance ORDER BY client_id desc LIMIT $start, $limit
此边界框搜索的写入是here。幻数69.0
来自于每个纬度都有大约69英里的事实。 3959
是一个弧度(57.3958度)的英里数。
但是,编写此查询的方式使得很难使用索引来加速它。 It's not sargable as written。如果您可以重新制定标准
WHERE companyname = :name
AND is_active = :inactive_switch
AND lat BETWEEN ...
AND long BETWEEN ...
然后(companyname, is_active, lat)
上的复合索引将在查询性能方面产生奇迹般的改进。查询计划程序可以随机访问索引到适当的起始值lat
,然后按顺序扫描到最后一个相关值。
请注意,创建大量单列索引通常会对INSERT
和UPDATE
性能造成影响,并且通常无法帮助您更快地进行SELECT
查询。
另请注意,SELECT *
对查询效果有害,尤其是在包含许多列且具有ORDER BY ... LIMIT
模式的表中。为什么? MySQL必须对一大堆长行进行排序,只是为了丢弃除了少数几个之外的所有行。您最好在SELECT
声明中列出实际需要的列。
116列是一个非常大的 - 有些人会说在病理上很大 - 在一个表中有一些列,特别是一个megarow表。如果不了解更多数据,很难为重构数据提出建议。您可能想要调查名为数据库规范化的主题。
答案 1 :(得分:0)
查询需要很长时间的主要原因是在查询中使用了Sin,Cos,ACos函数。
如你所知:
如您所见,这些计算非常耗时。特别是当你为数百万行重复这些计算时。
您需要的是: