MySQL大批量IN查詢的優(yōu)化方案
引言
MySQL大批量IN查詢優(yōu)化是一個非常經(jīng)典且棘手的高并發(fā)、大數(shù)據(jù)量場景下的問題。直接使用 WHERE id IN (十萬個ID) 是絕對的下策,會導致性能急劇下降。
本文我將與大家探討最有效、最常用的優(yōu)化方案,并按推薦順序排列。
核心思路
根本問題在于,將一個巨大的列表(10萬個參數(shù))傳遞給SQL語句,會導致數(shù)據(jù)庫解析SQL的耗時極長(語法分析、優(yōu)化)、網(wǎng)絡傳輸壓力大,并且很可能無法有效利用索引。
最佳思路是:將“內(nèi)存計算”轉(zhuǎn)化為“集合聯(lián)接查詢”。
首選舉薦方案:使用臨時表
這是處理此類問題最標準、兼容性最好且效果最顯著的方法。其本質(zhì)是將程序中的ID列表持久化到數(shù)據(jù)庫的一張臨時表中,然后通過高效的表聯(lián)接(JOIN) 來代替低效的 IN 操作。
操作步驟:
創(chuàng)建臨時表:在數(shù)據(jù)庫中創(chuàng)建一張臨時表,通常只包含一個主鍵字段 id (根據(jù)實際情況選擇類型,如 BIGINT UNSIGNED)。使用 CREATE TEMPORARY TABLE 可以避免沖突且會話結束后自動清理。
CREATE TEMPORARY TABLE temp_ids ( id BIGINT UNSIGNED NOT NULL PRIMARY KEY ) ENGINE=Memory;
ENGINE=Memory:建議使用內(nèi)存引擎,數(shù)據(jù)完全存儲在內(nèi)存中,速度極快。如果ID量極大(遠超10萬),可改用InnoDB并添加索引。
批量插入數(shù)據(jù):使用批量插入(Batch Insert)的方式,將你的10萬個ID分批次插入到臨時表中。這是性能關鍵點,絕對不要用10萬條獨立的INSERT語句。
Java (JDBC) 示例:
String sql = "INSERT INTO temp_ids (id) VALUES (?)";
PreparedStatement pstmt = connection.prepareStatement(sql);
for (Long id : hugeIdList) { // hugeIdList 是你的10萬個ID的集合
pstmt.setLong(1, id);
pstmt.addBatch(); // 加入批量操作
// 每1000條或一定數(shù)量執(zhí)行一次,避免批量過大
if (i % 1000 == 0) {
pstmt.executeBatch();
}
}
pstmt.executeBatch(); // 插入最后一批
- 其他語言:同理,找到對應的批量操作方式。
使用JOIN代替IN:改寫原來的SQL語句,用 JOIN 關聯(lián)臨時表。
原SQL:
SELECT * FROM your_table WHERE your_id IN (1, 2, 3, ..., 100000);
優(yōu)化后的SQL:
SELECT t.* FROM your_table t INNER JOIN temp_ids tmp ON t.your_id = tmp.id;
- 如果原表
your_table的your_id字段有索引,這個JOIN操作會非常快,因為它本質(zhì)上是兩個集合的哈希聯(lián)接或索引查找,數(shù)據(jù)庫優(yōu)化器可以高效處理。
優(yōu)點:
- 性能飛躍:避免了超長SQL的解析,利用了索引和高效的集合操作。
- 通用性強:適用于所有版本的MySQL,是標準的SQL用法。
- 資源可控:臨時表(尤其是內(nèi)存臨時表)對系統(tǒng)影響較小。
備選方案:使用內(nèi)聯(lián)值表(MySQL 8.0+ 專屬)
如果你的MySQL版本是8.0或更高,可以使用 JSON_TABLE 或 VALUES 語句來構造一個內(nèi)聯(lián)的表結構。
示例 (使用 JSON_TABLE):
SELECT t.* FROM your_table t JOIN JSON_TABLE( '[1,2,3,...,100000]', -- 這里替換為你的JSON數(shù)組字符串 '$[*]' COLUMNS(id BIGINT PATH '$') ) AS tmp ON t.your_id = tmp.id;
操作步驟:
- 在應用程序?qū)?,?0萬個ID的列表序列化為一個JSON數(shù)組字符串,例如
"[1,2,3,4,5]"。 - 將上述字符串填充到SQL中的
'[1,2,3,...,100000]'位置。 - 執(zhí)行該SQL。
優(yōu)點:
- 無需創(chuàng)建臨時表,一步到位。
缺點:
- 僅限MySQL 8.0+。
- SQL語句本身仍然會非常長(一個包含10萬個數(shù)字的JSON字符串),雖然解析器對JSON的解析可能比解析10萬個逗號分隔的數(shù)字更快,但仍然有網(wǎng)絡傳輸和內(nèi)存消耗的壓力。通常不如臨時表方案穩(wěn)定可靠。
堅決避免的方案
- 拆分多次查詢(如
WHERE id IN (1,2,3...1000),查100次):
缺點:網(wǎng)絡往返次數(shù)(RT)暴增,總耗時可能更長,對應用和數(shù)據(jù)庫都是負擔。
- 手動拼接10萬個參數(shù)的SQL字符串:
缺點:這是問題的根源。數(shù)據(jù)庫解析SQL的CPU消耗巨大,而且可能達到 max_allowed_packet 限制導致失敗。
總結與選擇
| 方案 | 適用場景 | 優(yōu)點 | 缺點 |
|---|---|---|---|
| 臨時表 JOIN | 所有MySQL版本,強烈推薦 | 性能最佳,通用,資源可控 | 需要額外兩次數(shù)據(jù)庫往返(建表+插入) |
| 內(nèi)聯(lián)值表 | MySQL 8.0+ | 單次查詢完成 | SQL長,有潛在性能開銷,版本限制 |
給你的最終建議:
毫不猶豫地選擇【臨時表】方案。 這是經(jīng)過無數(shù)生產(chǎn)環(huán)境驗證的、最有效的處理大批量IN查詢的方法。雖然需要3步操作(建表、批量插入、JOIN查詢),但其整體的性能、穩(wěn)定性和資源消耗遠勝于其他任何方法。
到此這篇關于MySQL大批量IN查詢的優(yōu)化方案的文章就介紹到這了,更多相關MySQL優(yōu)化大批量IN查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SQL?FOREIGN?KEY約束保障表之間關系完整性關鍵規(guī)則詳解
這篇文章主要介紹了SQL?FOREIGN?KEY約束保障表之間關系完整性關鍵規(guī)則詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
weblogic服務建立數(shù)據(jù)源連接測試更新mysql驅(qū)動包的問題及解決方法
WebLogic是用于開發(fā)、集成、部署和管理大型分布式Web應用、網(wǎng)絡應用和數(shù)據(jù)庫應用的Java應用服務器,這篇文章主要介紹了weblogic服務建立數(shù)據(jù)源連接測試更新mysql驅(qū)動包,需要的朋友可以參考下2022-01-01
MySQL5.73?root用戶密碼修改方法及ERROR?1193、ERROR1819與ERROR1290報錯解決
這篇文章主要給大家介紹了關于MySQL5.73?root用戶密碼修改方法及ERROR?1193、ERROR1819與ERROR1290:...?running?with?--skip-...報錯的解決方法,文中通過圖文將解決的步驟介紹的非常詳細,需要的朋友可以參考下2023-02-02

