大数据排序方案---外排序介绍

本文介绍了一种处理大规模数据集的外排序算法。该算法通过分阶段处理,首先将原始数据分割成若干个可以放入内存的小段,并进行内排序;随后通过两两合并的方式逐步将这些有序小段整合为最终的有序数据集。

原文:http://blog.sina.com.cn/s/blog_62186b4601019uz1.html

我们一般提到排序都是指内排序,比如快排,堆排序,归并排序等,所谓内排序就是能把所有待排序的数据外进内存之中,比如,一个数组之中。但是如果文件太大,文件中的所有数据不能一次性的放入内存之中,快排,堆排序,归并排序等内排序就无法工作了。

    比如下面的程序生成了一个包含266万个int整型的文件,为了排序这266万个int整型,我们用外排序。

外排序

该算法分两个阶段:

阶段一:把原始数据分成M段,每次读取一段,存入一个数组,使用内排序算法对这一段数据进行排序,然后将排完序的数据写入一个临时文件。假定最大数组规模为10万个int型值,则每个临时文件中保存着10万个有序的int型值。我们用S1、S2、.....Sk表示这些临时文件,其中最后的一个数据段Sk,包含的数据个数可能不足10万。

 

阶段二:将每对有序数据段(比如S1跟S2、S3跟S4....)合并为一个大的有序的数据段,将其存入一个新的临时文件。重复此过程,直至只剩下一个数据段。

 

 

实现阶段一:

    在函数initializeSegments中,我们将largedata.dat中每个规模为MAX_ARRAY_SIZE(10万)的数据段依次放入数组并排序,使用快排,并将所有排完序的数据依次存入一个名为f1.dat的新文件中。函数返回数据段的数目。

阶段一代码如下:

外排序

实现阶段二:

    每个合并步骤中,两个有序数据段合并为一个新的更大的有序数据段,规模加倍,因此,数据段的数目减半。合并后数据无法放入内存中。合并步骤的实现方法是:首先将文件f1.dat中的前一半数据段移动到临时文件f2.dat中。然后将文件f1.dat的第一个数据段与文件f2.dat的第一个数据段合并,写入临时文件f3.dat中。(注 f1.dat中的数据段可能比f2.dat中的多一段,如果这样的话,在合并操作后,将其最后一段数据段直接复制到f3.dat中)

下面是合并所有数据段的代码:

外排序

 

完整的实现代码详见:http://www.oschina.net/code/snippet_176897_13955

(1)int numberOfSegments =initializeSegments(MAX_ARRAY_SIZE, "largedata.dat", "f1.dat");

从原文件中创建初始数据段,并将有序数据段存入文件f1.dat中。

(2)merge(numberOfSegments, MAX_ARRAY_SIZE, "f1.dat", "f2.dat", "f3.dat");

将f1中的文件合并到f3中,利用f2做辅助。函数merge递归的调用多次,完成多个合并操作。每个步骤将numberOfSegments减少一半,而将每个数据段的大小增至一倍。完成一个合并操作后,下一个合并步骤中将f3中的新数据段合并至f2中,用f1做辅助。因此新调用的合并函数应该为:

merge((numberOfSegments + 1) / 2, segmentSize * 2, f3, f1, f2);

递归函数merge当numberOfSegments变为1时终止,在此情况下,f1包含排好序的数据。将f1复制到sortedlargedata.dat。

 

外排序分析:

    在外排中,主要的代价是文件IO。假定原文件中待排序的数据个数为n。

    在阶段一种,从原文件读取了n个元素,并写入临时文件,因此阶段一的IO开销为O(n)。

    在阶段二中,在第一个合并操作之前,有序数据段的数目为n/c,其中c=MAX_ARRAY_SIZE。每个合并操作之后,有序数据段的数目减少一半。因此log(n/c)个步骤之后,数据段的数目为1。每个合并步骤中,从文件f1读取一半数据段,写入临时文件f2.f1剩余数据段与f2数据段进行合并。每个合并步骤的IO操作次数为O(n)。所以log(n/c)个合并操作总的IO次数为O(n)*log(n/c)。

    所以外排序的复杂度为O(nlogn)。

<think> 嗯,用户想了解SQL在大数据场景下的排序方法。从引用内容看,用户可能正在准备大数据相关的SQL面试,或者在工作中需要优化海量数据的排序性能。 用户提供的五个引用都很有针对性:引用[1]展示了窗口函数排序的实际案例,引用[2]提到窗口函数是面试重点,引用[3][4]直接关联大数据排序,引用[5]则给出Spark SQL的实战案例。这些恰好覆盖了三个关键方向:传统数据库优化、窗口函数应用和分布式计算框架。 考虑到用户可能是技术人员,回复需要兼顾原理和实操。重点应该包括: 1)窗口函数的分治思想(如row_number+partition by) 2)大数据特有的抽样技巧(引用[4]的随机抽样法) 3)分布式引擎的优化(Spark SQL的排序策略) 需要特别注意避免术语堆砌,比如解释“分桶排序”时要关联Hive的cluster by原理。用户提供的示例代码格式很规范,回复中的SQL示例也要保持这种风格。 用户没有明确数据库类型,所以回复要通用化。但引用[5]提到Spark SQL,暗示可能需要分布式解决方案。有趣的是引用[1]和[4]形成对比:一个是精确排序,一个是近似处理——这正好带出“精确性vs性能”的权衡话题。 数据规模可能是亿级,因为引用[3]提到“100天刷题”,引用[5]有电商搜索排名案例。回复中TopN的示例应该用实际业务场景(如用户行为分析)而非抽象例子。 </think> 在大数据场景下进行SQL排序时,传统`ORDER BY`易引发性能瓶颈。以下是高效方法分类及实践方案--- ### 一、窗口函数分治排序(适用于精确排序) **原理**:通过`PARTITION BY`将数据分块,局部排序后合并 **引用案例**(来自引用[1]): ```sql SELECT user_id, login_time, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_time) AS num FROM login_log ``` **优势**: - 分布式计算:每个分区独立排序,避免全表Shuffle - 增量处理:新增分区无需全局重排 --- ### 二、近似排序与抽样(适用于统计分析) **方法**: 1. **随机抽样排序**(引用[4]方案): ```sql SELECT TOP 100 * FROM large_table WHERE (ABS(CAST(BINARY_CHECKSUM(key_col, NEWID()) AS INT)) % 100) < 10 -- 抽10%样本 ORDER BY sort_col ``` 2. **TABLESAMPLE**(Hive/SparkSQL): ```sql SELECT * FROM table TABLESAMPLE(10 PERCENT) ORDER BY col ``` --- ### 三、分布式引擎优化策略 1. **预分区排序**(Hive/SparkSQL): ```sql -- 建表时按排序列分桶 CREATE TABLE user_log PARTITIONED BY (dt STRING) CLUSTERED BY (user_id) SORTED BY (login_time) INTO 32 BUCKETS ``` 2. **Top-N优化**(引用[5]案例): ```sql /* SparkSQL:局部排序后聚合全局TopN */ SELECT date, product_id, search_count FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY date ORDER BY search_count DESC) AS rank FROM search_log ) WHERE rank <= 3 -- 每日Top3 ``` --- ### 四、硬件层加速方案 1. **索引优化**: - 列式存储(Parquet/ORC)的**Z-Order索引**加速多列排序 2. **资源调整**: ```sql -- SparkSQL配置 SET spark.sql.shuffle.partitions=2000; -- 增加Shuffle并行度 SET spark.executor.memory=8g; -- 提升单节点内存 ``` --- ### 性能对比表 | 方法 | 数据量上限 | 时延 | 适用场景 | |---------------------|------------|----------|-------------------| | 窗口函数分治 | 亿级 | 中 | 精确全排序 | | 抽样排序 | 无上限 | 低 | 统计分析 | | 预分区+桶排序 | 十亿级 | 低(首次)| 高频排序查询 | | Top-N优化 | 亿级 | 极低 | 排名场景 | > **提示**:十亿级以上数据优先用 **分桶预排序+增量更新**,百亿级考虑 **近似算法**(如T-Digest) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值