You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何优化以下UPDATE查询语句以获得更快的执行结果?

优化UPDATE查询性能的实战方案

先别急,我们一步步来拆解和优化这个查询——从理清逻辑歧义到消除性能瓶颈,让你的UPDATE跑得更快:

1. 先修正WHERE子句的逻辑歧义

原语句的WHERE条件TE.vendido = 0 or TE.vendido is null or TE.vendido = 0 and TP.id_ubicacion is null or TE.vendido is null and TP.id_ubicacion is null因为AND优先级高于OR,实际执行逻辑大概率和你预期的不一致。用括号明确分组是关键,假设你的真实需求是:

统计TE.vendido为0或NULL的记录,或者TP.id_ubicacion为NULL时的对应记录

修正后的条件应该是:

(TE.vendido = 0 OR TE.vendido IS NULL) OR TP.id_ubicacion IS NULL

如果你的需求是仅当TE.vendido为0/NULL,同时TP.id_ubicacion可为空,可以调整为:

(TE.vendido = 0 OR TE.vendido IS NULL) AND (TP.id_ubicacion IS NULL OR TP.id_ubicacion IS NOT NULL)

(注:后面的AND条件其实冗余,只是用来演示分组的重要性)

2. 修复子查询的分组错误

原子查询里GROUP BY TP.id但选择TP.codigo1,这会导致同一个codigo1对应多个TP.id时,子查询返回多行重复的codigo1结果,UPDATE时会重复更新同一条TblPartes记录——既浪费性能又可能导致逻辑错误。正确的分组应该是GROUP BY TP.codigo1,因为我们最终是按codigo1更新stock字段。

3. 添加强力索引(性能提升核心)

索引是加速查询的关键,针对这个场景建议创建以下索引:

  • TblExistencias建组合索引:
    CREATE INDEX idx_te_idcodigo_vendido ON TblExistencias(id_codigo, vendido);
    
    这个索引会同时加速JOIN(用到id_codigo)和WHERE过滤(用到vendido)的过程,避免全表扫描。
  • TblPartes建覆盖索引:
    CREATE INDEX idx_tp_id_codigo1_ubicacion ON TblPartes(id, codigo1, id_ubicacion);
    
    覆盖子查询用到的id(JOIN关联)、codigo1(分组和UPDATE关联)、id_ubicacion(WHERE过滤)三个字段,避免数据库频繁回表查询原始数据。

4. 重构后的高效UPDATE语句

结合以上优化点,最终的查询语句如下:

UPDATE TblPartes tp
JOIN (
    SELECT 
        tp_inner.codigo1,
        COUNT(te.id_codigo) AS stock_count
    FROM TblPartes tp_inner
    LEFT JOIN TblExistencias te 
        ON tp_inner.id = te.id_codigo
    WHERE 
        (te.vendido = 0 OR te.vendido IS NULL) 
        OR tp_inner.id_ubicacion IS NULL
    GROUP BY tp_inner.codigo1
) te_summary ON tp.codigo1 = te_summary.codigo1
SET tp.stock = te_summary.stock_count;

额外小技巧(针对MySQL 8.0+)

如果你的数据库支持窗口函数,可以尝试用它替代子查询分组,简化逻辑的同时可能进一步提升性能:

UPDATE TblPartes tp
JOIN (
    SELECT 
        DISTINCT tp_inner.codigo1,
        COUNT(te.id_codigo) OVER (PARTITION BY tp_inner.codigo1) AS stock_count
    FROM TblPartes tp_inner
    LEFT JOIN TblExistencias te 
        ON tp_inner.id = te.id_codigo
    WHERE 
        (te.vendido = 0 OR te.vendido IS NULL) 
        OR tp_inner.id_ubicacion IS NULL
) te_summary ON tp.codigo1 = te_summary.codigo1
SET tp.stock = te_summary.stock_count;

(注意加DISTINCT避免重复更新,实际测试后选择更高效的版本即可)

内容的提问来源于stack exchange,提问作者Martin

火山引擎 最新活动