簡體   English   中英

MySQL 貨量有限、人流量大的預訂數據庫查詢設計

[英]MySQL query design for booking database with limited amount of goods and heavy traffic

我們正在運行一個預訂鮭魚捕撈許可證的網站。 該站點一年 364 天處理流量都沒有問題。 第 365 天是許可證銷售開始的時間,這就是問題發生的地方。 由於流量增加,服務器每年都在掙扎,我們必須進一步優化我們的預訂查詢。

許可證分為許多不同的類型( tbl_license_types ),每種許可證類型都連接到一個或多個釣魚區( tbl_zones )。

每個許可證類型都可以有一個季節性配額,這是一個設置為 tbl_license_types 中的tbl_license_types字段的單個值。

每個區域可以有每日配額、每周配額和季節性配額。 每日配額所有天都一樣,季節性配額當然是單個值。 因此,每日和季節性是 tbl_zones 中的tbl_zones字段。 然而,每周配額因周而異,因此在單獨的tbl_weekly_quotas中指定。

預訂可以是一個或多個連續日期,但僅在tbl_shopping_cart (和tbl_bookings )中表示為From_dateTo_date 對於用戶進行的每次預訂嘗試,必須根據tbl_shopping_carttbl_bookings中已允許的預訂來檢查配額。

為了能夠按日期計數/分組,我們使用一個名為view_season_calendar的視圖,其中包含當前季節的所有日期的單列。

一開始我們使用了一個事務,我們首先進行查詢來檢查配額,如果配額允許,我們將使用第二個查詢將預訂插入tbl_bookings

然而,在相對中等的流量下會產生很多死鎖,因此我們將其重新設計為單個查詢(偽代碼):

INSERT INTO tbl_bookings (_booking_)
WHERE _lowest_found_quota_ >= _requested_number_of_licenses_

其中_lowest_found_quota_是約 330 行長的 SELECT ,其中包含多個子查詢並且相關表被多次連接以檢查所有配額。

示例:用戶想要從 2020 年 5 月 19 日到 2020 年 5 月 25 日為區域 5 和 6 預訂許可證類型 A。 系統需要

  • 將以前的許可證類型 A 預訂與許可證類型 A 季節性配額相比較。
  • 根據 5 區每日配額計算 6 個日期中每個日期在 5 區的先前預訂。
  • 6區的計數相同。
  • 根據 5 區的每周配額,計算日期所在的兩周內每周在 5 區的預訂。
  • 6區的計數相同。
  • 根據 5 區的季節性配額計算當前季節在 5 區的所有先前預訂。
  • 6區的計數相同。

如果所有都在配額之內,請插入預訂。

正如我所說,這在早些時候運行良好,但由於更高的流量負載,我們現在需要進一步優化此查詢。 我對如何做到這一點有一些想法;

  1. 在每個預訂上使用隔離級別READ UNCOMMITTED ,直到請求的區域/許可證類型的配額幾乎已滿,然后回退到默認的REPEATABLE READ 只要配額還剩很多,計數就不需要 100% 正確。 這將大大減少鎖等待和死鎖,對吧?
  2. 創建一個或多個視圖來記錄每個日期、周、區域和許可證類型的所有預訂,然后在插入的 WHERE 子句中使用這些視圖。
  3. 如果執行 nr 2,請在視圖中使用READ UNCOMMITTED 如果視圖報告相關配額接近滿,請取消插入並使用我們今天使用的設計開始一個新的。 (希望流量水平在配額滿之前下降)

對於如何盡可能高效地完成查詢,我將不勝感激。

  • 看看你是否可以在賽季開始前一天開始升級 AWS,然后在高峰期之后降級。 為可能帶來很大的性能提升付出的代價很小。

  • 而不是用於計數的長而復雜的查詢,而是在您 go 時減少一些計數器。 (這可能有幫助,也可能沒有幫助,所以請嘗試一下。)

  • 您的 web 服務器對其將處理的連接數有一些限制; 限制這一點,而不是讓 2K 用戶進入 MySQL 並相互絆倒。 想想當過道如此擁擠以至於沒有人完成時,雜貨店是什么樣的!

  • 一定要使用“事務”,但不要讓它們過於寬泛。 如果它們包含太多東西,流量將退化為單個文件(和/或事務將因死鎖而中止)。

  • 在事務之外盡可能多地做——例如收集和檢查用戶名/地址等。如果您在頒發許可證這樣做,請准備好在出現問題時撤消許可證。 (這應該在代碼中完成,而不是通過ROLLBACK

(更多的)

  • VIEWs是語法糖; 它們不提供任何性能或隔離。 OTOH,如果制作“物化”視圖,可能會有一些有用的東西。

  • 長的“歷史列表”是一個潛在的性能問題(尤其是 CPU)。 當大量連接同時處於事務中間時,可能會發生這種情況——每個連接都需要掛在數據集的“快照”上。

  • 盡可能盡快終止交易——即使你轉身開始新的交易。 數據倉庫中的一個示例是在開始主事務之前進行“規范化”。 (可能此示例不適用於您的應用。)

  • 考慮有一個計算配額的后台任務。 希望通過不在事務中進行計算,常規任務可以運行得更快。

  • 預訂行業中使用的一種技術:(這聽起來有點像您的第 1 項。)以最少的鎖定向前推進。 在最后一刻,以最短的交易時間進行預訂並確認房間(飛機座位等)仍然可用。

  • 如果整個任務可以分為(1)讀取一些東西,然后(2)寫入(並重新讀取以驗證該東西仍然可用),那么......如果讀取步驟比寫入步驟重,則添加更多奴隸('副本')並將它們用於讀取步驟。 為寫入步驟保留 Master。 請注意,復制品很容易(且便宜)添加並在短時間內折騰。

每秒速率 = RPS

為您的 AWS 參數組考慮的建議

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 

您會發現這些更改將導致交易更快地完成處理。 如需其他幫助,請查看配置文件、網絡配置文件以獲取聯系信息和免費下載的實用程序腳本以幫助進行性能調整。 在我們的常見問題頁面上,您會找到“問。如何找到不使用索引的 JOINS 或 QUERIES?” 幫助減少 1,173 的 select_scan RPhr。 Com_rollback 平均每 2,700 秒 1 次,通常可以通過維護查詢中的一致讀取順序進行糾正。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM