以下是关于 数据库 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
并结合分片策略,可在分库分表环境下高效完成数据合并、排序和分页操作。