【发布时间】:2014-03-11 02:03:28
【问题描述】:
我有一个幂等后台处理任务,它需要一行信息,进行一些清理并插入数据库。我的问题是相同的信息可能会被多次处理。
为了解决这个问题,我根据每行数据的信息创建了一个键(散列),并在索引上创建了一个唯一约束以防止重复。
问题:我通过以下方式检查数据库中是否已经存在数据:
SELECT key FROM items WHERE key IN (key,key,key,key).
我发现这个查询有点快,但仍然有一些反应慢
SELECT key FROM items WHERE (key = ANY(VALUES(key),(key)))
然后我对返回的键和我期望的键进行交集,只处理不存在的数据。
这一直很好,直到表达到 1 亿以上,我可以一次检查 100 多个键,这会导致大量的 IO 扫描和检索每一行。
我的问题:有没有更有效的方法来使用唯一约束和索引来检查是否存在?也许有些东西实际上并没有到达每一行?
或者,是否有其他可行的方法?简单地尝试插入和捕获唯一约束违规实际上会更快吗?
简化表定义:
Column | Type | Modifiers | Storage | Description
------------------------+-----------------------------+---------------------------------------------------------------+----------+-------------
id | integer | not null default nextval('items_id_seq'::regclass) | plain |
created_at | timestamp without time zone | not null | plain |
updated_at | timestamp without time zone | not null | plain |
key | character varying(255) | | extended |
item_attributes | hstore | | extended |
item_name | character varying(255) | | plain |
Indexes:
"items_pkey" PRIMARY KEY, btree (id)
"index_items_on_key" UNIQUE, btree (key)
还有一个查询计划:
Nested Loop (cost=0.10..108.25 rows=25 width=41) (actual time=0.315..2.169 rows=25 loops=1)
-> HashAggregate (cost=0.10..0.17 rows=25 width=32) (actual time=0.071..0.097 rows=25 loops=1)
-> Values Scan on "*VALUES*" (cost=0.00..0.09 rows=25 width=32) (actual time=0.009..0.033 rows=25 loops=1)
-> Index Scan using index_items_on_key on items (cost=0.00..4.32 rows=1 width=41) (actual time=0.076..0.077 rows=1 loops=25)
Index Cond: ((key)::text = "*VALUES*".column1)
Total runtime: 2.406 ms
【问题讨论】:
-
包括您的表定义,包括索引和理想情况下您正在执行的查询的解释计划。
-
尝试插入并忽略约束违规可能会更干净。它可能不会更快,因为检查约束所需的 IO 会影响执行插入所需的 IO,因此必须以任何一种方式完成。
-
@JustKim 我添加了一个带有索引的表定义。
标签: ruby-on-rails postgresql postgresql-9.1