-- ======================================== -- GPS分段里程表分区优化 - 快速执行版 -- ======================================== -- 适用场景:数据量适中(100万-500万),可以接受短暂停机 -- 执行时间:根据数据量,预计5-30分钟 -- ======================================== -- 第一步:检查当前数据状态 -- ======================================== USE your_database_name; -- 请修改为实际的数据库名 SELECT '=== 当前表信息 ===' as info; SELECT TABLE_NAME as '表名', TABLE_ROWS as '记录数(估算)', ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS '大小(MB)' FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'tb_vehicle_gps_segment_mileage'; SELECT '=== 数据时间范围 ===' as info; SELECT MIN(segment_start_time) as '最早数据', MAX(segment_start_time) as '最新数据', DATEDIFF(MAX(segment_start_time), MIN(segment_start_time)) as '数据跨度(天)' FROM tb_vehicle_gps_segment_mileage; SELECT '=== 按月数据分布 ===' as info; SELECT DATE_FORMAT(segment_start_time, '%Y-%m') as '月份', COUNT(*) as '记录数', ROUND(SUM(segment_distance), 2) as '总里程(km)' FROM tb_vehicle_gps_segment_mileage GROUP BY DATE_FORMAT(segment_start_time, '%Y-%m') ORDER BY 1 DESC LIMIT 12; -- 暂停!请检查以上信息,确认数据量和时间范围 -- 按回车继续... -- ======================================== -- 第二步:创建分区表 -- ======================================== -- 创建新的分区表 CREATE TABLE `tb_vehicle_gps_segment_mileage_partitioned` ( `segment_id` bigint(20) NOT NULL AUTO_INCREMENT, `vehicle_id` bigint(20) NOT NULL, `vehicle_no` varchar(20) DEFAULT NULL, `segment_start_time` datetime NOT NULL, `segment_end_time` datetime NOT NULL, `start_longitude` decimal(10,7) DEFAULT NULL, `start_latitude` decimal(10,7) DEFAULT NULL, `end_longitude` decimal(10,7) DEFAULT NULL, `end_latitude` decimal(10,7) DEFAULT NULL, `segment_distance` decimal(10,3) DEFAULT 0.000, `gps_point_count` int(11) DEFAULT 0, `gps_ids` text, `task_id` bigint(20) DEFAULT NULL, `task_code` varchar(50) DEFAULT NULL, `calculate_method` varchar(20) DEFAULT 'tianditu', `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`segment_id`, `segment_start_time`), UNIQUE KEY `uk_vehicle_time` (`vehicle_id`, `segment_start_time`), KEY `idx_vehicle_id` (`vehicle_id`), KEY `idx_start_time` (`segment_start_time`), KEY `idx_task_id` (`task_id`), KEY `idx_vehicle_task` (`vehicle_id`, `task_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆GPS分段里程表(按月分区)' PARTITION BY RANGE (TO_DAYS(segment_start_time)) ( PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')), PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')), PARTITION p202403 VALUES LESS THAN (TO_DAYS('2024-04-01')), PARTITION p202404 VALUES LESS THAN (TO_DAYS('2024-05-01')), PARTITION p202405 VALUES LESS THAN (TO_DAYS('2024-06-01')), PARTITION p202406 VALUES LESS THAN (TO_DAYS('2024-07-01')), PARTITION p202407 VALUES LESS THAN (TO_DAYS('2024-08-01')), PARTITION p202408 VALUES LESS THAN (TO_DAYS('2024-09-01')), PARTITION p202409 VALUES LESS THAN (TO_DAYS('2024-10-01')), PARTITION p202410 VALUES LESS THAN (TO_DAYS('2024-11-01')), PARTITION p202411 VALUES LESS THAN (TO_DAYS('2024-12-01')), PARTITION p202412 VALUES LESS THAN (TO_DAYS('2025-01-01')), PARTITION p202501 VALUES LESS THAN (TO_DAYS('2025-02-01')), PARTITION p202502 VALUES LESS THAN (TO_DAYS('2025-03-01')), PARTITION p202503 VALUES LESS THAN (TO_DAYS('2025-04-01')), PARTITION p202504 VALUES LESS THAN (TO_DAYS('2025-05-01')), PARTITION p202505 VALUES LESS THAN (TO_DAYS('2025-06-01')), PARTITION p202506 VALUES LESS THAN (TO_DAYS('2025-07-01')), PARTITION p202507 VALUES LESS THAN (TO_DAYS('2025-08-01')), PARTITION p202508 VALUES LESS THAN (TO_DAYS('2025-09-01')), PARTITION p202509 VALUES LESS THAN (TO_DAYS('2025-10-01')), PARTITION p202510 VALUES LESS THAN (TO_DAYS('2025-11-01')), PARTITION p202511 VALUES LESS THAN (TO_DAYS('2025-12-01')), PARTITION p202512 VALUES LESS THAN (TO_DAYS('2026-01-01')), PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')), PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')), PARTITION p202603 VALUES LESS THAN (TO_DAYS('2026-04-01')), PARTITION p202604 VALUES LESS THAN (TO_DAYS('2026-05-01')), PARTITION p202605 VALUES LESS THAN (TO_DAYS('2026-06-01')), PARTITION p202606 VALUES LESS THAN (TO_DAYS('2026-07-01')), PARTITION p202607 VALUES LESS THAN (TO_DAYS('2026-08-01')), PARTITION p202608 VALUES LESS THAN (TO_DAYS('2026-09-01')), PARTITION p202609 VALUES LESS THAN (TO_DAYS('2026-10-01')), PARTITION p202610 VALUES LESS THAN (TO_DAYS('2026-11-01')), PARTITION p202611 VALUES LESS THAN (TO_DAYS('2026-12-01')), PARTITION p202612 VALUES LESS THAN (TO_DAYS('2027-01-01')), PARTITION pfuture VALUES LESS THAN MAXVALUE ); SELECT '分区表创建成功' as result; -- ======================================== -- 第三步:迁移数据 -- ======================================== SELECT '开始迁移数据...' as info, NOW() as start_time; -- 一次性迁移(适用于数据量不超过500万) INSERT INTO tb_vehicle_gps_segment_mileage_partitioned SELECT * FROM tb_vehicle_gps_segment_mileage; SELECT '数据迁移完成' as info, NOW() as end_time; -- ======================================== -- 第四步:验证数据 -- ======================================== SELECT '=== 数据验证 ===' as info; -- 比较记录数 SELECT '原表' as table_name, COUNT(*) as record_count FROM tb_vehicle_gps_segment_mileage UNION ALL SELECT '新表(分区)' as table_name, COUNT(*) as record_count FROM tb_vehicle_gps_segment_mileage_partitioned; -- 比较统计数据 SELECT '原表' as table_name, SUM(segment_distance) as total_distance, MIN(segment_start_time) as min_time, MAX(segment_start_time) as max_time FROM tb_vehicle_gps_segment_mileage UNION ALL SELECT '新表(分区)' as table_name, SUM(segment_distance) as total_distance, MIN(segment_start_time) as min_time, MAX(segment_start_time) as max_time FROM tb_vehicle_gps_segment_mileage_partitioned; -- 查看分区分布 SELECT PARTITION_NAME as '分区名', TABLE_ROWS as '记录数', ROUND(DATA_LENGTH/1024/1024, 2) as '数据(MB)', ROUND(INDEX_LENGTH/1024/1024, 2) as '索引(MB)' FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'tb_vehicle_gps_segment_mileage_partitioned' ORDER BY PARTITION_ORDINAL_POSITION; -- 暂停!请检查数据是否一致 -- 如果数据一致,继续执行下一步 -- 如果不一致,请停止并检查问题 -- ======================================== -- 第五步:切换表名(谨慎!) -- ======================================== -- 建议在业务停机窗口执行以下操作 -- START TRANSACTION; SELECT '开始切换表名...' as info; -- 重命名原表为备份表 RENAME TABLE tb_vehicle_gps_segment_mileage TO tb_vehicle_gps_segment_mileage_old, tb_vehicle_gps_segment_mileage_partitioned TO tb_vehicle_gps_segment_mileage; SELECT '表名切换完成,请立即验证应用功能!' as result; -- 如果有问题,立即回滚: -- RENAME TABLE -- tb_vehicle_gps_segment_mileage TO tb_vehicle_gps_segment_mileage_partitioned, -- tb_vehicle_gps_segment_mileage_old TO tb_vehicle_gps_segment_mileage; -- COMMIT; -- ======================================== -- 第六步:验证分区效果 -- ======================================== SELECT '=== 测试查询性能 ===' as info; -- 测试1:查询最近1月数据(应该只扫描1个分区) EXPLAIN PARTITIONS SELECT COUNT(*), SUM(segment_distance) FROM tb_vehicle_gps_segment_mileage WHERE segment_start_time >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH); -- 测试2:按车辆ID查询最近1周数据 EXPLAIN PARTITIONS SELECT * FROM tb_vehicle_gps_segment_mileage WHERE vehicle_id = 1 AND segment_start_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) LIMIT 10; -- 测试3:统计最近3个月的里程 SELECT DATE_FORMAT(segment_start_time, '%Y-%m') as month, COUNT(*) as segments, ROUND(SUM(segment_distance), 2) as total_km FROM tb_vehicle_gps_segment_mileage WHERE segment_start_time >= DATE_SUB(CURDATE(), INTERVAL 3 MONTH) GROUP BY DATE_FORMAT(segment_start_time, '%Y-%m'); -- ======================================== -- 第七步:清理和优化(可选) -- ======================================== -- 确认应用运行正常后,等待1-2周,然后删除备份表 -- DROP TABLE tb_vehicle_gps_segment_mileage_old; -- 分析表,优化查询计划 ANALYZE TABLE tb_vehicle_gps_segment_mileage; -- ======================================== -- 完成! -- ======================================== SELECT '========================================' as info; SELECT '分区优化完成!' as result; SELECT '请注意:' as notice; SELECT '1. 定期添加新月份的分区' as task1; SELECT '2. 定期清理历史分区释放空间' as task2; SELECT '3. 查询时尽量带上时间范围条件' as task3; SELECT '========================================' as info; -- ======================================== -- 日常维护命令参考 -- ======================================== -- 添加新分区(每月执行一次) -- ALTER TABLE tb_vehicle_gps_segment_mileage -- REORGANIZE PARTITION pfuture INTO ( -- PARTITION p202701 VALUES LESS THAN (TO_DAYS('2027-02-01')), -- PARTITION pfuture VALUES LESS THAN MAXVALUE -- ); -- 删除历史分区(释放空间) -- ALTER TABLE tb_vehicle_gps_segment_mileage DROP PARTITION p202401; -- 查看分区状态 -- SELECT * FROM information_schema.PARTITIONS -- WHERE TABLE_SCHEMA = DATABASE() -- AND TABLE_NAME = 'tb_vehicle_gps_segment_mileage';