【发布时间】:2017-07-08 06:10:30
【问题描述】:
问题总结
这是一个关于 SQL 事务中查询的可序列化的问题。
具体来说,我使用的是 PostgreSQL。可以假设我使用的是最新版本的 PostgreSQL。根据我的阅读,我相信用于支持我正在尝试做的事情的技术被称为“多版本并发控制”或“MVCC”。
总结一下:如果我有一个主表,并且有多个外键链接表连接到该主表,我如何保证,对于表中的给定键,以及任何数字在一个事务中使用该键的 SELECT 语句,每个语句都从任何链接表中进行 SELECT,我将获取启动事务时存在的数据?
其他问题
这个问题类似,但范围更广,问题和答案并没有专门与 PostgreSQL 相关: Transaction isolation and reading from multiple tables on SQL Server Express and SQL Server 2005
示例
假设我有 3 张桌子:
bricks
brickworks (primary key)
completion_time (primary key)
has_been_sold
brick_colors
brickworks (primary key, foreign key pointing to "bricks")
completion_time (primary key, foreign key pointing to "bricks")
quadrant (primary key)
color
brick_weight
brickworks (primary key, foreign key pointing to "bricks")
completion_time (primary key, foreign key pointing to "bricks")
weight
砖厂一次生产一块砖。它在其 4 个象限中的每个象限中制作可能具有不同颜色的砖块。
稍后有人分析积木以确定它们的颜色组合,并将结果写入brick_colors 表。
其他人分析积木以确定其重量,并将结果写入brick_weight 表。
在任何给定时间,现有的砖块可能有也可能没有记录的颜色,可能有也可能没有记录的重量。
应用程序存在,并且该应用程序收到有人想要购买特定砖块的消息(此时应用程序已通过其砖块工厂/completion_time 复合键知道)。
应用程序想要在它开始查询的确切时间选择砖块的所有已知属性。
如果在 MID-TRANSACTION 中添加颜色或重量信息,应用程序不想知道它。
应用程序想要执行 SEPARATE QUERIES(而不是具有多个 JOIN 到外键链接表的 SELECT,这可能会因为 brick_colors 表而返回多行)。
这个例子故意简单;如果我的示例包括 10 个外键链接表,并且它们中的许多或全部可以为同一个主键返回多行(就像 brick_colors 在上面的例子)。
尝试的解决方案
这是我到目前为止的想法:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY ;
-- All this statement accomplishes is telling the database what rows should be returned from the present point-in-time in future queries within the transaction
SELECT DISTINCT true
FROM bricks b
LEFT JOIN brick_colors bc ON bc.brickworks = b.brickworks AND bc.completion_time = b.completion_time
LEFT JOIN brick_weight bw ON bw.brickworks = b.brickworks AND bw.completion_time = b.completion_time
WHERE b.brickworks = 'Brick-o-Matic' AND b.completion_time = '2017-02-01T07:35:00.000Z' ;
SELECT * FROM brick_colors WHERE b.brickworks = 'Brick-o-Matic' AND b.completion_time = '2017-02-01T07:35:00.000Z' ;
SELECT * FROM brick_weight WHERE b.brickworks = 'Brick-o-Matic' AND b.completion_time = '2017-02-01T07:35:00.000Z' ;
COMMIT ;
仅出于确保可序列化的目的而将第一个 SELECT 与 JOIN 一起使用似乎很浪费。
还有其他方法吗?
参考文献
PostgreSQL Concurrency Control
【问题讨论】:
标签: postgresql mvcc