【发布时间】:2015-06-30 16:04:36
【问题描述】:
我目前正在构建一个爬虫。多个爬虫工作人员访问同一个 PostgreSQL 数据库。遗憾的是,我遇到了此处介绍的主要交易的问题:
BEGIN ISOLATION LEVEL SERIALIZABLE;
UPDATE webpages
SET locked = TRUE
WHERE url IN
(
SELECT DISTINCT ON (source) url
FROM webpages
WHERE
(
last IS NULL
OR
last < refreshFrequency
)
AND
locked = FALSE
LIMIT limit
)
RETURNING *;
COMMIT;
-
url是一个 URL(字符串) -
source是域名(字符串) -
last是最后一次抓取页面的时间(日期) -
locked是一个布尔值,设置为指示当前正在抓取网页(布尔值)
我尝试了两种不同的事务隔离级别:
-
ISOLATION LEVEL SERIALIZABLE,我收到类似could not serialize access due to concurrent update的错误 -
ISOLATION LEVEL READ COMMITTED,我从并发事务中得到重复的urls,因为从事务第一次提交时数据被“冻结”(我认为)
总的来说,我对 PostgreSQL 和 SQL 还很陌生,所以我真的不确定我能做些什么来解决这个问题。
更新:
PostgreSQL版本为9.2.x。webpage表定义:
CREATE TABLE webpages (
last timestamp with time zone,
locked boolean DEFAULT false,
url text NOT NULL,
source character varying(255) PRIMARY KEY
);
【问题讨论】:
-
@ErwinBrandstetter:我在查询下方描述了不同隔离级别以及不同列类型和描述的问题。我正在使用 PostgreSQL 9.2。
-
有干净的解决方案,具体取决于具体要求,不清楚。特别是,如果没有解释,这毫无意义:
DISTINCT ON (source) url,也没有ORDER BY。它应该做什么?是否要根据source检索一个(任意)url? -
我想按源分散我发出的请求,以免请求淹没相同的主机。我不使用 ORDER BY 的原因是我需要为每个 url 找到不同的来源,而我没有使用 GROUP BY 的原因是因为我需要返回 url 但这是不可能的,因为如果你GROUP BY 源然后 url 不在 SELECT 中。
-
显示所有约束的实际表定义会有所帮助(psql 中的
\d webpages)。解释也应该在问题中。请编辑以提供完整的图片。您可以使用FOR UPDATE行级锁或咨询锁来解决这个问题,具体取决于整个情况... -
另外,您有单独的
source表吗?
标签: sql postgresql concurrency transactions locking