FileSort

/*************************************************************************
    > File Name: FileSort.h
    > Author: wangzhicheng
    > Mail: 2363702560@qq.com 
    > Created Time: Sat 31 Dec 2016 09:30:39 AM AWST
	> Brief:sort strings in the file
 ************************************************************************/
#ifndef FILE_SORT_H
#define FILE_SORT_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <omp.h>
#include <iostream>
#include <fstream>
#include <thread>
#include <algorithm>
#include <functional>  
namespace filesort
{
#define ASC 0
#define DESC 1
using namespace std;
class FileSort 
{
	public:
	/*
	 * @brief sort a file 
	 * @input_path the input file full path
	 * @sortype sort type 
	 * @return true if sort is ok
	 * */
	static bool sort(const char *input_path, const char *output_path, int sortype = ASC, int threadnum = 2);
	private:
	/*
	 * @brief use the stl sort
	 * */
	inline static void threadsort(vector<string>&input, int sortype)
	{
		switch(sortype)
		{
			case ASC:	// ASC
				std::sort(input.begin(), input.end());
				break;
			case DESC:	// DESC
				std::sort(input.rbegin(), input.rend());
				// lamba
				/*
				std::sort(input.begin(), input.end(), [](const string &str0, const string &str1)
						{
							return str0 > str1;
						});
						*/
				break;
		}
	}
};
}
#endif

/*************************************************************************
    > File Name: FileSort.cpp
    > Author: wangzhicheng
    > Mail: 2363702560@qq.com 
    > Created Time: Sat 31 Dec 2016 09:30:39 AM AWST
	> Brief: sort strings in a file
 ************************************************************************/
#include "FileSort.h"
namespace filesort
{
bool FileSort::sort(const char *input_path, const char *output_path, int sortype, int threadnum)
{
	// safe check entry arguments
	int MaxThreadNum = omp_get_num_procs() << 1;
	if(threadnum <= 0) threadnum = 1;
	if(threadnum >= MaxThreadNum) threadnum = MaxThreadNum;
	// open the input file
	ifstream is(input_path);
	if(!is)
	{
		cerr << input_path << " open failed...!" << endl;
		return false;
	}
	// import the string in the input file to various segments
	typedef vector<string> stringset;
	vector<stringset>segments;
	segments.resize(threadnum);		// every thead is responsible for every segment
	int index = 0;
	string line;
	while(getline(is, line))
	{
		segments[index].emplace_back(line);
		index = (index + 1) % threadnum;
	}
	is.close();
	// start theads to sort
	vector<thread>sortthreads;
	int i;
	for(i = 0;i < threadnum;i++)
	{
		stringset &strings = segments[i];
		sortthreads.push_back(thread(FileSort::threadsort, ref(strings), sortype));
	}
	for(auto &th:sortthreads)
	{
		th.join();
	}
	// open the output file
	ofstream os(output_path, ios::trunc);
	if(!os)
	{
		cerr << input_path << " open failed...!" << endl;
		return false;
	}
	// merge the vector to sort
	// init the heap
	vector<pair<string, int> >outstrings;	// first -- key second -- position
	for(i = 0;i < threadnum;i++)
	{
		stringset &strings = segments[i];
		if(!strings.empty())
		{
			outstrings.emplace_back(pair<string, int>(strings.front(), i));
			strings.erase(strings.begin());
		}
	}
	index = 0;
	switch(sortype)
	{
	case ASC:
		make_heap(outstrings.begin(), outstrings.end(), [](const pair<string, int>&p0, const pair<string, int>&p1)
				{
					return p0.first > p1.first;
				});
		break;
	case DESC:
		make_heap(outstrings.begin(), outstrings.end(), [](const pair<string, int>&p0, const pair<string, int>&p1)
				{
					return p0.first < p1.first;
				});
		break;
	}
	while(!outstrings.empty())
	{
		pop_heap(outstrings.begin(), outstrings.end());
		string &key = outstrings.back().first;
		int pos = outstrings.back().second;
		os << key << endl;
		outstrings.pop_back();
		stringset &strings = segments[pos];
		if(!strings.empty())
		{
			outstrings.emplace_back(pair<string, int>(strings.front(), pos));
			strings.erase(strings.begin());
		}
		switch(sortype)
		{
		case ASC:
			make_heap(outstrings.begin(), outstrings.end(), [](const pair<string, int>&p0, const pair<string, int>&p1)
					{
						return p0.first > p1.first;
					});
			break;
		case DESC:
			make_heap(outstrings.begin(), outstrings.end(), [](const pair<string, int>&p0, const pair<string, int>&p1)
					{
						return p0.first < p1.first;
					});
			break;
		}
	}
	os.close();
}
}

/*************************************************************************
    > File Name: main.cpp
    > Author: wangzhicheng
    > Mail: 2363702560@qq.com 
    > Created Time: Sat 31 Dec 2016 09:44:59 AM AWST
 ************************************************************************/

#include "FileSort.h"
#include <iterator>
#include <time.h>
using namespace filesort;
int main()
{
	// generate testing data
	static const int N = 10;
	static const int MAX = 100;
	int i, j;
	ofstream test_input("./input_data", ios::trunc);
	if(!test_input)
	{
		cerr << "input file generate failed...!" << endl;
		return 1;
	}
	char buf[64];
	srand(time(0));
	for(i = 0;i < MAX;i++)
	{
		for(j = 0;j < N;j++)
		{
			sprintf(buf + j, "%d", rand() % N);
		}
		test_input << buf << endl; 
	}
	test_input.close();
	// sort
	FileSort::sort("./input_data", "./output_data", DESC);

	return 0;
}

CC = g++
DBG = 

ifndef  DEBUG_SET
	DEBUG_SET=  -std=c++11 -g -pthread
endif

IFLAGS =-I .\

INDEX_ROOT=..
LIBS =	-L .\
		-lpthread\
		-lgomp\

LINK = 


TARGET=MergeSort
all:$(TARGET)

OBJS=FileSort.o\
	 main.o\

$(TARGET):$(OBJS)
	$(CC) -fPIC -o ./$(TARGET) $(OBJS) $(LIBS) $(LINK)
	
.cpp.o:
	$(CC) $(DBG) $(DEBUG_SET) $(IFLAGS) -fPIC -c $<
	
clean:
	rm *.o -fr
	rm -f MergeSort

### MySQL 文件排序 (filesort) 优化与解析 在 MySQL 查询执行过程中,当无法使用索引对结果集进行排序时,MySQL 会采用 filesort 操作。尽管名称中包含 "file",但并不意味着所有排序操作都会写入磁盘;实际上,如果数据量较小,排序可以在内存中完成[^4]。 #### 文件排序的工作机制 文件排序主要分为两个阶段:**排序缓冲区填充** 和 **合并排序**。 1. **内存排序(save_index)**:若排序数据量较小,可以完全放入排序缓冲区,则直接在内存中进行排序,效率较高。此过程调用 `save_index` 方法实现。 2. **文件排序(merge_many_buff)**:若排序数据量较大,超出排序缓冲区容量,则会将中间排序结果写入临时文件,并通过 `merge_buffers()`、`merge_index()` 和 `merge_many_buff()` 等方法完成最终的归并排序[^4]。 #### 影响文件排序性能的因素 - **排序缓冲区大小(sort_buffer_size)**:该参数决定了可用于排序的内存大小。增大此值可减少磁盘 I/O,提高排序速度,但过大会导致内存浪费或系统资源争用。 - **连接缓冲区大小(join_buffer_size)**:对于涉及 JOIN 的查询,适当调整此参数也有助于提升性能。 - **临时表限制(tmp_table_size/max_heap_table_size)**:若排序操作依赖内部临时表,且临时表过大,可能导致转换为磁盘表,从而影响性能。 #### 如何避免 filesort 要优化 filesort,最有效的方式是尽量避免它: - **使用合适的索引**:确保查询中的 `ORDER BY`、`GROUP BY` 和 `DISTINCT` 子句能利用索引。例如,在 `ORDER BY column` 上创建索引,或在多列排序时创建复合索引。 - **覆盖索引(Covering Index)**:若查询字段均包含在索引中,MySQL 可以仅通过索引获取数据,无需回表查询,这通常也能避免 filesort。 - **减少不必要的排序**:检查业务逻辑是否真的需要排序,或者是否可以在应用层处理排序,以降低数据库负担。 #### 示例:优化包含 filesort 的查询 假设存在如下查询: ```sql EXPLAIN SELECT * FROM tb_hero WHERE hero_name = '李寻欢' AND book_id = 1 ORDER BY age DESC LIMIT 10; ``` 其执行计划显示 `Extra` 列为 `Using filesort`,说明排序未命中索引。可以通过以下方式优化: ##### 方式一:添加复合索引 ```sql CREATE INDEX idx_hero_book_age ON tb_hero(hero_name, book_id, age); ``` 这样,MySQL 可以利用索引来加速过滤和排序操作,避免 filesort。 ##### 方式二:改写查询结构 在某些复杂查询中,使用子查询或派生表结合 JOIN 可以改善排序性能,例如: ```sql SELECT a.* FROM tb_hero a JOIN ( SELECT id FROM tb_hero WHERE hero_name = '李寻欢' AND book_id = 1 ORDER BY age DESC LIMIT 10 ) b USING (id); ``` 此方式利用子查询先完成排序和限制行数,再通过主键回表查询完整数据,有助于减少排序数据量[^3]。 #### 总结 虽然 filesort 是 MySQL 内部用于排序的一种机制,但在实际应用中应尽可能避免其触发。通过合理设计索引、调整配置参数以及优化 SQL 语句结构,可以显著提升查询性能,减少因 filesort 引起的额外开销。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值