Php 优化Postgresql数据库查询的帮助

Php 优化Postgresql数据库查询的帮助,php,optimization,postgresql,performance,Php,Optimization,Postgresql,Performance,我试图在优化用于获取大量数据的查询时找到一些建议 我正在处理的原始代码在一大组用户中循环,并为每个用户计算了一个日期范围。然后,它将在该日期范围内查询他们回答了多少问题,以及在该日期范围内有多少问题是正确的。这些结果已经统计,我们需要的是最终的统计结果 我已经做了一些加快速度的工作,因为这需要几分钟的时间:现在,脚本不再单独查询每个用户,而是在每个用户之间循环计算适用于他们的日期范围。查询的所有其他方面对于每个用户都是相同的。这些数据收集在一个3d数组[startDate][endDate][u

我试图在优化用于获取大量数据的查询时找到一些建议

我正在处理的原始代码在一大组用户中循环,并为每个用户计算了一个日期范围。然后,它将在该日期范围内查询他们回答了多少问题,以及在该日期范围内有多少问题是正确的。这些结果已经统计,我们需要的是最终的统计结果

我已经做了一些加快速度的工作,因为这需要几分钟的时间:现在,脚本不再单独查询每个用户,而是在每个用户之间循环计算适用于他们的日期范围。查询的所有其他方面对于每个用户都是相同的。这些数据收集在一个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日期范围和用户之间存在一对多关系。这些用户id都不会显示在多个日期范围内。 2我们要寻找的最终结果就是这些计数,但是日期范围需要基于每个用户进行计算,因此每个日期范围的id数组

有一件事我认为~可能~会让它变得更快,那就是用板条箱包装一个临时表,其中一列表示日期范围,一列表示用户id。然后使用该表的联接重写该查询,而不是将这些数字放入查询本身。有人知道这是否有效吗

谢谢你的建议

有一件事我认为~可能~ 用板条箱装一只狗会更快 临时表,其中包含用于 用户的日期范围和列 身份证。然后使用 加入那张桌子而不是把它放在桌子上 查询本身中的那些数字。 有人知道这是否有效吗

这就是我将采取的方法。这也将使查询更加清晰。 您也可以将索引添加到临时表中,不过您应该在用数据填充临时表后再添加索引。不要假设你需要一个索引测试

哦,您可能希望存储时间戳,而不是日期,这样可以节省时间,还可以在您的答案表中的时间戳列上创建索引


PS-通常认为最好不要将列命名为与内置类型相同的列。即使数据库没有被人类读者弄糊涂。

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


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

如前所述:请提供解释分析的结果以及表结构和创建的索引,否则将很难提供帮助

timestamp::date上的索引可能有助于避免使用timestamp上的索引,因为强制转换


您还可以发布解释分析输出,其中将突出显示执行计划中存在问题的位置

您可以通过在解释分析到SQL语句之前添加解释分析来运行此查询,并将其粘贴到此处。它将输出查询计划,其中将包含它所采取的每个步骤的成本和时间。请把你的表格定义贴出来好吗?programsId、timestamp和usercontextid属于哪些表?哦,是的,对此很抱歉。programsId、timestamp和usercontextid都显示在usersAnswersProgramsLink表中。它只是一个简单的表格,链接用户、答案和程序,这些都是被询问的问题集。这些UserContentID和时间间隔来自哪里?它们来自同一个数据库吗?如果是,也许您应该合并查询。
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')
  )
)