数据库连接+查询优化

数据库连接+查询优化

Prompt------❤️

创建表

复制代码
你是一个DBA,Database Administrator
这个是两个表的ddl语句,临时表的字段都是从里面提取到的,所以可以按照之前的属性值,约束,但是您需要考虑一下,新建的表的索引是否需要变更呢?
请你模仿上方已有的两个数据表的定义,帮我设计一个数据库表ads_rb_alert_record吧,设置相应的索引,以及字段的属性值以及字段约束条件
如果两个表中已有的,按照之前的定义,如果新增加的,考虑一下是否需要修改默认值不为null,因为null可能会造成索引实效的问题,谢谢您
使用场景:
包括但是不限于的字段:

数据库的相关的操作

连接

别样的语法

python 复制代码
passwd = quote_plus("C@safsdvscd_")
DB_CONNECT_STRING = f"mysql+mysqldb://ai_test:{passwd}@10.11.39.11:11422/ai_delivery?charset=utf8"

Adminer

Database management in a single PHP file

Adminer is available for: MySQL, MariaDB, PostgreSQL, CockroachDB, SQLite, MS SQL, Oracle. Others can be added via plugin: Elasticsearch, SimpleDB, MongoDB, Firebird,

对于本地安装,前提需要配置好一个支持 PHP 模块的 Web 服务器,例如 Apache httpd。然后在 Adminer 官方网站下载相应的 php 文件到服务器根目录下即可

辨析

数据库要允许没有主键的表

有时候,应用程序会在数据层面保证数据的完整性,而不是依赖数据库层面的主键约束。这样做的原因可能是为了更好地控制数据逻辑和业务流程。在这种情况下,数据库允许没有主键的表存在,将完整性的责任交给了应用程序

InnoDB对聚簇索引处理如下:

  • 如果定义了主键,那么InnoDB会使用主键作为聚簇索引
  • 如果没有定义主键,那么会使用第一非空的唯一索引(NOT NULL and UNIQUE INDEX)作为聚簇索引
  • 如果既没有主键也找不到合适的非空索引,那么InnoDB会自动生成一个不可见的名为ROW_ID的列名为GEN_CLUST_INDEX的聚簇索引,该列是一个6字节的自增数值,随着插入而自增

外键一定是另一个表的主键

外键约束并不仅仅可以与另一张表的主键约束相连接,还可以定义为引用另一张表的UNIQUE约束

内存表和临时表

概念

临时表用来给复杂查询保存中间结果,分为内部临时表和外部临时表。

内部临时表:MySQL 内部生成,比如 union 语句、group by 语句可以保存中间结果;

外部临时表:由客户端创建,SQL 语法:CREATE TEMPORARY TABLE。

内存表是指使用 Memory 存储引擎的表,创建语句如下:

复制代码
create table test_memory(`id` int, `a` VARCHAR(20) DEFAULT NULL, PRIMARY KEY (`id`)) engine=Memory;
生命周期
  • 内存表可以给所有客户端看到,客户端连接关闭后不影响内存表。但如果 MySQL 重启服务,内存表的数据会丢失,表结构还在。
    可以看到,临时表也可以是内存表。
  • 临时表是会话级别的,客户端连接关闭后,临时表自动删除。同时,会话之间的临时表是相互隔离的,不同会话可以创建相同名称的临时表。

内存表则不受会话的影响,只有使用 drop 才能删除掉。

truncate、delete和drop的区别

视图

🧩 注意事项

  • ✅ 1. 视图不会自动刷新

  • 视图是一个 虚拟表,每次查询它都会重新执行内部 SQL。

  • 如果底层数据变化,下一次查询就会看到新结果。

  • 不需要手动刷新,但性能取决于底层查询。

  • ✅ 2. 性能问题(最常见)

  • 两个表都很大 → 查询慢

  • 解决方案:

    • 添加索引(强烈建议)

建议添加以下索引:

sql 复制代码
-- 对 ads_module_rb_info 建索引
ALTER TABLE ads_module_rb_info ADD INDEX idx_module_hi_group (module, hi_group);
ALTER TABLE ads_module_rb_info ADD INDEX idx_update_time (update_time);
ALTER TABLE ads_module_rb_info ADD INDEX idx_icode_rb_status_module (icode_path, rb_name, status, module);

-- 对 ads_rb_cd_stage_record 建索引
ALTER TABLE ads_rb_cd_stage_record ADD INDEX idx_module_name_stage (module_name, stage);
ALTER TABLE ads_rb_cd_stage_record ADD INDEX idx_rb_name_module (rb_name, module_name);

⚠️ 特别注意:GROUP BY rb_name, module_name 是消耗较大的操作,必须靠索引加速

  • ✅ 3. 字段顺序与命名一致性

  • 为了便于使用,建议保持字段顺序一致

  • 如果你未来要导出到报表系统,建议命名规范,比如:

    • cd_update_time 明确表示"CD 更新时间"
    • 避免使用 update_time 重复(主表和子表都有)
  • ✅ 4. 安全性 & 权限

  • 创建视图需要 CREATE VIEW 权限

  • 使用者需要对 ads_module_rb_infoads_rb_cd_stage_recordSELECT 权限

  • 你可以通过 GRANT 授权给特定用户:

sql 复制代码
GRANT SELECT ON v_ads_rb_cd_stage TO 'user'@'host';
  • ✅ 5. 视图不能独立于原始表存储数据

  • 视图只是 SQL 查询的封装,不保存任何数据

  • 所有计算在运行时完成

  • ✅ 6. 使用限制(MySQL 特性)

特性 说明
支持 CTE? 不支持(除非 MySQL 8+)
支持子查询? ✅ 支持
支持 LIMIT ❌ 视图本身不能有 LIMIT,但可以写在查询上
支持 ORDER BY ✅ 允许,但查询时仍需加 ORDER BYLIMIT

📈 如何测试视图?------❤️

    1. 创建视图后,测试是否正常:
sql 复制代码
-- 查看视图结构
DESCRIBE v_ads_rb_cd_stage;

-- 查询前几条
SELECT * FROM v_ads_rb_cd_stage LIMIT 10;
    1. 测试性能(加入 EXPLAIN):
sql 复制代码
EXPLAIN SELECT * FROM v_ads_rb_cd_stage ORDER BY update_time DESC LIMIT 200;

🔍 检查:

  • 是否走索引?
  • 是否出现 Using temporary; Using filesort

插入操作 失败 也会造成 主键 的自动增长

  • MYSQL不保证AUTO_INCREMENT依次增长(1,2,3,4,5),但是可以保证正向增长(1,3,5,9)所以,当你某次操作失败后,下次AUTO_INCREMENT就不是顺序的了
  • 解决的办法:
  • Mysql主键如果在insert插入时有值,将不使用自增。也就是说插入数据的时候只要自己把ID加上就按照插入的数进行自增了,这个数通过自己的逻辑判断代码来赋值 ,只要ID不重复就可以了
    -每次插入前查询最大ID,然后加1再作为ID插入

综合案例

prompt

复制代码
你是一个数据库设计师
这里有两个表
CREATE TABLE `ads_module_rb_info` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `icode_path` varchar(255) NOT NULL COMMENT '代码库',
    `module` varchar(64) DEFAULT '' COMMENT '模块名',
    `rb_name` varchar(255) NOT NULL COMMENT 'rb名称',
    `rb_time` DATE NOT NULL COMMENT 'rb拉出来的时间(作为rb日)',
    `create_rb_time` datetime DEFAULT NULL COMMENT '拉出rb的时间,精确到秒',
    `revision` varchar(255) NOT NULL COMMENT '基于哪个commit拉取的分支',
    `status` tinyint(2) NOT NULL COMMENT '0未拉出,1有风险,2已拉出',
    `merge_status` tinyint(2) NOT NULL COMMENT '是否合回去主干0否 1是',
    `risk_message` text NOT NULL COMMENT 'rb风险信息',
    `rd_owner` varchar(32) DEFAULT NULL COMMENT '当前rb的研发负责人,取的拉rb时候最后一个commit研发',
    `qa_owner` varchar(32) DEFAULT NULL COMMENT '值班qa',
    `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `relation_story_list` varchar(1024) NOT NULL DEFAULT '' COMMENT '当前rb关联的项目',
    `relation_revision_list` text NOT NULL COMMENT '当前rb关联的commitid',
    `relation_master_number` int(11) DEFAULT NULL COMMENT '当前rb关联的master build_number',
    `rb_stage` int(11) DEFAULT '0' COMMENT 'rb当前到达哪个阶段 0RB拉出阶段, 1RB测试阶段,2RB发布阶段,3set base阶段,4实验CR阶段,5实验quick阶段,6实验部署阶段,7实验确认阶段,8推全CR阶段,9推全quick阶段,10上线完成阶段',
    `operator_user` varchar(64) DEFAULT NULL COMMENT '实验确认操作人',
    `operator_time` datetime DEFAULT NULL COMMENT '实验确认时间',
    `succ_process` varchar(32) DEFAULT NULL COMMENT '实验确认类型',
    `hi_group` varchar(32) DEFAULT NULL COMMENT '群组',
    `hi_token` varchar(512) DEFAULT NULL COMMENT '群机器人',
    PRIMARY KEY (`id`),
    UNIQUE KEY `icode_path_rb_name_status_module` (
        `icode_path`,
        `rb_name`,
        `status`,
        `module`
    ),
    KEY `icode_path` (`icode_path`),
    KEY `update_time` (`update_time`),
    KEY `status` (`status`),
    KEY `rb_name` (`rb_name`)
) ENGINE = InnoDB AUTO_INCREMENT = 1659549 DEFAULT CHARSET = utf8
第二个:
CREATE TABLE `ads_rb_cd_stage_record` (
    `icode_path` varchar(255) NOT NULL COMMENT '代码库',
    `module_name` varchar(32) DEFAULT NULL COMMENT '模块名',
    `rb_name` varchar(255) NOT NULL COMMENT 'rb分支名',
    `stage` tinyint(4) NOT NULL COMMENT '阶段名称 0RB拉出阶段, 1RB测试阶段,2RB发布阶段,3set base阶段,4实验CR阶段,5实验quick阶段,6实验部署阶段,7实验确认阶段,8推全CR阶段,9推全quick阶段,10上线完成阶段',
    `stage_status` tinyint(4) NOT NULL COMMENT '阶段状态0成功,1失败,2运行中',
    `stage_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '达到当前阶段的时间',
    `exempt_user` varchar(255) DEFAULT NULL COMMENT '豁免操作人',
    `exempt_type` tinyint(4) DEFAULT '0' COMMENT '豁免类型,人工豁免0,自动豁免1',
    `reason` varchar(10240) DEFAULT NULL COMMENT '豁免原因',
    `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    UNIQUE KEY `rb_name_stage_module_name` (
        `rb_name`,
        `stage`,
        `module_name`
    ),
    KEY `rb_name` (`rb_name`),
    KEY `module_name` (`module_name`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8

任务一:这里有两个查询,都是成功执行,没有报错
SELECT icode_path, module, rb_name, rd_owner, qa_owner, update_time, rb_stage, hi_group, hi_token

FROM ads_module_rb_info

WHERE module IN ('mixer', 'ranker', 'theseus')

GROUP BY rb_name

ORDER BY update_time DESC

LIMIT 200
SELECT icode_path, module_name, rb_name, MAX(stage) AS cur_stage, stage_status, stage_time, update_time

FROM ads_rb_cd_stage_record

WHERE module_name IN ('mixer', 'ranker', 'theseus')

GROUP BY rb_name

ORDER BY update_time DESC

LIMIT 200
考虑各种结合的可能,保留每个表的所有字段不要结合,给我所有可能合并关联查询的的例子,子查询,关联查询等,我实际运行比较一下选择哪一个
任务2:
ads_rb_cd_stage_record有613262万多条数据,ads_module_rb_info有12802条数据,想一想使用EXISTS_还是_IN_,

answer

你提出的问题非常清晰,目标是将两个表进行关联查询,在满足特定条件(hi_group IS NOT NULL)的基础上,结合 ads_module_rb_infoads_rb_cd_stage_record 的数据 ,并最终返回指定字段,且 limit 200

核心需求总结

  1. ads_module_rb_info 中筛选出:

    • hi_group IS NOT NULL
    • module IN ('mixer', 'ranker', 'theseus')
    • rb_name 分组(用于关联)
    • 返回字段:icode_path, module, rb_name, rd_owner, qa_owner, update_time, rb_stage, hi_group, hi_token
  2. ads_rb_cd_stage_record 中:

    • 根据同一 rb_name 查找
    • rb_name 分组,取 MAX(stage) 作为 cur_stage
    • 同时获取 stage_status, stage_time, update_time
    • module_name IN ('mixer', 'ranker', 'theseus')
  3. 关联条件:ads_module_rb_info.rb_name = ads_rb_cd_stage_record.rb_name AND ads_module_rb_info.module = ads_rb_cd_stage_record.module_name

  4. 比较:ads_module_rb_info.rb_stage == ads_rb_cd_stage_record.cur_stage(即当前阶段是否一致)

  5. 最终结果集:

    • ads_module_rb_info 所有字段(不要丢失)
    • 加上 cur_stage, stage_status, stage_time, update_time(来自 ads_rb_cd_stage_record
    • 结果按 ads_module_rb_info.update_time DESC 排序
    • 限制 LIMIT 200
  6. 注意:不能丢掉任何字段(原表所有字段都保留,但只展示部分字段?)

❓问题:"保留每个表的所有字段不要结合" → 这个表述有点模糊。我理解为:输出的列应该包含两个表中所有相关字段(即不要合并字段名,而是以结构化形式展示),但最终只显示一部分,比如你列出的字段

✅ 方案一:使用 INNER JOIN + 子查询实现分组

这是最直观的方式。

sql 复制代码
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    r.cur_stage,
    r.stage_status,
    r.stage_time,
    r.update_time AS cd_update_time
FROM 
    ads_module_rb_info m
INNER JOIN (
    SELECT 
        rb_name,
        MAX(stage) AS cur_stage,
        stage_status,
        stage_time,
        update_time
    FROM 
        ads_rb_cd_stage_record
    WHERE 
        module_name IN ('mixer', 'ranker', 'theseus')
    GROUP BY 
        rb_name
) r ON m.rb_name = r.rb_name
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND m.rb_stage = r.cur_stage
ORDER BY 
    m.update_time DESC
LIMIT 200;
  • ⚠️ 注意:
  • ads_rb_cd_stage_record 需要根据 module_name 过滤
  • m.moduler.module_name 并未做匹配 ------ 可能会有跨模块错误!
  • 因此必须加上 AND m.module = r.module_name

但这里有个问题:r 是子查询,没有 module_name 字段了

所以我们需要 保留 module_name 在子查询中,否则无法匹配。


✅ 方案二:修正后的 JOIN + 子查询(推荐)

sql 复制代码
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    r.cur_stage,
    r.stage_status,
    r.stage_time,
    r.update_time AS cd_update_time,
    r.module_name AS record_module_name
FROM 
    ads_module_rb_info m
INNER JOIN (
    SELECT 
        rb_name,
        module_name,
        MAX(stage) AS cur_stage,
        stage_status,
        stage_time,
        update_time
    FROM 
        ads_rb_cd_stage_record
    WHERE 
        module_name IN ('mixer', 'ranker', 'theseus')
    GROUP BY 
        rb_name, module_name
) r ON m.rb_name = r.rb_name 
    AND m.module = r.module_name
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND m.rb_stage = r.cur_stage
ORDER BY 
    m.update_time DESC
LIMIT 200;

✅ 优点:逻辑完整,可读性强

✅ 保证了 module 匹配正确

GROUP BY rb_name, module_name 正确,避免多个同名 rb 在不同模块被混淆


✅ 方案三:用 LEFT JOIN + NOT EXISTS(排除不匹配项)

如果你担心某些 rb_nameads_rb_cd_stage_record 中缺失,可以用 LEFT JOIN,然后过滤 cur_stage 不为空的情况:

sql 复制代码
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    r.cur_stage,
    r.stage_status,
    r.stage_time,
    r.update_time AS cd_update_time
FROM 
    ads_module_rb_info m
LEFT JOIN (
    SELECT 
        rb_name,
        module_name,
        MAX(stage) AS cur_stage,
        stage_status,
        stage_time,
        update_time
    FROM 
        ads_rb_cd_stage_record
    WHERE 
        module_name IN ('mixer', 'ranker', 'theseus')
    GROUP BY 
        rb_name, module_name
) r ON m.rb_name = r.rb_name AND m.module = r.module_name
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND m.rb_stage = r.cur_stage
    AND r.cur_stage IS NOT NULL -- 确保有记录
ORDER BY 
    m.update_time DESC
LIMIT 200;

✅ 更安全:允许 ads_module_rb_info 存在而 cd_record 不存在的情况(但会被过滤掉)

✅ 如果无记录,则 r.cur_stageNULL,条件 m.rb_stage = NULL 会失败 → 自动过滤


✅ 方案四:使用 EXISTS 子查询(适合检查存在性)

sql 复制代码
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token
FROM 
    ads_module_rb_info m
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND EXISTS (
        SELECT 1
        FROM ads_rb_cd_stage_record r
        WHERE 
            r.rb_name = m.rb_name
            AND r.module_name = m.module
            AND r.stage = m.rb_stage
    )
ORDER BY 
    m.update_time DESC
LIMIT 200;

✅ 优点:简洁,不需要聚合,仅判断是否存在对应阶段记录

❗ 缺点:无法获取 cur_stage, stage_status, stage_time 等信息

❗ 所以不符合你的第2点"需要获取这些字段"

👉 所以这个方案 只适用于你想知道"是否匹配",而不关心具体状态,不符合要求。


✅ 方案五:先查 ads_rb_cd_stage_record,再关联(反向思路)

sql 复制代码
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    r.cur_stage,
    r.stage_status,
    r.stage_time,
    r.update_time AS cd_update_time
FROM 
    ads_rb_cd_stage_record r
INNER JOIN (
    SELECT 
        icode_path, module, rb_name, rd_owner, qa_owner, update_time, rb_stage, hi_group, hi_token
    FROM 
        ads_module_rb_info
    WHERE 
        hi_group IS NOT NULL
        AND module IN ('mixer', 'ranker', 'theseus')
) m ON m.rb_name = r.rb_name AND m.module = r.module_name
WHERE 
    r.stage = m.rb_stage
    AND r.stage = (SELECT MAX(stage) FROM ads_rb_cd_stage_record WHERE rb_name = r.rb_name AND module_name = r.module_name)
ORDER BY 
    m.update_time DESC
LIMIT 200;

❌ 不可行!因为 r.stage = MAX(stage) 会导致重复计算,而且 MAX(stage) 要求 GROUP BY,不能直接写在 WHERE 中。

❗ 必须提前聚合!

所以应改为:

sql 复制代码
-- 先聚合
WITH max_stages AS (
    SELECT 
        rb_name,
        module_name,
        MAX(stage) AS cur_stage,
        stage_status,
        stage_time,
        update_time
    FROM 
        ads_rb_cd_stage_record
    WHERE 
        module_name IN ('mixer', 'ranker', 'theseus')
    GROUP BY 
        rb_name, module_name
)
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    s.cur_stage,
    s.stage_status,
    s.stage_time,
    s.update_time AS cd_update_time
FROM 
    ads_module_rb_info m
INNER JOIN 
    max_stages s ON m.rb_name = s.rb_name AND m.module = s.module_name
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND m.rb_stage = s.cur_stage
ORDER BY 
    m.update_time DESC
LIMIT 200;

✅ 这是最高效、最易维护的方式之一(CTE + JOIN)

✅ 性能好:预处理 max_stages,避免重复计算


✅ 方案六:纯子查询(不推荐,性能差)

sql 复制代码
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    (
        SELECT MAX(stage)
        FROM ads_rb_cd_stage_record r2
        WHERE r2.rb_name = m.rb_name AND r2.module_name = m.module
    ) AS cur_stage,
    (
        SELECT stage_status
        FROM ads_rb_cd_stage_record r2
        WHERE r2.rb_name = m.rb_name AND r2.module_name = m.module AND r2.stage = (
            SELECT MAX(stage) 
            FROM ads_rb_cd_stage_record r3 
            WHERE r3.rb_name = m.rb_name AND r3.module_name = m.module
        )
    ) AS stage_status,
    (
        SELECT stage_time
        FROM ads_rb_cd_stage_record r2
        WHERE r2.rb_name = m.rb_name AND r2.module_name = m.module AND r2.stage = (
            SELECT MAX(stage) 
            FROM ads_rb_cd_stage_record r3 
            WHERE r3.rb_name = m.rb_name AND r3.module_name = m.module
        )
    ) AS stage_time,
    (
        SELECT update_time
        FROM ads_rb_cd_stage_record r2
        WHERE r2.rb_name = m.rb_name AND r2.module_name = m.module AND r2.stage = (
            SELECT MAX(stage) 
            FROM ads_rb_cd_stage_record r3 
            WHERE r3.rb_name = m.rb_name AND r3.module_name = m.module
        )
    ) AS cd_update_time
FROM 
    ads_module_rb_info m
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND m.rb_stage = (
        SELECT MAX(stage)
        FROM ads_rb_cd_stage_record r
        WHERE r.rb_name = m.rb_name AND r.module_name = m.module
    )
ORDER BY 
    m.update_time DESC
LIMIT 200;

❌ 严重性能问题:每行都要执行多次子查询,N 行 ≈ N×3+N×3... 太慢!

⛔️ 绝对不要用这种方案


✅ 推荐方案总结(按优先级排序)

方案 名称 优点 缺点 建议
✅ 1 CTE + JOIN 性能好,可读性强,支持复杂逻辑 需要 MySQL 8+(支持 CTE) ✅ 强烈推荐
✅ 2 子查询 + INNER JOIN 通用性强,MySQL 5.7 支持 代码较长 ✅ 推荐
⚠️ 3 LEFT JOIN 安全性高,容忍缺失 可能出现 null 导致性能下降 可选
❌ 4 EXISTS 简洁 无法获取状态字段 ❌ 不符合需求
❌ 5 子查询嵌套 不可维护 极其低效 ❌ 绝对不要

✅ 最终推荐 SQL(CTE + JOIN,适用于 MySQL 8+)

sql 复制代码
WITH latest_stages AS (
    SELECT 
        rb_name,
        module_name,
        MAX(stage) AS cur_stage,
        stage_status,
        stage_time,
        update_time
    FROM 
        ads_rb_cd_stage_record
    WHERE 
        module_name IN ('mixer', 'ranker', 'theseus')
    GROUP BY 
        rb_name, module_name
)
SELECT 
    m.icode_path,
    m.module,
    m.rb_name,
    m.rd_owner,
    m.qa_owner,
    m.update_time,
    m.rb_stage,
    m.hi_group,
    m.hi_token,
    s.cur_stage,
    s.stage_status,
    s.stage_time,
    s.update_time AS cd_update_time
FROM 
    ads_module_rb_info m
INNER JOIN 
    latest_stages s ON m.rb_name = s.rb_name AND m.module = s.module_name
WHERE 
    m.hi_group IS NOT NULL
    AND m.module IN ('mixer', 'ranker', 'theseus')
    AND m.rb_stage = s.cur_stage
ORDER BY 
    m.update_time DESC
LIMIT 200;

📊 测试建议

  1. 分别运行以上三个推荐方案(CTE, 子查询 JOIN, LEFT JOIN)
  2. 使用 EXPLAINEXPLAIN FORMAT=JSON 查看执行计划
  3. 检查:
    • 是否走索引(尤其是 rb_name, module, update_time
    • 是否有 Using temporary; Using filesort
    • 查询时间(秒级 vs 分钟级)
  4. 如果数据量大(百万级),建议增加索引优化

💡 索引建议(提升性能)

你现在已有以下索引,建议补充或验证:

sql 复制代码
-- 索引优化建议
ALTER TABLE ads_module_rb_info ADD INDEX idx_module_hi_group (module, hi_group);
ALTER TABLE ads_module_rb_info ADD INDEX idx_update_time (update_time);
ALTER TABLE ads_module_rb_info ADD INDEX idx_icode_rb_status_module (icode_path, rb_name, status, module);

-- 对于 ads_rb_cd_stage_record
ALTER TABLE ads_rb_cd_stage_record ADD INDEX idx_module_name_stage (module_name, stage);
ALTER TABLE ads_rb_cd_stage_record ADD INDEX idx_rb_name_stage (rb_name, stage);

✅ 特别注意:GROUP BY rb_name, module_name 需要 (rb_name, module_name) 索引才能高效执行

相关推荐
倔强的石头_20 小时前
【金仓数据库】ksql 指南(六)—— 创建与管理用户和权限(KingbaseES 安全控制核心)
数据库
小熊officer21 小时前
Python字符串
开发语言·数据库·python
渐暖°21 小时前
JDBC直连ORACLE进行查询
数据库·oracle
萧曵 丶1 天前
Next-Key Lock、记录锁、间隙锁浅谈
数据库·sql·mysql·mvcc·可重复读·幻读
做cv的小昊1 天前
【TJU】信息检索与分析课程笔记和练习(7)数据库检索—Ei
数据库·笔记·学习·全文检索
zgl_200537791 天前
ZGLanguage 解析SQL数据血缘 之 标识提取SQL语句中的目标表
java·大数据·数据库·数据仓库·hadoop·sql·源代码管理
莳花微语1 天前
记录一次OGG进程abended,报错OGG-01431、OGG-01003、OGG-01151、OGG-01296问题的处理
数据库·sql·mysql
尋有緣1 天前
力扣1355-活动参与者
大数据·数据库·leetcode·oracle·数据库开发
萧曵 丶1 天前
MySQL三大日志系统浅谈
数据库·sql·mysql