wlzboy
2026-03-31 61c4c3f45e4257e2e7662f033e2719e62366c632
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
-- ========================================
-- 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';