在 Laravel 或原生 MySQL 开发中,我们经常会用 WHERE IN (...) 来批量查询或更新数据,例如:
$skus = $cnt->pluck('product_sku')->toArray();
$parent_sku_data = DB::table('listings_items')
->where('site', 'Amazon.com')
->whereIn('sku', $skus)
->where('parent_sku', '>', '')
->pluck('parent_sku', 'sku')
->toArray();
但是,如果数据量太大,直接 WHERE IN 会有几个明显问题:
❌ 使用 WHERE IN 的问题
-
SQL 太长
-
参数列表过大时,可能超过 MySQL 的
max_allowed_packet限制,导致执行报错。
-
-
性能差
-
IN 里成千上万个元素时,优化器处理效率低,查询速度明显下降。
-
-
锁风险
-
一次性锁住大量行,容易导致锁等待甚至死锁,尤其是在事务中执行 UPDATE/DELETE 时。
-
🔑 优化方案
1. 分批处理(推荐)
把大数组分成小块,每次执行一次查询或更新。
$skus = $cnt->pluck('product_sku')->toArray();
$parent_sku_data = [];
foreach (array_chunk($skus, 500) as $chunk) {
$res = DB::table('listings_items')
->where('site', 'Amazon.com')
->whereIn('sku', $chunk)
->where('parent_sku', '>', '')
->pluck('parent_sku', 'sku')
->toArray();
$parent_sku_data = $parent_sku_data + $res;
}
✅ array_chunk($skus, 500) 表示每次取 500 个 SKU,避免单次 SQL 过长,提高效率。
2. 用临时表替代 IN
如果要处理的数据量非常大(几十万或百万级),可以先写入 临时表,然后用 JOIN 查询。
CREATE TEMPORARY TABLE tmp_sku_list (sku VARCHAR(50) PRIMARY KEY);
-- 批量插入数据(应用层或脚本里循环插入)
INSERT INTO tmp_sku_list (sku) VALUES ('SKU1'), ('SKU2'), ...;
-- JOIN 查询
SELECT li.sku, li.parent_sku
FROM listings_items li
JOIN tmp_sku_list ts ON li.sku = ts.sku
WHERE li.site = 'Amazon.com' AND li.parent_sku > '';
👉 临时表方式适合 超大数据量场景,避免一次性 IN 导致 SQL 过长和性能下降。
3. 用子查询(数据已在数据库中)
如果 $cnt->pluck('product_sku') 已经是数据库中的表数据,可以直接用子查询替代 IN,避免把大数据拉到 PHP 再传回 SQL:
👉 子查询方式减少 PHP 和数据库之间的数据传输,提高效率。
✅ 总结
| 数据量范围 | 推荐方案 |
|---|---|
| 几百~几千条 | 用 array_chunk 分批 whereIn |
| 几万~几十万条 | 临时表 + JOIN 查询 |
| 数据本身在数据库里 | 用子查询替代 IN |
核心原则:避免一次性锁住过多行,分批处理或用临时表/子查询,提高性能并降低锁风险。
2025-09-11 18:37:15,若文章内容或图片失效,请留言或联系站长反馈!










暂无评论内容