mysql大查询性能提升

时间:2011-10-18 14:56:02

标签: php mysql

任何人都知道如何优化此查询?它工作正常,但是当负载很重时它会导致服务器超时。

$screenRestrict="clientID='1' AND screenID='1'";
$lastupdate="1318515710";

INSERT INTO allvisits (clientID, screenID, hitID, entryPageID, entryPageName, xentryTime, xexitTime, pagecount, minsonsite)(
    SELECT 
        clientID, screenID, id AS hitID, pageID AS entryPageID,
        (SELECT name FROM pages WHERE id=entryPageID) AS entryPageName,
        (SELECT clicktime FROM clicks WHERE id = hitID AND isFirstClick=1 ) AS xentryTime,
        (SELECT MIN(clicktime) FROM clicks WHERE $screenRestrict AND isLastClick=1 AND clicktime > xentryTime) AS xexitTime,
        (SELECT COUNT(*) FROM clicks WHERE $screenRestrict AND clicktime BETWEEN xentryTime AND xexitTime) AS pagecount,
        (SELECT (xexitTime-xentryTime)/60) AS minsonsite
    FROM clicks WHERE $screenRestrict AND isFirstClick=1 AND clicktime>'$lastupdate'
)

非常感谢:)

更新

感谢所有提示。我已经为isLastClick添加了一个索引,并设法加快它的速度,但是在低服务器负载下仍需要+10秒。我已经确定了最后一个瓶颈并在下面标出了它。有没有更好的方法来选择晚于xentrytime的第一个“isLastClick”记录?

SELECT clientid, 
             screenid, 
             id                                                      AS hitid, 
             pageid                                                  AS entrypageid, 
             clicktime                                               AS xentrytime, 
             (SELECT name 
                FROM   pages 
                WHERE  id = entrypageid)                               AS entrypagename, 
             (SELECT clicktime 
                FROM   clicks 
                WHERE  clicktime > xentrytime //<<removing this cuts 8.5 seconds!!
                             AND screenid = '2' 
                             AND islastclick = 1 
                             LIMIT 1)             AS xexittime, 
             (SELECT COUNT(1) 
                FROM   clicks 
                WHERE  screenid = '2' 
                             AND clicktime BETWEEN xentrytime AND xexittime) AS pagecount, 
             (SELECT ( xexittime - xentrytime ) / 60)                AS minsonsite 
FROM   clicks 
WHERE  screenid = '2' 
             AND isfirstclick = 1 
             AND clicktime > '1318961057'

1 个答案:

答案 0 :(得分:1)

请检查评论。

如果页面的$ screenrestrict和页面ID相同。尝试使用该页面标识

加入内部表

我不确定您对xentrytime和xexittime列的想法。因为,我看到使用子查询获取相同的东西。

请记住,要调优查询,请尝试获取过滤器并限制每个子查询中选择的行数。有些过滤器是基于业务逻辑编写的,因此在编写查询时也要考虑包含这些条件,并查看解释计划中的性能是否有所提高。

INSERT INTO allvisits 
            (clientid, 
             screenid, 
             hitid, 
             entrypageid, 
             entrypagename, 
             xentrytime, 
             xexittime, 
             pagecount, 
             minsonsite) 
(SELECT clientid, 
        screenid, 
        id                                                      AS hitid, 
        pageid                                                  AS entrypageid, 
        (SELECT name 
         FROM   pages 
         WHERE  id = entrypageid)                               AS entrypagename 
        , 
        clicktime                        AS xentrytime, //this should work w.r.t your code
        (SELECT MIN(clicktime)             //try to change this logic. The logic written here doesnt look good at all. and try to filter out data by joining with outer table. 
         FROM   clicks 
         WHERE  $screenrestrict 
                AND islastclick = 1 
                AND clicktime > xentrytime)                     AS xexittime, 
        (SELECT COUNT(1)   //this will give some performance improvement
         FROM   clicks 
         WHERE  $screenrestrict 
                AND clicktime BETWEEN xentrytime AND xexittime) AS pagecount, 
        (SELECT ( xexittime - xentrytime ) / 60)                AS minsonsite 
 FROM   clicks 
 WHERE  $screenrestrict 
        AND isfirstclick = 1 
        AND clicktime > '$lastupdate') 

<强>更新

这两个内部查询需要更多的微调

       SELECT MIN(innClick.clicktime)             
         FROM   clicks innClick1
         WHERE  innClick1.screenid =  '2' // when u put it as part of big query use  WHERE  innClick1.screenid = outClick.screenid instead of hard coding it. where outClick is alias for Click table in outside
                AND innClick1.islastclick = 1 
                AND innClick1.clicktime > innClick1.xentrytime

        SELECT COUNT(1) 
         FROM   clicks innClick2
         WHERE  innClick2.screenid =  '2' 
                AND innClick2.clicktime BETWEEN innClick2.xentrytime AND innClick2.xexittime

w.r.t解释计划

  • 您可以尝试添加更多过滤器以减少内部查询中提取的行数。
  • 尝试减少任何全表扫描,如果扫描基于索引扫描(也完整),可以暂时忽略。
  • 尝试根据已编入索引的列添加过滤器。
  • 通过在这些子查询中进一步过滤数据并尝试进行大量试验和错误 -
  • 尝试分别减少每个查询的时间。当你有更好的表现时,最后加入他们

单击时间,xentrytime和xexittime,如果已建立索引,我认为查询的性能会更好。您可以尝试but still indexing will slow your insert statements,因为每次插入时都应更新这些额外的索引。