-- ========================================
-- 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';
