如何為 SPEED 重寫此查詢或重組我的表
我有一個這種結構的 InnoDB MySQL 表:
它包含對多個服務之一的請求的日誌。它包含約 300 萬行,每月增加約 300 萬行(但如果需要,我會刪除舊數據)。
我正在嘗試生成報告,並獲取在日期範圍內對每個服務發出的請求數。
這是我目前的查詢:
SELECT service, COUNT(*) as lastMonthCount FROM request_logs WHERE datetime > '2021-02-16 10:51:05' GROUP BY service
這可行,但速度非常慢(約 28 秒)。
它輸出這個:
我在
datetime
和上有索引service
。我可以看到它們是 typeBTREE
。我怎樣才能從根本上加快這個查詢,或者重組我的表/索引,以便我可以用另一種方式實現相同的案例?
對於像這樣一個相對簡單的查詢,您無法對其進行優化,因為幾乎沒有更改空間(沒有簡單的方法來詢問該數據)。
您可以通過在
datetime
和service
上設置索引來顯著減少被觸摸的頁面數量。這樣,它需要分組的數據將已經在它讀取的內容中可用,以便在日期執行過濾。這將增加磁碟上的數據量,因為索引會更大,並且出於同樣的原因減慢寫入觸摸。datetime
出於這些原因,您可能希望用新的複合索引替換現有索引,而不是僅僅添加它。關於為什麼這會更快的更多細節:
有了索引
datetime
,它將需要讀取基表數據頁以獲取service
每個匹配行的列,這些行以及由於引用其他結構而讀取的額外頁面可能會讀取更多頁面,因為那些由於每行的數據較大(它們包括 URL 列和您為服務添加或可能已經擁有的任何其他屬性),因此每個頁麵包含的行較少。如果這還不夠快…
您可能需要查看某種形式的記憶體以進行計數。這裡有幾個選項:
- 如果物化視圖在 mysql 中足夠智能,它們可能會起作用
- 有點反規範化,包括在更新主表時由觸發器更新的計數表(這本質上是物化視圖的更“手動”版本)
- 應用程序層中的某些東西,如果您可以忍受結果不一定每次都是 100% 最新的(如果操作正確,是迄今為止最快的選擇,但顯然有這個關鍵缺點)
- 如果數據足夠大以至於查詢每次都從儲存而不是 RAM 讀取,並且您不想使用上述三個選項中的一個/多個:將硬體扔到問題上併購買大量 RAM!(這通常不是一個好的解決方案,儘管有時可以)
不幸的是,與其他現代RDBMS相比,MySQL 的選項有時會受到更多限制。解決您在其他系統中面臨的問題的一種常見方法是使用一種稱為Materialized View的東西。雖然不是 MySQL 的正式功能,但您可以通過一些編碼來複製行為,如使用物化視圖和使用 MYSQL的物化視圖加速 MySQL 中所展示的。
您還可以從這個DBA.StackExchange 答案中找到一些有用的資訊,該答案提供了一些替代方法,例如創建匯總表。當然,這意味著您需要在兩個地方維護數據,但您可以使用Triggers自動執行此操作。
最後,正如我在評論中提示的那樣,如果您的表目前在
datetime
欄位和service
欄位上有兩個單獨的索引,則一次只能使用其中一個索引來為您的查詢提供服務。改進查詢的最佳索引可能涉及創建一個索引,datetime, service
以便在datetime
欄位過濾結果後,它返回的剩餘行已經service
包含索引中的欄位,準備好進行分組。還要在評論中回答您的問題,
VARCHAR(16)
索引不是一個糟糕的數據類型,INT
例如,它只是 4 倍大。我懷疑您會通過更改數據類型看到改變遊戲規則的性能,但是您可以嘗試切換到一個並擁有一個儲存在INT
其中的實際名稱的引用表(與主表的外鍵關係)。您也可以嘗試數據類型,但我個人並不熟悉它,並且聽說過一般建議反對。service``ENUM