精品一区二区三区在线成人,欧美精产国品一二三区,Ji大巴进入女人66h,亚洲春色在线视频

逆天改命!僅一行SQL,查詢時間提速10倍!

數據庫
簡單地重寫 SQL 查詢可以比投入資源解決問題節省更多時間、成本和精力。因此,如果你的應用程序使用基于 OFFSET 的分頁,并且發現速度很慢,我強烈建議切換到鍵集分頁。

這是我們后端團隊的一個故事。

我們當時正在開發一個相當簡單的 API,它可以分頁獲取用戶的交易歷史記錄。非常標準的功能。最初幾個月運行順暢。但隨著數據不斷增長,之前 200 毫秒就能返回結果的查詢……現在需要 2 到 3秒。

起初,我們以為這只是加載問題,或者可能是缺少索引。但在深入挖掘并檢查數據庫執行計劃后,我們發現了一些非常基本且開銷巨大的問題。

這是 OFFSET。

OFFSET 分頁:沉默的殺手

這是我們使用的查詢:

SELECT * FROM transactions
WHERE user_id = 42
ORDER BY created_at DESC
LIMIT 20 OFFSET 10000;

看起來很干凈,對吧?但幕后真正發生的事情是這樣的:

數據庫獲取10,020 行,然后丟棄前 10,000 行,只返回最后 20 行。因此,即使我們只向用戶顯示 20 條記錄,數據庫仍然需要做大量工作。

每次滾動或分頁,OFFSET 都會不斷增加……性能也會持續下降。數據越大,性能越差。

修復:鍵集分頁

在嘗試了一些沒有太大作用的優化之后,我們使用鍵集分頁重寫了查詢,這改變了一切。

新版本的外觀如下:

SELECT * FROM transactions
WHERE user_id = 42
  AND created_at < '2024-05-01 10:00:00'
ORDER BY created_at DESC
LIMIT 20;

因此,我們不會說“跳過前 10,000 行”,而是告訴數據庫:“給我此時間戳之后的接下來的 20 行”。“給我這個時間戳之后的 20 行。”

這稱為搜索分頁或鍵集分頁。

這樣效率更高,因為數據庫不需要掃描和丟棄任何東西。它只需使用索引直接跳轉到正確的位置。

進行此更改后,我們的 API 響應時間從2.6 秒下降到 200 毫秒以下,無需基礎設施更改,無需緩存,只需更智能的 SQL。

我們如何處理重復的時間戳

我們面臨的一個小問題:有時多個交易具有完全相同的created_at時間戳(尤其是當用戶批量上傳數據時)。

當我們僅根據 進行分頁時,這會導致分頁故障,例如重復或跳過行created_at。

因此,我們這樣修復它:

WHERE (created_at, id) < ('2024-05-01 10:00:00', 98765)
ORDER BY created_at DESC, id DESC

通過在和子句中添加決勝因素(id),分頁變得穩定且可預測。ORDER BYWHERE

我們考慮的其他一些方法

雖然鍵集分頁解決了我們的大多數問題,但我們也探索了一些其他想法,每個想法都根據用例有用。

1.基于游標的分頁

這本質上是鍵集分頁,但不是在 API 中傳遞原始時間戳或 ID,而是將它們包裝在游標令牌中,如下所示:

"next_cursor": "2024-05-01T10:00:00Z_98765"

Instagram、Twitter 以及大多數現代 API 正是這樣處理滾動的。它保持了簡潔、無狀態且高效。

2. 僅索引偏移

注意:當你必須使用OFFSET時

在一些內部工具(如管理儀表板)中,我們必須允許跳轉到任何頁面,如第 7 頁或第 10 頁。在這種情況下,鍵集不起作用。

因此我們所做的是:

  • 在查詢中使用的字段上添加覆蓋索引
  • 僅從索引本身中選擇列
CREATE INDEX idx_user_created_id_amount
ON transactions(user_id, created_at DESC, id, amount);transactions(user_id, created_at DESC, id, amount);

這不會使 OFFSET 變得更快,但確實比以前更快了。如果你必須使用 OFFSET,這是最省事的方法。

3.物化視圖

注意:對于靜態儀表板

我們的一個報告儀表板不斷地重復執行相同的慢速查詢,每天匯總用戶交易。

我們用物化視圖解決了這個問題:

CREATE MATERIALIZED VIEW user_summary AS
SELECT user_id, DATE(created_at), SUM(amount)
FROM transactions
GROUP BY user_id, DATE(created_at);

我們使用 cron 每隔幾分鐘刷新一次視圖。這使得報告更加快速,并減少了實時表格的負載。使用 cron這使得報告更加簡潔,并減少了實時表的負載。

修復后的實際結果

以下是每次改進后查詢時間的變化情況:

查詢類型平均響應時間OFFSET 10000~2600 msOFFSET + 索引~1300 ms鍵集/查找方法~180 ms鍵集 + 游標標記~190 ms物化視圖~50–100 ms

我們并沒有想到僅僅改變 SQL 樣式就會帶來如此巨大的差異,但事實是它確實產生了巨大的影響。

最后的想法

這次經歷提醒我們,性能并不總是需要大的改變或昂貴的升級。

有時,簡單地重寫 SQL 查詢可以比投入資源解決問題節省更多時間、成本和精力。

因此,如果你的應用程序使用基于 OFFSET 的分頁,并且發現速度很慢,我強烈建議切換到鍵集分頁。

它簡單、優雅、高效。

責任編輯:龐桂玉 來源: dbaplus社群
相關推薦

2021-05-24 10:46:18

Python字典開發

2023-03-16 16:18:09

PyTorch程序人工智能

2023-08-14 07:42:01

模型訓練

2025-03-31 00:00:01

2016-10-08 16:02:37

WIFIMegaMIMO系統

2019-12-25 14:08:50

Pandas數據計算

2013-09-24 09:40:41

Java圖形加速

2020-07-20 09:20:48

代碼geventPython

2023-01-12 08:07:03

Python代碼版權

2016-02-18 09:36:52

光纖wifi

2020-08-12 14:54:00

Python代碼開發

2022-06-27 08:42:05

代碼sklearn機器學習

2022-08-31 15:57:11

程序員

2021-02-17 13:20:51

forpandas語言

2018-07-06 10:49:01

數據

2016-12-02 08:53:18

Python一行代碼

2020-04-10 15:20:40

數據庫SQL索引

2023-12-11 15:40:32

PyTorch代碼大模型

2021-05-28 07:39:17

SQL代碼操作

2024-03-12 09:29:21

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 布尔津县| 弥渡县| 洮南市| 龙游县| 贵南县| 子长县| 财经| 公主岭市| 扶余县| 阳城县| 沁阳市| 和林格尔县| 云安县| 乌兰察布市| 夏津县| 云林县| 桦甸市| 南靖县| 宁乡县| 遂溪县| 城口县| 三河市| 睢宁县| 武义县| 武强县| 台北市| 吉隆县| 孝昌县| 灵寿县| 禄丰县| 阳谷县| 佛教| 靖西县| 呼玛县| 容城县| 江山市| 钟山县| 浦县| 筠连县| 攀枝花市| 景东|