php pdostatement::execute taking FOREVER


php pdostatement::execute taking FOREVER

我正在设计一个web应用程序,它有一个相当复杂的查询来搜索用户当前位置附近的点。。。以及相当多的其他信息。主POI表中大约有150万行,该表与其他四个表相连(其他较小的表用于与主要兴趣点相关的其他数据(。

当在mysql控制台中运行查询时,它会在0.5秒或更短的时间内返回我要查找的数据(达到这一点已经足够PITA了,但我最终在主POI表上找到了我需要的索引(。。。但是,当我将查询放入我的应用程序并通过web运行时(通过jquery、ajax和php-pdo准备的语句(,返回任何数据都需要6-7秒以上。。。有时长达18-25秒。

我可能做错了什么,会导致执行花那么长时间?有没有什么事情我需要确保我正在做,我可能会忘记?

以下是我的php代码的相关片段(非常简单(,其中实际发生了减速:

$qry = "...";
$data = array(xxx); // user's lat/lon and other data we need
$sth = $this -> ci -> prepare($qry);
$sth -> execute($data);

记录在案,将它作为一个未准备好的语句来运行并没有什么好的。事实上,它实际上有点慢。。。

请帮帮我,我一整天都在为这个揪头发。我以为一旦我最终优化了查询,就会解决问题,但事实显然不是这样。。。

mysql> select
    t.treasureID, t.buriedByUserID, t.lockLevel, t.currentGoldValue, t.initialSilverValue,
    t.burySeen, t.initialGoldValue, t.prize1, t.buryPerkID, t.decoyOf,
    t.unlockAttempts, t.unlockedByKeypad, t.unlockedByUserID, t.prizeID,
    p.prizeDesc, p.validFrom, p.validUntil, p.sponsor, p.prizeName,
    userB.displayName as bDisplayName, s.sponsorID, s.sponsorName, pb.perkName,
    (DEGREES( ACOS( SIN( RADIANS( 40.6846 ) ) * SIN( RADIANS( t.latitude ) ) + COS( RADIANS( 40.6846 ) ) * COS( RADIANS( t.latitude ) ) * COS( RADIANS( -76.19613 - t.longitude ) ) ) ) * 60 * 1.1515 ) AS distance
    from treasures t
    left join prizes p on t.prizeID=p.prizeID
    left join userInfo userB on userB.userID=t.buriedByUserID
    left join sponsors s on p.sponsorID=s.sponsorID
    left join perksB pb on t.buryPerkID=pb.perkID
    where
        t.unlockedByUserID=-1 and
        t.buriedByUserID<>1011 and
        t.isGlobal=0 and
        t.latitude between 40.467351088803 and 40.901848911197 and
        t.longitude between -76.483560028513 and -75.908699971487 and
        ((1361820374 > p.validFrom and 1361820374 < p.validUntil) or p.validUntil is null)
        having distance < 15
        order by distance asc
        limit 0, 50;
+------------+----------------+-----------+------------------+--------------------+----------+------------------+--------+------------+---------+----------------+------------------+------------------+---------+---------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------+-----------------+--------------+-----------+--------------+----------+---------------------+
| treasureID | buriedByUserID | lockLevel | currentGoldValue | initialSilverValue | burySeen | initialGoldValue | prize1 | buryPerkID | decoyOf | unlockAttempts | unlockedByKeypad | unlockedByUserID | prizeID | prizeDesc                                                                                                                 | validFrom  | validUntil | sponsor       | prizeName       | bDisplayName | sponsorID | sponsorName  | perkName | distance            |
+------------+----------------+-----------+------------------+--------------------+----------+------------------+--------+------------+---------+----------------+------------------+------------------+---------+---------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------+-----------------+--------------+-----------+--------------+----------+---------------------+
+------------+----------------+-----------+------------------+--------------------+----------+------------------+--------+------------+---------+----------------+------------------+------------------+---------+---------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------+-----------------+--------------+-----------+--------------+----------+---------------------+
50 rows in set (0.78 sec)

在控制台中,尝试以这种方式运行

SELECT SQL_NO_CACHE t.treasureID...

和这个

EXPLAIN SELECT t.treasureID...

如果它运行缓慢并且explain显示了许多行,那么问题就出在查询本身
如果它在没有缓存的情况下运行得很快,请尝试控制台版本的已准备语句
如果差异仍然存在(控制台没有准备好的快速,控制台有准备好的慢速(-分析两个查询,看看你能从分析结果中得到什么:

set profiling=1;
...run your queries
show profiles;
show profile for query 1;
show profile for query 2;

也试着玩ATTR_EMULATE_REPREPARES,但我觉得这没有多大帮助
还要确保PHP端没有其他代码会花费时间