帮助优化Postgresql数据库的查询

时间:2009-10-29 21:16:24

标签: php optimization postgresql performance

我正在尝试在优化我用来获取大量数据的查询时找到一些建议。

我正在处理的原始代码通过大量用户循环,并计算了每个用户的日期范围。然后,它将采用该日期范围并查询他们回答的问题数量以及在该日期范围内纠正的数量。这些结果已经计算好了,这就是我们需要的最终结果。

我已经采取了哪些措施来加快速度(因为它需要几分钟)是这样的:现在只需循环遍历每个用户,而不是单独查询每个用户,计算适用于他们的日期范围(查询的所有其他方面对于每个用户都是相同的)。该数据收集在3d数组[startDate] [endDate] [userid]中,并构建一个查询以对所有用户执行该操作。以下是获取输出的查询示例:


SELECT COUNT(uapl.id) AS numAnswered,
SUM(CASE WHEN (a.correct OR q.survey OR uapl.answersId IS NULL) THEN 1 ELSE 0 END) AS numCorrect
FROM usersAnswersProgramsLink uapl
JOIN questions q ON uapl.questionsId=q.id
LEFT JOIN answers a ON uapl.answersId=a.id
WHERE
programsId=123
AND
(
  (
    CAST(timestamp AS date) >= '2009-09-01'
    AND CAST(timestamp AS date) <= '2009-09-21'
    AND usercontextid in('123','234','345','465','567')
  )
  OR
  (
    CAST(timestamp AS date) >= '2009-09-10'
    AND CAST(timestamp AS date) <= '2009-09-21'
    AND usercontextid in('321','432','543')
  )
  OR
  (
    CAST(timestamp AS date) >= '2009-09-16'
    AND CAST(timestamp AS date) <= '2009-09-21'
    AND usercontextid in('987','876')
  )
) 

这在加速代码方面效果相当好。在我运行的大多数测试中,它现在需要20%到10%的时间。尽管我最糟糕的情况是,它只有50%,我想改进它。

最糟糕的情况发生在我有大量的用户ID进行比较时(万分之一)。现在的问题是,我不再对我提取这些查询的算法进行优化。它现在以毫秒为单位。这个查询花了很长时间。

这就是我的难题。我想加快速度。欢迎大家提出意见。这里有几条相关的信息:

1)日期范围与用户之间存在1对多的关系。这些用户ID中没有一个会显示在多个日期范围内。 2)我们正在寻找的最终结果只是那些计数,但日期范围需要基于每个用户计算,因此每个日期范围的id数组。

我认为〜可能会让它更快的一件事就是创建一个临时表,其中包含日期范围的列和用户ID的列。然后使用JOIN重写该查询到该表,而不是将这些数字放在查询本身。有谁知道这是否有效?

感谢您的任何建议!

3 个答案:

答案 0 :(得分:2)

如前所述:请提供EXPLAIN ANALYZE <query>的结果以及表格结构和创建的索引,否则将难以提供帮助

timestamp::date上的索引可以提供帮助(由于演员而不会使用时间戳索引)

您还可以将explain analyze输出发布到http://explain.depesz.com/,这会突出显示执行计划中存在问题的位置

答案 1 :(得分:0)

  

我认为〜可能会做出一件事   它的速度更快   带有列的临时表   日期范围和用户列   ID的。然后使用a重写该查询   加入那张桌子而不是放   查询本身中的那些数字。   有谁知道这是否有效?

这将是我采取的方法。它还将使查询更清晰。 您也可以将索引添加到临时表中,但是在填充数据之后应该执行此操作。不要假设你需要索引 - 测试。

哦 - 您可能希望存储时间戳而不是日期(它会保存转换),也可能是答案表中“timestamp”列的索引。

PS - 通常认为最好不要将列命名为内置类型。即使数据库不会让人类读者感到困惑。

答案 2 :(得分:0)

首先,我建议您添加一个粗略的过滤器,使用usercontextidtimestamp上的索引:

SELECT  COUNT(uapl.id) AS numAnswered,
        SUM(CASE WHEN (a.correct OR q.survey OR uapl.answersId IS NULL) THEN 1 ELSE 0 END) AS numCorrect
FROM    questions q
JOIN    usersAnswersProgramsLink uapl
ON      uapl.questionsId = q.id
LEFT JOIN
        answers a
ON      a.id = uapl.answersId
WHERE   programsId=123
        AND timestamp >= '2009-09-01'
        AND timestamp < '2009-09-22'
        AND usercontextid IN (/* all possible values here */)
        AND 
(
  (
    CAST(timestamp AS date) >= '2009-09-01'
    AND CAST(timestamp AS date) <= '2009-09-21'
    AND usercontextid in('123','234','345','465','567')
  )
  OR
  (
    CAST(timestamp AS date) >= '2009-09-10'
    AND CAST(timestamp AS date) <= '2009-09-21'
    AND usercontextid in('321','432','543')
  )
  OR
  (
    CAST(timestamp AS date) >= '2009-09-16'
    AND CAST(timestamp AS date) <= '2009-09-21'
    AND usercontextid in('987','876')
  )
)

您还需要澄清所有这些字段属于哪些表。