Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
限量流量预订数据库MySQL查询设计_Mysql_Performance_Isolation Level_Transaction Isolation - Fatal编程技术网

限量流量预订数据库MySQL查询设计

限量流量预订数据库MySQL查询设计,mysql,performance,isolation-level,transaction-isolation,Mysql,Performance,Isolation Level,Transaction Isolation,我们正在运行一个网站,用于预订鲑鱼捕捞许可证。该网站每年处理364天的流量没有问题。第365天是许可证销售开始的时候,这就是问题发生的地方。由于流量增加,服务器每年都在挣扎,我们必须进一步优化预订查询 许可证分为许多不同类型(tbl\u许可证类型),每个许可证类型都连接到一个或多个捕鱼区(tbl\u区域) 每个许可证类型都可以有一个季节配额,这是一个在tbl\u license\u types中设置为整数字段的单个值 每个分区可以有每日配额、每周配额和季节配额。所有日子的每日配额都是相同的,当然

我们正在运行一个网站,用于预订鲑鱼捕捞许可证。该网站每年处理364天的流量没有问题。第365天是许可证销售开始的时候,这就是问题发生的地方。由于流量增加,服务器每年都在挣扎,我们必须进一步优化预订查询

许可证分为许多不同类型(
tbl\u许可证类型
),每个许可证类型都连接到一个或多个捕鱼区(
tbl\u区域

每个许可证类型都可以有一个季节配额,这是一个在
tbl\u license\u types
中设置为整数字段的单个值

每个分区可以有每日配额、每周配额和季节配额。所有日子的每日配额都是相同的,当然,季节配额是单一值。因此,每日和季节是
tbl\u区域中的整数字段。但是,每周配额因周而异,因此在单独的
tbl\u每周配额中指定

预订可以是一个或多个连续的日期,但在
tbl\U购物车
(和
tbl\U预订
)中仅表示为
From\u date
To\u date
)。对于用户的每次预订尝试,必须根据
tbl_购物车
tbl_预订
中已允许的预订检查配额

为了能够按日期进行计数/分组,我们使用一个名为
view\u seasure\u calendar
的视图,其中有一列包含当前季节的所有日期

在开始时,我们使用了一个事务,首先进行查询以检查配额,如果配额允许,我们将使用第二个查询将预订插入
tbl\u bookings

然而,在相对适中的流量下,这会产生很多死锁,因此我们将其重新设计为单个查询(伪代码):

其中,
\u lowest\u found\u quota\u
是一个约330行长的SELECT,包含多个子查询,相关表被多次连接以检查所有配额

示例:用户希望从2020-05-19到2020-05-25为5区和6区预订A类许可证。 系统需要

  • 根据许可证类型A的季节配额统计以前的许可证类型A的预订
  • 根据5区每日配额,统计6个日期中每个日期在5区的先前预订
  • 6区的计数相同
  • 根据5区每周配额,统计5区在该日期所属的两周内之前的预订量
  • 6区的计数相同
  • 根据5区季节配额统计当前季节5区的所有以前预订
  • 6区的计数相同
如果全部在配额内,请插入预订

正如我之前所说的,这很有效,但是由于更高的流量负载,我们现在需要进一步优化这个查询。我对如何做到这一点有一些想法

  • 在每次预订中使用隔离级别
    读取未提交的
    ,直到请求的区域/许可证类型的配额接近满,然后返回默认的
    可重复读取
    。只要配额还有很多,计数就不需要100%正确。这将大大减少锁等待和死锁,对吗
  • 创建一个或多个视图,记录每个日期、星期、区域和许可证类型的所有预订数量,然后在insert的WHERE子句中使用这些视图
  • 如果执行nr 2,请在视图中使用
    readuncommitted
    。如果视图报告相关配额已接近全部,请取消插入,并使用我们今天使用的设计开始新的插入。(希望在配额满之前,流量水平会下降)
  • 我非常希望您能考虑如何尽可能高效地完成查询。

    • 看看是否可以在赛季开始前一天开始升级AWS,然后在高峰过后降级。这是一个很小的代价,可能是一个巨大的性能提升

    • 与其进行冗长复杂的计数查询,不如在运行时减少一些计数器。(这可能会有帮助,也可能不会有帮助,所以不妨尝试一下这个想法。)

    • 您的web服务器对其将处理的连接数有一定限制;限制这一点,而不是让2K用户进入MySQL并彼此绊倒。想想杂货店是什么样子,当过道如此拥挤,以至于没有人能完成

    • 一定要使用“事务”,但不要太宽泛。如果它们包含太多内容,则通信量将退化为单个文件(和/或事务将因死锁而中止)

    • 在事务之外尽可能多地执行操作,例如收集和检查用户名/地址等。如果在颁发许可证后执行此操作,请准备在出现问题时撤消许可证。(这应该在代码中完成,而不是通过
      回滚

    (更多)

    • 视图
      是语法糖;它们不提供任何性能或隔离。哦,如果您创建“物化”视图,可能会有一些有用的东西

    • 一个长的“历史列表”是一个潜在的性能问题(特别是CPU)。这可能发生在大量连接在事务的中间时——每个都需要挂在它的“快照”的数据集上。

    • 在任何可能的情况下,尽可能快地终止事务——即使你转身开始一个新的事务。数据仓库中的一个例子是在开始主事务之前进行“规范化”。(这个例子可能不适用于你的应用程序。)

    • 考虑让一个后台任务计算配额。希望常规任务可以通过不在其事务中进行计算而运行得更快

    • 在预订行业中使用的一种技术:(这听起来有些奇怪
      INSERT INTO tbl_bookings (_booking_)
      WHERE _lowest_found_quota_ >= _requested_number_of_licenses_
      
      innodb_lru_scan_depth=100  # from 1024 to conserve 90% of CPU cycles used for function every second
      innodb_flush_neighbors=2  # from 1 to reduce time required to lower innodb_buffer_pool_pages_dirty count when busy
      read_rnd_buffer_size=128K  # from 512K to reduce handler_read_rnd_next RPS of 3,227
      innodb_io_capacity=1900  # from 200 to use more of SSD IOPS
      log_slow_verbosity=query_plan,explain  # to make slow query log more useful
      have_symlink=NO  # from YES for some protection from ransomware