-- ============================================================================
|
-- 大屏 /large-screen/* 慢查询优化 SQL 脚本
|
-- 背景: /large-screen/summary 在 MyCat 分表下按 site_id 过滤会广播扫描 50 张
|
-- t_charging_order 物理表(无索引、无时间边界、跨分片 join),导致超时。
|
-- 方案: 新建站点级预聚合表 t_large_screen_site_stat(全局表),由后端定时任务
|
-- 按"月/日/全局"切片汇总写入,大屏接口改为读该表;本脚本为 50 张分表
|
-- 补充 create_time 索引,供聚合任务按月/按日切片范围扫描使用。
|
--
|
-- 执行方式: 在 MySQL 192.168.110.74 上直接执行(不要走 MyCat)。
|
-- 幂等: 可重复执行,不会报错。
|
-- ============================================================================
|
|
-- 1. 预聚合表(全局表,不分区)
|
CREATE TABLE IF NOT EXISTS `charging_pile_order`.`t_large_screen_site_stat` (
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
`stat_type` char(1) NOT NULL COMMENT '统计粒度:D=日 M=月 G=全局',
|
`period` varchar(16) NOT NULL COMMENT 'D:yyyy-MM-dd / M:yyyy-MM / G:ALL',
|
`site_id` int NOT NULL COMMENT '站点ID, G行固定为0',
|
`order_count` bigint NOT NULL DEFAULT 0 COMMENT '订单数',
|
`user_count` bigint NOT NULL DEFAULT 0 COMMENT '充电用户数(按站点统计, 跨站充电会重复计数)',
|
`capacity` decimal(16,2) NOT NULL DEFAULT 0.00 COMMENT '充电量(kWh)',
|
`electric_fee` decimal(16,2) NOT NULL DEFAULT 0.00 COMMENT '电费',
|
`service_fee` decimal(16,2) NOT NULL DEFAULT 0.00 COMMENT '服务费(含三方0.8折算)',
|
`income` decimal(16,2) NOT NULL DEFAULT 0.00 COMMENT '收入(电费+服务费)',
|
`total_power` decimal(16,2) NOT NULL DEFAULT 0.00 COMMENT '功率合计(仅D行使用)',
|
`registered_user_count` bigint NOT NULL DEFAULT 0 COMMENT '注册用户数(仅G行使用)',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
PRIMARY KEY (`id`),
|
UNIQUE KEY `uk_stat_period_site` (`stat_type`,`period`,`site_id`)
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='大屏站点统计预聚合表';
|
|
-- 2. 给 50 张 t_charging_order 物理分表补 create_time 索引(幂等,已存在则跳过)
|
DROP PROCEDURE IF EXISTS `charging_pile_order`.`add_large_screen_create_time_index`;
|
DELIMITER $$
|
CREATE PROCEDURE `charging_pile_order`.`add_large_screen_create_time_index`()
|
BEGIN
|
DECLARE i INT DEFAULT 0;
|
DECLARE tbl_name VARCHAR(64);
|
DECLARE idx_exists INT;
|
WHILE i < 50 DO
|
SET tbl_name = CONCAT('t_charging_order_', i);
|
SELECT COUNT(*) INTO idx_exists
|
FROM information_schema.statistics
|
WHERE table_schema = 'charging_pile_order'
|
AND table_name = tbl_name
|
AND index_name = 'idx_create_time';
|
IF idx_exists = 0 THEN
|
SET @ddl = CONCAT('ALTER TABLE `charging_pile_order`.`', tbl_name,
|
'` ADD KEY idx_create_time (create_time)');
|
PREPARE stmt FROM @ddl;
|
EXECUTE stmt;
|
DEALLOCATE PREPARE stmt;
|
END IF;
|
SET i = i + 1;
|
END WHILE;
|
END$$
|
DELIMITER ;
|
CALL `charging_pile_order`.`add_large_screen_create_time_index`();
|
DROP PROCEDURE `charging_pile_order`.`add_large_screen_create_time_index`;
|
|
-- 3. 索引结果核对(应返回 50 行)
|
SELECT table_name, index_name
|
FROM information_schema.statistics
|
WHERE table_schema = 'charging_pile_order'
|
AND table_name LIKE 't_charging_order\_%'
|
AND index_name = 'idx_create_time'
|
ORDER BY table_name;
|
|
-- 1.2 用户-站点对表(充电用户数精确去重)
|
-- 背景: 预聚合表的 user_count 按站点求和, 跨站充电用户会重复计数。
|
-- 本表记录"每个站点出现过哪些用户"(所有订单口径, 与工作台 countAllUserData 一致),
|
-- 接口对选中站点做 COUNT(DISTINCT app_user_id) 精确去重。
|
CREATE TABLE IF NOT EXISTS `charging_pile_order`.`t_large_screen_user_site` (
|
`site_id` int NOT NULL COMMENT '站点ID',
|
`app_user_id` bigint NOT NULL COMMENT '用户ID',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
PRIMARY KEY (`site_id`,`app_user_id`)
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='大屏充电用户-站点对(精确去重)';
|
|
-- ============================================================================
|
-- 上线后数据一致性对比(只读,可在线执行;对比新老口径差值,应≈0)
|
-- 老口径: 现接口 getLargeScreenSummary 的原始 SQL(挑少量站点对比,避免生产压力)
|
-- ============================================================================
|
-- SELECT COUNT(DISTINCT charging_order.id) AS validOrderCount,
|
-- COALESCE(ROUND(SUM(accounting.charging_capacity), 2), 0) AS totalChargingCapacity,
|
-- COALESCE(ROUND(SUM(accounting.period_electric_price), 2), 0) AS electricityFee,
|
-- COALESCE(ROUND(SUM(CASE WHEN charging_order.order_source IN (0,1)
|
-- THEN accounting.period_service_price ELSE accounting.period_service_price * 0.8 END), 2), 0) AS serviceFee
|
-- FROM charging_pile_order.t_charging_order charging_order
|
-- LEFT JOIN charging_pile_order.t_charging_order_accounting_strategy accounting
|
-- ON accounting.charging_order_id = charging_order.id
|
-- WHERE charging_order.del_flag = 0
|
-- AND charging_order.status = 5
|
-- AND charging_order.recharge_payment_status = 2
|
-- AND charging_order.site_id IN (101, 102);
|
--
|
-- SELECT SUM(order_count) AS validOrderCount,
|
-- SUM(capacity) AS totalChargingCapacity,
|
-- SUM(electric_fee) AS electricityFee,
|
-- SUM(service_fee) AS serviceFee
|
-- FROM charging_pile_order.t_large_screen_site_stat
|
-- WHERE stat_type = 'M' AND site_id IN (101, 102);
|