设计基于预订的表的最佳方法

时间:2009-09-22 14:02:07

标签: sql-server locking

我的一个客户有一个基于预订的系统。与航线类似。在MS SQL 2005上运行。

上一家公司设计的方式是将分配创建为一组行。

简单示例:

AllocationId | SeatNumber | IsSold

1234         | A01        | 0

1234         | A02        | 0

在出售座位的过程中,系统会在桌面上建立更新锁定。

我们遇到的问题是锁定过程运行缓慢,我们正在寻找加快速度的方法。

该表已经有效地建立索引,因此我们正在寻找一种加速该过程的硬件解决方案。该表大约有5 mil活动行,位于RAID 50 SAS阵列上。

我假设硬盘搜索时间将是加速更新锁的限制因素,当你有5行的行并且一次更新2-5行时(我可能是错的)。

关于在多个磁盘阵列上使用索引分区的人们,我是否曾尝试加速锁定?任何人都可以给我一些建议,找出可能升级的硬件或我们可以利用什么技术来加速更新锁(不移动到集群)的可能解决方案?

5 个答案:

答案 0 :(得分:0)

我认为你没有从表分区中得到任何东西 - 你得到的唯一改进是从较小(较短)的索引树中读取较少的磁盘(每次读取都会达到索引的每个级别)至少一次,所以读取的速度越快,越少。)但是,我有一个带有4M +行分区的表,索引为4列,净10字节密钥长度。它符合三个指数水平,最高水平为42.6%。假设你有类似的东西,分区可能只从树中移除一个级别似乎是合理的,我怀疑这是一个很大的改进。

一些袖手旁观的想法:

由于奇偶校验计算,Raid 5(和50)在写入时可能会变慢。如果磁盘I / O缓存足够大以处理工作负载,那么问题就不是问题(或者说我已经说过了),但是如果这种问题充满了你可能会想看看raid 10。

将表分区到多个驱动器阵列。使用两个(或更多)Raid阵列,将表分布在卷[文件/文件组,有或没有表分区或分区视图]上,并且您有两倍的磁盘I / O速度,具体取决于数据所在的位置相对于检索它的查询。 (如果阵列#1和阵列#2上的每一个都是空闲的,那么你什么也得不到。)

最糟糕的情况是,可能会出现前沿或尖端技术,这会让你的袜子脱落。如果它对您的业务至关重要并且您已经获得了预算,那么可能值得进行一些认真的研究。

答案 1 :(得分:0)

如何更新锁等待

为什么“表格”上的锁定不仅仅是“”的销售?

  

如果锁定保持的次数超过a   可能的第二个派系   是你的问题。 SqlServer没有   就像你在用户时持有锁   填写网页表格等。

使用SqlServer,您必须自己实施“购物车”,暂时保留座位,直到用户付费为止。例如,添加“IsReserved”和“ReservedAt”colunn,那么任何已保留超过n分钟的座位应自动保留。

这是一个难题,因为购物者不希望有库存的座位出售给他正在结账的其他人。但是,您不知道购物者是否会完成结账。那么如何在UI上显示它呢?考虑看看其他预订网站的内容,然后复制一个用户已经知道如何使用的网站。

(甲骨文有时可以应对长时间保存的锁定,但如果你保持锁定时间短,那么即使是Oracle也会更快更快乐。“

答案 2 :(得分:0)

我首先想弄清楚你为什么要锁定表而不是一行。 要检查的一件事是Update语句的执行计划,以查看它导致更新的索引,然后确保在这些索引上启用了row_level_lock和page_level_lock。 您可以使用以下语句执行此操作。

Select allow_row_locks, allow_page_locks from sys.indexes where name = 'IndexNameHere'

答案 3 :(得分:0)

  

最后一次尝试......

很明显,持有的锁太多了。

  

一旦系统开始减速   由于锁太多,没有   指出开始更多交易。

因此,您应该对系统进行基准测试以找出最佳数量的葡萄干交易,然后使用一些队列系统(或其他方式)来限制葡萄干交易的数量。 Sql Server可能有一些设置(活动连接数等)来帮助,否则你将不得不在你的应用程序代码中写这个。

  

Oracle善于允许reads to bypass writes,但是SqlServer并不像标准版那样......

因此我会将存储过程拆分为使用两个事务,第一个事务应该只是:

  • SNAPSHOT(或READ UNCOMMITTED)交易
  • 找到您要出售的座位的行的“Id”。
  • 然后你应该提交(或中止)这个交易,

并使用第二个(希望非常短)的交易

  • 最喜欢的是READ COMMITTED,(或者可能是SERIALIZABLE)
  • 选择要更新的每一行(使用locking hint
  • 检查它是否同时售出(中止并重新开始,如果有)
  • 在行上设置“IsSold”标志

(您可以使用“in”在单个更新语句中进行上述操作,然后检查预期的行数是否已更新)

对不起,有时您需要了解每次交易的内容以及锁定的详细信息。

  

如果表格较小,那么   更新更短,锁定   保持更短的时间。

因此,请考虑拆分表:

  • 所以你有一个JUST包含“AllocationId”和“IsSold”的表。
  • 此表可以存储为单个btree(AllocationId上的索引组织表)
  • 由于所有其他索引都在桌面上,这些索引不符合座位的详细信息,因此更新不会锁定任何索引。

答案 4 :(得分:0)

以下是一些想法:

  1. 确保您的数据和日志位于不同的主轴上,以最大限度地提高写入性能。
  2. 将驱动器配置为仅使用前30%左右的数据,剩余部分用于备份(最小化搜索/随机访问时间)。
  3. 使用RAID 10作为日志卷;根据需要添加更多主轴(写入性能由日志速度驱动)
  4. 确保您的服务器有足够的RAM。理想情况下,事务开始之前,事务所需的所有内容都应该在内存中,以最大限度地缩短锁定时间(考虑预缓存)。您可以检查一堆性能计数器。
  5. 分区可能会有所帮助,但这在很大程度上取决于您的应用和数据的详细信息......
  6. 我假设已经优化了T-SQL,索引,事务大小等。

    如果有帮助,我会在书中详细讨论这个主题(包括SSD,磁盘阵列优化等) - Ultra-Fast ASP.NET