Files
biz-api-cloud-zax/db/20261004_add_wallet_transaction_scope_order_index.sql
T
dzc 940e457930 feat:迁移hard和wallet模块的定时任务
feat:增加订餐预约时间管理
2026-10-08 11:48:24 +08:00

92 lines
6.4 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 20261004 钱包流水表排序索引优化(可重复执行)
-- ⚠️ 本脚本第 4、5 步(前缀索引)已被 20261005_wallet_transaction_biz_type_varchar.sql 接替:
-- biz_type 改为 varchar 后重建为全列索引。线上已执行过 20261005 的环境勿再执行本脚本。
-- 背景:/api/wallet/wallet-transaction/page-all 分页查询很慢;索引生效后发现 page-cz/page-jz 仍慢(3~6s)。
-- 原因:查询固定排序 create_time DESC, user_id DESC, id DESC,
-- 旧索引 (tenant_id, del_flag, create_time DESC, user_id DESC) 末尾隐式追加的主键 id 为 ASC,
-- 与 ORDER BY 最后一段 id DESC 方向不匹配,索引无法提供有序结果,
-- 优化器对租户内全部流水做 filesort(执行计划 Using filesort),数据量越大越慢。
-- 方案:建显式包含 id DESC 的 5 列索引,排序完全走索引,LIMIT 只需读取前 N 条;
-- 旧 4 列索引被新索引前缀完全覆盖,一并删除以降低流水表写入放大。
-- 已在测试库(123.157.250.162:28816/pjcloudx_wallet)验证:四种查询形态(首页/部门权限包裹/业务类型+时间范围/冷门部门)
-- filesort 全部消除;删除旧索引后计划不变。
-- 幂等方式:本环境(OceanBase MySQL 模式)不支持 CREATE INDEX IF NOT EXISTS / DROP INDEX IF EXISTS,
-- 改用 information_schema.statistics 判断索引是否存在后经 PREPARE 动态执行;
-- 已存在/已删除时输出 skip 提示,重复执行无副作用。
-- 执行顺序:在线 DDL 不锁表,可独立执行;若担心流水表写入放大,可只执行第 1、2 步。
USE pjcloudx_wallet;
-- 1. 新建 5 列排序索引(与 Mapper commonWrapperQuery 的 ORDER BY 完全同序)
SET @ddl = IF(
(SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wallet_transaction'
AND index_name = 'idx_wallet_tx_tenant_del_ct_uid_id') = 0,
'CREATE INDEX idx_wallet_tx_tenant_del_ct_uid_id ON wallet_transaction (tenant_id, del_flag, create_time DESC, user_id DESC, id DESC)',
'SELECT ''skip: idx_wallet_tx_tenant_del_ct_uid_id 已存在'' AS msg');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2. 删除被完全覆盖的旧 4 列索引(第 1 步成功后执行)
SET @ddl = IF(
(SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wallet_transaction'
AND index_name = 'idx_wallet_tx_tenant_del_create_user') > 0,
'DROP INDEX idx_wallet_tx_tenant_del_create_user ON wallet_transaction',
'SELECT ''skip: idx_wallet_tx_tenant_del_create_user 不存在'' AS msg');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 3. 部门前置索引:数据权限为"本部门/自定义部门"的操作者,最终 SQL 是外层 dept_id IN (...) 过滤。
-- 部门占比小时按 create_time 顺序扫会翻大量无关行;该索引让优化器按部门范围直取,
-- 部门内排序与索引后缀同序同样免 filesort(已验证:冷门部门走此索引,大部门自动走 5 列索引)。
-- 代价是流水表(高写入)多维护一个二级索引,如写入压力敏感可只执行 1、2 步。
SET @ddl = IF(
(SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wallet_transaction'
AND index_name = 'idx_wallet_tx_tenant_del_dept_ct') = 0,
'CREATE INDEX idx_wallet_tx_tenant_del_dept_ct ON wallet_transaction (tenant_id, del_flag, dept_id, create_time DESC, user_id DESC, id DESC)',
'SELECT ''skip: idx_wallet_tx_tenant_del_dept_ct 已存在'' AS msg');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 4. 业务类型+金额前缀索引:page-cz / page-jz 固定带 biz_type IN ('1','2','3') + price>0 / price<0。
-- biz_type 为 tinytext 无法整列建 B-tree(只能前缀),price 也不在任何索引中,
-- 此前 COUNT 与翻页需对租户内全部行回表校验这两个字段;记账扣款(price<0)仅约 0.5% 行且偏旧,
-- page-jz 首页还要按时间倒序翻过大量支付流水。
-- 本索引把 jz 的 COUNT/翻页访问行数从全租户降到 ~0.5%(测试库 40195→443),cz 同理;
-- 已验证 page-all 仍走 5 列排序索引、page-xf(biz_type='4') 计划不变,无回归。
-- 注:前缀索引仍需回表核对 biz_type 完整值,线上行数放大后 COUNT 预计降至 1s 内。
-- ⚠️ 已知代价(2026-10-04 线上实测):本索引会使优化器把 page-jz 的翻页查询切换为
-- "全量命中集回表+filesort"(无提前终止),jz 从 6s 恶化到 10s;cz/xf 等不受影响。
-- 根因:biz_type 为 tinytext 只能建前缀索引,前缀列的条件不会下推到索引层(ICP),
-- 也永远无法构成覆盖索引,多值 IN(1,2,3) 又无法沿用 biz 前导索引的顺序。
-- 纯索引手段无法同时优化 jz 的 COUNT 与翻页;根治需改代码(UNION 逐 biz_type 等值分支
-- + FORCE INDEX(idx_wallet_tx_biz_ct))或授权将 biz_type 改为 varchar 后建覆盖索引。
SET @ddl = IF(
(SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wallet_transaction'
AND index_name = 'idx_wallet_tx_tenant_del_biz_price') = 0,
'CREATE INDEX idx_wallet_tx_tenant_del_biz_price ON wallet_transaction (tenant_id, del_flag, biz_type(2), price)',
'SELECT ''skip: idx_wallet_tx_tenant_del_biz_price 已存在'' AS msg');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 5. biz 前导有序索引:让单值 biz_type 等值/单元素 IN 的翻页(page-tk 退款/page-th 退还等)
-- 自动走"biz 前缀定位 + 索引序 + price ICP 过滤",跳过无关业务类型的回表;
-- 同时为 page-jz/page-cz 的 UNION 改写(代码修复)预置索引。
-- 注意:本索引对 jz/cz(多值 IN)的翻页无直接改善,仅建议需要提速 tk/th 或配合代码修复时执行。
SET @ddl = IF(
(SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wallet_transaction'
AND index_name = 'idx_wallet_tx_biz_ct') = 0,
'CREATE INDEX idx_wallet_tx_biz_ct ON wallet_transaction (tenant_id, del_flag, biz_type(2), create_time DESC, user_id DESC, id DESC, price)',
'SELECT ''skip: idx_wallet_tx_biz_ct 已存在'' AS msg');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;