sql拆解升级

一、代码审查、团队有个小伙子写的sql,真的头大

SELECT
    id,
    tenant_id,
    store_id,
    esp_org_id,
    ifd_id,
    dim_dish_id,
    standard_price,
    valuation_type,
    weight_type,
    portion_weight,
    first_validate_time,
    create_time,
    update_time
FROM dwd_ifd_goods_standard_prices AS t
WHERE
    t.ifd_id = 'bcc3d3e10e11ffbf6a61a3a675bf77'
    AND t.id = IFNULL(
        -- 子查询1:找<=指定时间的最新一条
        (SELECT s1.id
         FROM dwd_ifd_goods_standard_prices s1
         WHERE ((s1.tenant_id = t.tenant_id) OR (s1.tenant_id IS NULL AND t.tenant_id IS NULL))
           AND s1.first_validate_time <= '2026-04-09 14:47:06.748'
           AND s1.ifd_id = t.ifd_id
         ORDER BY s1.first_validate_time DESC
         LIMIT 1),
        -- 子查询2:找>指定时间的最早一条
        (SELECT s2.id
         FROM dwd_ifd_goods_standard_prices s2
         WHERE ((s2.tenant_id = t.tenant_id) OR (s2.tenant_id IS NULL AND t.tenant_id IS NULL))
           AND s2.first_validate_time > '2026-09 14:47:06.748'
           AND s2.ifd_id = t.ifd_id
         ORDER BY s2.first_validate_time ASC
         LIMIT 1)
    );

二、SQL 功能说明(你必须知道)

这条 SQL 的核心作用:

  1. ifd_id + tenant_id 分组
  2. 先找 生效时间 ≤ 指定时间最新一条价格
  3. 找不到就找 生效时间 > 指定时间最早一条价格
  4. 最终只返回这一条匹配的价格数据

三、性能问题分析(原 SQL 致命缺陷)

  1. 相关子查询:每扫描一行主表数据,就执行 2 次子查询,数据量大时极慢
  2. NULL 判断冗余(a=b or (a is null and b is null)) 可以用 MySQL 安全等于 <=> 简化
  3. 无索引:全表扫描,百万级数据直接卡死

四、最优优化方案(推荐直接使用)

1. 优化后 SQL(简洁 + 高效)

SELECT
    id,
    tenant_id,
    store_id,
    esp_org_id,
    ifd_id,
    dim_dish_id,
    standard_price,
    valuation_type,
    weight_type,
    portion_weight,
    first_validate_time,
    create_time,
    update_time
FROM dwd_ifd_goods_standard_prices
WHERE
    ifd_id = 'bcc3d3e10e11ffbf6a61a3a675bf77'
    AND tenant_id <=> NULL
ORDER BY
    -- 先按时间倒序(取<=时间的最新)
    (first_validate_time <= '2026-04-09 14:47:06.748') DESC,
    first_validate_time DESC,
    -- 找不到再按时间正序(取>时间的最早)
    first_validate_time ASC
LIMIT 1;

2. 必加索引(性能提升 100 倍 +)

CREATE INDEX idx_ifd_tenant_time ON dwd_ifd_goods_standard_prices (ifd_id, tenant_id, first_validate_time);

五、优化点总结

  1. 去掉相关子查询:从 O (n) 复杂度降到 O (1)
  2. 用 <=> 替代 NULL 复杂判断:代码更简洁,数据库优化器能命中索引
  3. 一条 ORDER BY + LIMIT 实现逻辑:数据库一次排序即可拿到目标数据
  4. 组合索引ifd_id + tenant_id + first_validate_time 完美覆盖查询条件

直接使用【优化后 SQL + 索引】,性能和可读性都达到最优

#研发##数据人的面试交流地##春招至今,你收到几个面试了?#
全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务