以下是关于 数据库 UNION
和 UNION ALL
的使用 ,以及 分库分表环境下多表数据组合后的排序和分页问题的解决方案 的详细说明,并以表格总结关键内容:
1. UNION 和 UNION ALL 的核心区别
1.1 定义与语法
1.2 核心区别
特性 UNION UNION ALL 去重 自动去除重复行 不去重 排序 结果自动排序(基于第一个 SELECT
的列) 无默认排序,需显式 ORDER BY
性能 较低(因去重和排序操作) 较高(直接合并结果) 适用场景 需要去重的合并 直接合并无需去重的数据
2. 分库分表环境下的数据组合
2.1 分库分表背景
分库分表 :将数据分散存储在多个物理表或数据库中(如按时间、区域分片)。挑战 :跨分片查询时需合并多表数据。
2.2 使用 UNION
/UNION ALL
跨分片查询
SELECT * FROM orders_2023
UNION ALL
SELECT * FROM orders_2024
UNION ALL
SELECT * FROM orders_2025;
3. 分库分表下的排序问题及解决方案
3.1 问题描述
直接排序的性能问题 : 若在 UNION ALL
后使用 ORDER BY
,数据库需将所有分片数据拉取到单个节点排序,可能导致内存不足或性能下降。分片内排序的局限性 : 单独对每个分片排序后合并,无法保证全局顺序。
3.2 解决方案
方案 1:分片内排序 + 合并结果
SELECT * FROM ( ( SELECT * FROM orders_2023 ORDER BY order_time) UNION ALL ( SELECT * FROM orders_2024 ORDER BY order_time) UNION ALL ( SELECT * FROM orders_2025 ORDER BY order_time)
) AS combined
ORDER BY order_time;
方案 2:使用临时表或中间结果
CREATE TEMPORARY TABLE temp_orders AS
SELECT * FROM orders_2023
UNION ALL
SELECT * FROM orders_2024
UNION ALL
SELECT * FROM orders_2025;
SELECT * FROM temp_orders ORDER BY order_time;
方案 3:分片键与排序列的关联
策略 :按排序列分片(如按时间分片),合并时按分片顺序读取。示例 : 若订单按年分片,查询按时间排序时,直接按年份顺序查询分片即可保证全局顺序。
4. 分页查询问题及解决方案
4.1 问题描述
直接使用 LIMIT
和 OFFSET
的性能问题 : 当分页到较深的页码(如 OFFSET 10000
)时,数据库需扫描大量数据,导致性能下降。分片内分页的局限性 : 单独对每个分片分页后合并,可能无法保证全局顺序或数据完整性。
4.2 解决方案
方案 1:分片内分页 + 合并结果
SELECT * FROM ( ( SELECT * FROM orders_2023 ORDER BY order_id LIMIT 1000 ) UNION ALL ( SELECT * FROM orders_2024 ORDER BY order_id LIMIT 1000 ) UNION ALL ( SELECT * FROM orders_2025 ORDER BY order_id LIMIT 1000 )
) AS combined
ORDER BY order_time
LIMIT 10 OFFSET 0 ;
方案 2:使用游标分页(Keyset Pagination)
SELECT * FROM ( SELECT * FROM orders_2023 UNION ALL SELECT * FROM orders_2024 UNION ALL SELECT * FROM orders_2025
) AS combined
WHERE order_id > last_seen_id
ORDER BY order_id
LIMIT 10 ;
方案 3:分片键与分页键的关联
策略 :按分页键分片(如按用户ID分片),合并时按分片顺序读取。示例 : 若用户按ID分片,查询时按分片顺序读取并合并结果。
5. 优化建议
优先使用 UNION ALL
: 分片内预排序和分页 : 在分片查询时先局部排序/分页,减少全局操作的数据量。 分页策略选择 : 使用游标分页(Keyset Pagination)替代 OFFSET
。 分片键设计 :
6. 表格总结
特性 UNION UNION ALL 排序建议 分页建议 去重 ✅ 自动去重 ❌ 不去重 分片内排序后合并 分片内分页后合并 性能 低(因去重和排序) 高(直接合并) 避免全局排序,优先分片内处理 避免 OFFSET
,使用游标分页 适用场景 需要去重的合并 大数据量合并无需去重 分片键与排序列关联 分片键与分页键关联 分库分表优化 需合并后去重 直接合并,后续处理 分片内排序 + 临时表 分片内分页 + 游标分页
7. 示例代码总结
分库分表排序与分页优化示例
SELECT * FROM ( ( SELECT * FROM orders_2023 ORDER BY order_time LIMIT 1000 ) UNION ALL ( SELECT * FROM orders_2024 ORDER BY order_time LIMIT 1000 )
) AS combined
ORDER BY order_time
LIMIT 10 OFFSET 0 ;
SELECT * FROM ( SELECT * FROM orders_2023 UNION ALL SELECT * FROM orders_2024
) AS combined
WHERE order_id > 1000
ORDER BY order_id
LIMIT 10 ;
关键结论
UNION vs. UNION ALL :根据是否需要去重选择,UNION ALL
性能更高,但需自行管理重复数据。分库分表排序 :优先在分片内预排序,或通过临时表分阶段处理,避免全局排序。分页优化 :使用游标分页(Keyset Pagination)替代 OFFSET
,结合分片键设计减少数据扫描。 通过合理选择 UNION
/UNION ALL
并结合分片策略,可在分库分表环境下高效完成数据合并、排序和分页操作。