假设我有4个进程,每个进程都会同时将title, url (unique)
的1000条记录插入到blog_posts
表中。部分记录将包含重复的url
。
即使我在插入之前检查记录是否存在,由于进程之间的竞争条件,在每个进程的事务中插入也会失败。每个过程单个质量插入也会失败。我如何使用Postgres快速 ?
我正在考虑将每个进程的记录排队到Redis或其他东西并从那里大量插入它们以防止竞争条件,但我可能还有更好的方法。
答案 0 :(得分:1)
我升级到Postgres v9.5并使用带有ON CONFLICT DO NOTHING
的大量插入,这给了我速度和避免重复的能力。
答案 1 :(得分:0)
我建议的一个可能的解决方案 - 使用临时表,1表示重复数据,2表示过滤它(尽管在某些情况下可能不起作用)。
它也有点冗长,但所有陈述都相当简单,并且很容易将其精确调整到你想要的。
这是一个假设的例子。在这种情况下,我假设我不会操作重复 - 我只想要uniques(基于URL)。我尝试评论步骤,以便更容易看到如何根据需要调整逻辑。
设置临时表并使用任何数据填充它。
--
-- Create temp table, which will store all data, including duplicates.
--
-- DROP TABLE IF EXISTS abc_with_dupes;
--
CREATE TEMP TABLE IF NOT EXISTS abc_with_dupes (
url text NOT NULL,
title text NOT NULL
);
--
-- Create temp table, that will be closer to desired result, with constraints.
--
-- DROP TABLE IF EXISTS abc;
--
CREATE TEMP TABLE IF NOT EXISTS abc (
url text NOT NULL,
title text NOT NULL,
CONSTRAINT abc_pkey PRIMARY KEY (url)
);
--
-- Sample Data, into temp
--
INSERT INTO abc_with_dupes (url, title) VALUES
('http://example.com', 'a'),
('http://example.com', 'b'),
('http://example.ca' , 'c'),
('http://example.us' , 'd'),
('http://example.ru' , 'e');
仅将唯一记录迁移到abc临时表。逻辑将改变取决于重复需要做什么,在这种情况下,简单地忽略。
INSERT INTO abc (url, title) (
SELECT X.url, T.title FROM (
SELECT
url
FROM abc_with_dupes
GROUP BY url
HAVING(COUNT(*)) = 1
) AS X
JOIN abc_with_dupes T USING(url)
);
并检查结果:
--
-- Quick check: Records that ended up under abc temp table - unique.
--
-- ('http://example.ca' , 'c')
-- ('http://example.us' , 'd')
-- ('http://example.ru' , 'e')
--
SELECT * FROM abc;
--
-- Quick check: Records that have duplicate and didn't make to abc temp table
--
-- ('http://example.com', 'a')
-- ('http://example.com', 'b')
--
SELECT T.title, X.url FROM (
SELECT
url
FROM abc_with_dupes
GROUP BY url
HAVING(COUNT(*)) > 1
) AS X
JOIN abc_with_dupes T USING(url)
希望这会在某种程度上有所帮助。