我们有一个使用ASP.NET MVC和SQL Server 2008的网站,我们使用的是默认的transactionscope隔离级别,即Serializable。但是如果打开任何事务,它会使应用程序无法使用,因为我们有一个几乎所有东西都使用的表,它就像
一样运行select * from table1 where id = 1
所以我认为在执行上述操作时会锁定整个表格。
我一直在阅读有很多交易的Web应用程序的最佳选择。
我有点在Snapshot隔离级别上出售。哪些方面可以提供最好的一切:
根据您的经验,Web应用程序可以采用哪种隔离级别?
编辑: 默认隔离级别来自transactionscope,只是为了澄清为什么我提到可序列化为默认值。
我在这里阅读了很多博客和答案,建议使用no_lock进行选择,但如果你问我,这就是一种黑客攻击。在现实生活中,可能有99.99%的时间可以。这对Facebook,Twitter或Stack Overflow来说都很好。谁在乎数据是否已损坏。但我的看法是,如果我们使用事务隔离,那么它必须是100%保证架构。否则,根本不要使用它,并使用触发器或其他东西添加一些其他数据完整性检查。
答案 0 :(得分:3)
我认为这个问题可能更适合serverfault.com,这就是我对这个主题的理解:
首先,因为当默认隔离级别变为Serializable时,我认为它是Read Committed!
其次,快照可能不是一个好主意,因为它有效地使用tempdb(大部分位于内存中)来存储数据的并发版本,所以运气好的话,你将用完RAM的内存。 2-3。
第三,序列化级别不是一个全有或全无的努力,而是应该查看每个查询并使用查询提示或其他方式为每个查询设置它。我会说你的魔法选择语句在任何地方都可以使用,甚至可以用(nolock)提示(假设基础表只有99.99%读取; BTW如果你注意到自己做了太多的readonly东西,这表明你应该看进入缓存,无论是本机ASP.NET缓存还是Memcached或其他),其余的可能使用read committed。只有在极少数情况下(例如自动维护的查找表),您才需要高于此值的任何内容。
第四,不要过度使用悲观锁定。更明智的选择是改为乐观锁定,例如:插入希望没有欺骗,然后处理失败的约束和类似的事情。对于更新,您可以添加timestamp列并将其包含在where子句中。如果其他人在您之前劫持了更新,则行数将为0.等等。
希望这是有道理的。
答案 1 :(得分:3)
您应该在数据库中使用read committed snapshot。此隔离级别提供最高程度的并发性,但代价是在更新期间维护版本存储。如果您的应用程序是密集读取而不是oltp密集,那么这种权衡是值得的。
如果在数据库中启用了读提交的快照,则读取通过隔离下的事务将自动使用快照隔离。
可串行隔离级别通常是过度杀伤,真正的性能损失。读提交(simle,没有快照)是好的,但它可能会导致问题,因为它会阻止读取和写入。
答案 2 :(得分:2)
最好的策略之一是Row Versioning。您可以在数据库级别设置此项,如:
ALTER DATABASE YourDatabaseName SET READ_COMMITTED_SNAPSHOT ON;
默认情况下,这基本上是非阻塞读取。另请参阅Row Versioning-based Isolation Levels in the Database Engine。
答案 3 :(得分:1)
一个好的RDBMS只会在发出这样的SELECT时锁定“id = 1”所指示的行,而不是整个表。只要数据库提供合理的行锁定,并且在每个Web请求结束时释放所有挂起的锁,序列化隔离级别就可以了。这通常意味着在请求结束时关闭数据库连接,或者如果要再次为后续请求重新使用连接,则发出ROLLBACK或COMMIT。
答案 4 :(得分:1)
您需要使用read committed
并在应用中执行乐观锁定。在大多数情况下,这似乎更加强大。
还有a look stackoverflow团队如何处理他们的锁定问题。
答案 5 :(得分:0)
我认为最佳隔离级别是快照隔离级别,因为它将读取表中最后保存的数据如果另一个事务未完成且没有锁定且没有脏读取那么我最好使用快照隔离级别比读取提交更好
如何做到这一点 通过两种方式
1-alter database testing set allow_SnapShot_Isolation on; 要么 2-alter database testing set Read_Committed_Snapshot on;
我希望对读者有用 Mahmoud Shahin 埃及 0201288846966