【发布时间】:2014-09-10 18:18:22
【问题描述】:
我有两张桌子:
account_transaction:
+-------------------------------+--------------------------+------------------------+
| Column | Type | Modifiers |
+-------------------------------+--------------------------+------------------------+
| id | integer | not null |
| account_id | bigint | not null |
| created | timestamp with time zone | not null default now() |
| transaction_type | text | not null |
| amount | numeric(5,2) | not null |
| external_reference_id | character varying(60) | |
+-------------------------------+--------------------------+------------------------+
索引:
"idx_account_transaction_created" btree (created)
reporting_period:
+------------+--------------------------+-----------+
| Column | Type | Modifiers |
+------------+--------------------------+-----------+
| month | text | |
| created | timestamp with time zone | |
| date_range | tstzrange | |
+------------+--------------------------+-----------+
我想获取上一个报告期间的所有交易。这是产生相同结果的两个查询,但一个执行 seq 扫描,另一个可以使用 idx_account_transaction_created 索引。
explain select count(*) from account_transaction where created <@ (select date_range from reporting_period order by created desc limit 1);
+----------------------------------------------------------------------------------------+
| QUERY PLAN |
+----------------------------------------------------------------------------------------+
| Aggregate (cost=4214.81..4214.82 rows=1 width=0) |
| InitPlan 1 (returns $0) |
| -> Limit (cost=13.20..13.20 rows=1 width=40) |
| -> Sort (cost=13.20..13.60 rows=800 width=40) |
| Sort Key: reporting_period.created |
| -> Seq Scan on reporting_period (cost=0.00..12.40 rows=800 width=40) |
| -> Seq Scan on account_transaction (cost=0.00..4200.81 rows=1602 width=0) |
| Filter: (created <@ $0) |
+----------------------------------------------------------------------------------------+
(8 rows)
explain select count(*) from account_transaction where created >= '2014-06-01' and created <= '2014-06-30 23:59:59.999999';
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| QUERY PLAN |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Aggregate (cost=2640.54..2640.54 rows=1 width=0) |
| -> Index Only Scan using idx_account_transaction_created on account_transaction (cost=0.08..2605.77 rows=69535 width=0) |
| Index Cond: ((created >= '2014-06-01 00:00:00+00'::timestamp with time zone) AND (created <= '2014-06-30 23:59:59.999999+00'::timestamp with time zone)) |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
(3 rows)
我更喜欢第一个查询,因为它看起来更容易阅读和理解,而且它只有 1 次往返。第二个效率更高,因为它使用 created 字段上的索引,但这意味着应用程序需要走出去获取最后一个报告期间并获取 date_range 字段的上下边界(不是最糟糕的事情世界)。我想我总是可以把它写成一个函数或一个视图。但是,我有点惊讶 PostgreSQL 没有弄清楚它可以使用索引。我在这里缺少什么吗?有没有办法让第一个查询使用索引?
我使用的是 PostgreSQL 9.3
【问题讨论】:
标签: sql postgresql indexing range postgresql-9.3