1
SELECT * FROM table1
WHERE (col1, col2) IN (($1, $2), ($3, $4))
ORDER  BY col3
LIMIT  10;

输出EXPLAIN ANALYZE

 Limit  (cost=59174.75..59174.77 rows=10 width=113) (actual time=3632.627..3632.661 rows=10 loops=1)
   ->  Sort  (cost=59174.75..59180.22 rows=2188 width=113) (actual time=3632.623..3632.634 rows=10 loops=1)
         Sort Key: col3
         Sort Method: top-N heapsort  Memory: 27kB
         ->  Nested Loop  (cost=2.62..59127.46 rows=2188 width=113) (actual time=0.234..3561.309 rows=38347 loops=1)
   ...........
   Total runtime: 3632.818 ms

但是当我删除订单时:

SELECT * FROM table1 WHERE (col1, col2) IN (($1, $2), ($3, $4)) LIMIT 10;
 Limit  (cost=2.62..272.85 rows=10 width=105) (actual time=0.258..1.143 rows=10 loops=1)
   ->  Nested Loop  (cost=2.62..59127.46 rows=2188 width=105) (actual time=0.255..1.115 rows=10 loops=1)
........
Total runtime: 1.306 ms
  1. 有一个复合btree index on (col1, col2)和一个btree index on col3
  2. 写入性能和存储不是优先事项。读取性能至关重要,需要尽可能快。
  3. 这必须能够支持使用 IN 子句进行查询:WHERE (col1, col2) IN (($1, $2), ($3, $4)) ORDER BY col3 LIMIT 10;. (查找总是带有一个 IN 子句然后排序。)

注意:是否可以在 (col1, col2, col3) 上创建索引?那将使用(col1, col2)col3已订购...

4

1 回答 1

2

是的。你已经在问题中得到了答案。
对于给定的查询,多列索引(col1, col2, col3)应该是完美的。就试一试吧。

更多关于多列 B 树索引中列顺序的信息,请参见 dba.SE 上
的相关问题:复合索引是否也适用于第一个字段的查询?

此外,如果您实际上并不需要 中的所有列table1,则只需将所需的列放在SELECT列表中,而不是*获得性能。

至于您的附加要求:

WHERE (col1, col2) IN (($1, $2), ($3, $4))

相当于:

WHERE (col1 = $1 AND col2 = $2 OR
       col1 = $3 AND col2 = $4)

这降低了索引的有效性(col1, col2, col3),因为 Postgres 不能只从索引中获取预排序列表。这取决于。列表中的项目越少,每个IN相同的行越多,您从所述索引中获得的收益就越多。col3(col1, col2)

你必须进行测试。另外创建索引,确保您的服务器配置合理,统计数据是最新的(ANALYZE)并且您的成本设置是合理的,然后EXPLAIN将显示 Postgres 选择的内容。请务必运行一组代表您的用例的查询。最后,删除不被使用的索引。

欺骗 Postgres 有效地使用特殊索引

排序步骤似乎是昂贵的部分。试试这个替代查询:列表UNION ALL中的每个项目一条腿。IN这向 Postgres 提出了一个它无法拒绝的提议:特殊索引非常适合这个查询。最后的排序步骤对于少数IN物品来说很便宜。

(
SELECT *
FROM   table1
WHERE  col1 = $1 AND col2 = $3
ORDER  BY col3
LIMIT  10
)
UNION  ALL
(
SELECT *
FROM   table1
WHERE  col1 = $3 AND col2 = $4
ORDER  BY col3
LIMIT  10
)
... UNION  ALL ...
ORDER  BY col3
LIMIT  10

请注意,除了最后的和之外,所有括号都需要允许ORDER BY和。LIMITORDER BYLIMIT

于 2014-03-17T19:37:15.977 回答