【问题标题】:Transaction isolation and reading from multiple tables on SQL Server Express and SQL Server 2005SQL Server Express 和 SQL Server 2005 上的事务隔离和读取多个表
【发布时间】:2011-12-09 11:33:05
【问题描述】:

我有一个数据库,其中包含一个主表(我们称之为所有者)和几个包含藏品(如汽车、书籍等)的子表。

例如:

  • Owner 有列:owner_id, name
  • Cars 有列:owner_id (foreign key), brand
  • Books 有列:owner_id (foreign key), title, author

我的程序应该使用各种第三方库计算统计数据,例如 有多少 BMW 车主还拥有一本哈利波特书。我想同时读取所有表中的所有行,然后用非sql代码进行分析。

我想使用单独的Select * From X 语句读取所有表。我不能使用一个大连接,因为它会返回太多行((所有者 * 汽车 * 书籍)而不是(所有者 + 汽车 + 书籍))。联合也不会削减它,因为表包含不同类型的不同列。

我已经设置了

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

但我还是遇到了一些问题。

如果我通过运行两个线程对数据库施加压力,一个随机插入或删除,另一个读取有时会得到不一致的结果,例如在读取 Owners 和读取 Cars 表之间删除了 Cars

我有几个问题:

  1. 从多个表中一一读取时防止修改的正确方法是什么?在读取所有表之前,不得修改任何表。

    我正在使用 SQL Server 2005(网络上)和 SQL Server 2005 Express(本地)。我可以同时显式获取多个表的锁吗?

  2. 如果我针对我的本地 SQL Server Express 数据库运行,无论我做什么都无法让它工作。如果我针对我的联网 SQL Server 2005 数据库运行,我可以使它工作(付出一些努力)。 SQL Server Express 是否支持事务隔离级别 SERIALIZABLE?我相信它应该。差异可能是由于网络连接速度慢,但我不知道。

    在我的本地数据库上,我无法阻止读取之间的修改。也就是说,一个线程正在随机删除一个随机所有者(首先是汽车,然后是书籍,然后是所有者)或插入一个新所有者(插入所有者,插入 2 辆汽车,插入 2 本书)。另一个线程正在阅读使用:

    Begin Tran
    Select owner_id From Owner
    Select owner_id, brand From Cars
    Select owner_id, title, author From Books
    Commit Tran
    

    无论我做什么,有时我都会得到一个拥有零车或零书籍的车主。这绝不应该发生,因为所有插入和删除都在一个事务中。我好像快递服务器没有同时锁定 Owner、Cars 和 Books 语句。

    在联网的 SQL Server 2005 上,它运行良好,但可能是因为连接速度较慢,因此同时执行的可能性较低。

  3. 在我的本地数据库上,我从所有表中使用虚拟 Select 开始每个事务,以防止死锁。我不明白为什么这可以防止死锁但不能修改表。这在联网的 SQL Server 2005 上不是必需的。

目前,我不知道我是否误解了有关事务隔离的某些内容,或者这是否是 SQL Server Express 和 SQL Server 2005 之间差异的问题。任何帮助或见解将不胜感激。

【问题讨论】:

    标签: sql sql-server sql-server-2005 sql-server-2005-express


    【解决方案1】:

    您选择一次性加载所有数据意味着很少的选择:

    • 使用 sp_getapplock 通过相关代码序列化访问
    • 对事务中的读取使用 TABLOCKX、HOLDLOCK

    您遇到问题是因为SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 仅影响锁的隔离:您需要控制持续时间 (HOLDLOCK) 和粒度 + 模式 (TABLOCKX)

    【讨论】:

    • 谢谢,sp_getapplock 似乎有帮助。
    • 我使用了 sp_getapplock 选项,因为它最容易实现。如果其他应用程序修改数据库,它不会保护我,但目前这不是问题。感谢您解释事务隔离的工作原理。
    【解决方案2】:

    我有时会得到不一致的结果,

    除非您稍后会在不使用的数据库上进行批处理,否则最好习惯某些波动,这无论如何都不会重要。

    除非您的条目很少,否则绝对数量的更改不会很重要。无论如何,您都要处理统计数据。使用 READ COMMITED 并通过接受数据集不是静态的来处理不一致的情况。

    其他任何东西都会完全扼杀性能。

    或者去批处理。

    或者:使用 SNAPSHOT 来密封数据库的“及时查看”。

    【讨论】:

    • 其实这很重要。某些组合(例如没有汽车的所有者)永远不会发生,将被视为错误。只要我的快照在内部保持一致,数据是否发生变化都没有关系。
    • 其实没关系。统计不一致是使用统计数据的一部分。当您处理 300.000 个数据点时 - 2 个坏数据点有多重要?一点也不。
    • 某些组合永远不会发生。曾经。如果他们这样做,我们就有一个大问题。获得误报是不可接受的,但错过可能的错误会更糟。所以,这很重要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多