【问题标题】:Why is this postgresql query so slow?为什么这个 postgresql 查询这么慢?
【发布时间】:2011-02-28 23:06:34
【问题描述】:

我不是数据库专家,但我有足够的知识让自己陷入困境,就像这里的情况一样。这个查询

SELECT DISTINCT p.* 
  FROM points p, areas a, contacts c 
 WHERE (    p.latitude > 43.6511659465 
        AND p.latitude < 43.6711659465 
        AND p.longitude > -79.4677941889 
        AND p.longitude < -79.4477941889) 
   AND p.resource_type = 'Contact' 
   AND c.user_id = 6

非常慢。 points 表的记录少于 2000 条,但执行大约需要 8 秒。纬度和经度列上有索引。删除关于 resource_type 和 user_id 的子句没有任何区别。

纬度和经度字段都被格式化为数字(15,10)——我需要一些计算的精度。

在这个项目中有很多很多其他的查询比较点,但没有执行时间问题。怎么回事?

【问题讨论】:

  • 请发表解释。 Distinct 通常是性能问题。另外,请确保对纬度和经度进行索引。

标签: sql database postgresql indexing


【解决方案1】:

您是否忘记了实际查询中的某些内容?它缺少三个表之间的 ANSI-89 连接,为您提供笛卡尔积,但仅提取 POINTS 记录。

【讨论】:

  • 不仅如此,AND c.user_id=6 什么也不做,因为没有返回来自contacts 的结果。
  • 但是当仅在点和数字 long & lat 值之间进行比较时,速度没有变化。那里不可能加入,不是吗?
  • @user315975:我不知道您的数据,但如果表格毫无用处,请不要包含表格。仍然需要知道POINTSCONTACTS 之间的关系...
  • @user315975:分析一个有意义的查询的性能可能更值得。
  • 是的!发生的事情是他正在获取点、区域和联系人行的所有可能排列,然后按照“DISTINCT”子句的指示对其进行排序以删除重复项。
【解决方案2】:

您要连接三个表,p、a 和 c,但您没有指定如何将它们连接在一起。您得到的是在所有符合条件的表中的所有行之间的完整笛卡尔连接,然后是区域中的所有内容。

您可能希望将点中的某些内容附加到区域中的某些内容上。还有一些与……有联系的东西。好吧,我不知道你的架构是什么样的。

尝试在开头添加“EXPLAIN”以了解正在发生的事情。

【讨论】:

  • 确实如此。您可能只有 2000 条记录,但如果您有 2000 条区域和 2000 条联系人,那么您将生成 2000 * 2000 * 2000 = 80 亿行,然后将它们重新排序为不同的。
【解决方案3】:

您可能缺少连接。加入表会是这样的。

SELECT DISTINCT p.* 
  FROM points p
  JOIN areas a p ON  a.FkPoint = p.id
  JOIN contacts c ON c.FkArea = a.id
 WHERE (    p.latitude > 43.6511659465 
        AND p.latitude < 43.6711659465 
        AND p.longitude > -79.4677941889 
        AND p.longitude < -79.4477941889) 
   AND p.resource_type = 'Contact' 
   AND c.user_id = 6

要获得更好的坐标索引,请使用 QuadtreeR-Tree 索引实现。

如果您故意没有错过连接,请尝试这样的子查询。

select DISTINCT thePoints.*
(   
    SELECT DISTINCT p.* 
    FROM points p
    WHERE (     p.latitude > 43.6511659465 
            AND p.latitude < 43.6711659465 
            AND p.longitude > -79.4677941889 
            AND p.longitude < -79.4477941889) 
    AND p.resource_type = 'Contact' 
) as thePoints
, areas, contacts
WHERE  c.user_id = 6

【讨论】:

    【解决方案4】:

    您需要一个rtree 索引并使用@ 运算符,普通索引不起作用。

    R-树 http://www.postgresql.org/docs/8.1/static/indexes-types.html

    @ 运算符 http://www.postgresql.org/docs/8.1/static/functions-geometry.html

    【讨论】:

    • R-tree 索引不存在 8.3+。
    • 好吧,GiST 索引(我认为它为 geom 类型实现了 R-trees)
    猜你喜欢
    • 2011-03-11
    • 2020-03-19
    • 2014-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多