性能差异:INNER JOIN与WHERE子句的条件

Ins*_*ous 28 sql postgresql performance query-optimization

说我有一个表order作为

id | clientid | type | amount | itemid | date
---|----------|------|--------|--------|-----------
23 | 258      | B    | 150    | 14     | 2012-04-03
24 | 258      | S    | 69     | 14     | 2012-04-03
25 | 301      | S    | 10     | 20     | 2012-04-03
26 | 327      | B    | 54     | 156    | 2012-04-04
Run Code Online (Sandbox Code Playgroud)
  • clientid是一个回到client桌面的外键
  • itemid是一个回到item表的外键
  • type只是BS
  • amount 是一个整数

和一张桌子processed作为

id | orderid | processed | date
---|---------|-----------|---------
41 | 23      | true      | 2012-04-03
42 | 24      | true      | 2012-04-03
43 | 25      | false     | <NULL>
44 | 26      | true      | 2012-04-05     
Run Code Online (Sandbox Code Playgroud)

我需要把所有从行order,对于相同的clientid同一date具有相反的type值.请记住type,只能有两个值之一 - BS.在上面的例子中,这将是行2324.

另一个约束是相应的行processed必须是truefor orderid.

我的查询到目前为止

SELECT c1.clientid,
       c1.date,
       c1.type,
       c1.itemid,
       c1.amount,
       c2.date,
       c2.type,
       c2.itemid,
       c2.amount

FROM   order c1
INNER JOIN order c2 ON c1.itemid    =  c2.itemid AND
                       c1.date      =  c2.date   AND
                       c1.clientid  =  c2.clientid AND
                       c1.type     <>  c2.type AND
                       c1.id        <  c2.id

INNER JOIN processed p1 ON p1.orderid   =  c1.id AND
                         p1.processed =  true
INNER JOIN processed p2 ON p2.orderid   =  c2.id AND
                         p2.processed =  true
Run Code Online (Sandbox Code Playgroud)

问题:保持processed = truejoin子句的一部分会降低查询速度.如果我将它移动到WHERE子句,那么性能会好得多.这引起了我的兴趣,我想知道为什么.

而值列(主键和相应的外键列被索引value,processed等等)则不是.

免责声明:我继承了这种DB结构,性能差异大约为6秒.

Mar*_*tin 9

您看到差异的原因是由于计划程序正在组合的执行计划,这显然根据查询而不同(可以说,它应该优化2个查询是相同的,这可能是一个错误).这意味着规划人员认为必须以特定方式工作才能获得每个语句中的结果.

当您在JOIN中执行此操作时,计划程序可能必须从表中进行选择,按"True"部分进行筛选,然后加入结果集.我想这是一个大表,因此要查看大量数据,并且它不能有效地使用索引.

我怀疑如果你在WHERE子句中这样做,规划者就会选择一种效率更高的路由(即基于索引或预过滤的数据集).

您可以通过在两列上添加索引来快速(如果不是更快)使连接工作(不确定Postgres是否支持包含列和多列索引).

简而言之,规划者就是选择2条不同的路径来获取结果集的问题,其中一条路线的效率不如另一条路线.如果没有完整的表格信息和EXPLAIN ANALYZE信息,我们就不可能知道原因是什么.

如果您需要有关特定查询执行此操作的详细信息,则需要提供更多信息.然而原因是计划者选择不同的路线.

附加阅读材料:

http://www.postgresql.org/docs/current/static/explicit-joins.html

只是略读,似乎postgres规划师没有重新订购连接来优化它.尝试更改语句中连接的顺序,看看你是否获得相同的性能......只是一个想法.

  • 你不要通过在`ON`或`WHERE`子句中加入条件来强制**查询规划器.一个不错的优化器/查询规划器应该能够将两个版本识别为等效(如果是)并从各种执行计划中进行选择. (2认同)