C++ MySQL并发加载数据填充
我有一个小样本数据集-九个文件,每个文件中有1000000行。真实的数据都是实时捕获的,然后插入MySQL数据库。我第一次尝试这个方法时,插入总数据集(约5亿行,24GB纯文本)只花了16个多小时。我觉得那太慢了,所以就试着加快速度 为此,我已经有了一个功能齐全的多线程实现,这是一个我已经工作了一段时间的程序。对于每个文件,它将创建一个表,使用适当的SQL创建一个临时文件,然后在每个文件上运行C++ MySQL并发加载数据填充,c++,mysql,c,linux,mariadb,C++,Mysql,C,Linux,Mariadb,我有一个小样本数据集-九个文件,每个文件中有1000000行。真实的数据都是实时捕获的,然后插入MySQL数据库。我第一次尝试这个方法时,插入总数据集(约5亿行,24GB纯文本)只花了16个多小时。我觉得那太慢了,所以就试着加快速度 为此,我已经有了一个功能齐全的多线程实现,这是一个我已经工作了一段时间的程序。对于每个文件,它将创建一个表,使用适当的SQL创建一个临时文件,然后在每个文件上运行LOAD DATA LOCAL infle 有关守则如下: void insert_data(uint3
LOAD DATA LOCAL infle
有关守则如下:
void insert_data(uint32_t tid)
{
string scribe_file;
file_list_mutex.lock();
while(scribe_files.size() > 0)
{
scribe_file = *(scribe_files.begin());
scribe_files.erase(scribe_files.begin());
file_list_mutex.unlock();
MYSQL *thread_con = mysql_init(nullptr);
if(thread_con == nullptr)
{
log_mutex.lock();
cerr << "Thead " << tid << ": " << mysql_error(thread_con) << endl;
log_mutex.unlock();
return;
}
if(nullptr == (mysql_real_connect(thread_con, server.c_str(), user.c_str(),
password.c_str(), nullptr,
0, nullptr, 0)))
{
log_mutex.lock();
cerr << "Thead " << tid << ": " << mysql_error(thread_con) << endl;
log_mutex.unlock();
mysql_close(thread_con);
return;
}
if(mysql_select_db(thread_con, database.c_str()))
{
log_mutex.lock();
cerr << "Thead " << tid << ": " << mysql_error(thread_con) << endl;
log_mutex.unlock();
mysql_close(thread_con);
return;
}
string table_name = get_table_name(scribe_file);
if(table_name.empty())
{
log_mutex.lock();
cerr << "Thead " << tid << ": Unusuable input file: " << scribe_file << endl;
log_mutex.unlock();
return;
}
ifstream scribe_stream(scribe_file);
if(!scribe_stream.good())
{
log_mutex.lock();
cerr << "Thead " << tid << ": Error opening " << scribe_file << endl;
log_mutex.unlock();
return;
}
string output_filename = "/tmp/";
{
vector<string> file_path = split_string(scribe_file, '/');
output_filename.append(file_path.rbegin()[0]);
}
output_filename.append(".sql");
ofstream output;
output.open(output_filename, ios::out | ios::trunc);
if(!output.good())
{
log_mutex.lock();
cerr << "Thead " << tid << ": Error opening " << output_filename << endl;
log_mutex.unlock();
scribe_stream.close();
return;
}
string create_query = "CREATE TABLE IF NOT EXISTS ";
string table_format = " (IDpk INT NOT NULL auto_increment,"
" s CHAR(8) NOT NULL,"
" si INT unsigned NOT NULL,"
" pq TINYINT unsigned NOT NULL,"
" pr BIGINT unsigned DEFAULT NULL,"
" sz INT DEFAULT NULL,"
" io TINYINT unsigned DEFAULT NULL,"
" ipslt TINYINT unsigned DEFAULT NULL,"
" is TINYINT unsigned DEFAULT NULL,"
" ilp BIGINT unsigned DEFAULT NULL,"
" ips INT unsigned DEFAULT NULL,"
" at INT unsigned DEFAULT NULL,"
" vn TINYINT unsigned NOT NULL,"
" ms BIGINT unsigned NOT NULL,"
" us BIGINT unsigned NOT NULL,"
" PRIMARY KEY(IDpk),"
" KEY(us),"
" KEY(s),"
" KEY(pq))";
create_query.append(table_name);
create_query.append(table_format);
if(mysql_query(thread_con, create_query.c_str()))
{
log_mutex.lock();
cerr << "Thead " << tid << ": " << mysql_error(thread_con) << endl;
log_mutex.unlock();
scribe_stream.close();
output.close();
mysql_close(thread_con);
return;
}
string scribe_stream_line;
char values[MAX_TOKENS * MAX_TOKEN_LENGTH];
usec_t start_time = get_current_us_time();
uint64_t num_lines = 0;
log_mutex.lock();
cout << "Thread " << tid << ": Starting " << scribe_file << endl;
log_mutex.unlock();
char scribe_tokens[MAX_TOKENS][MAX_TOKEN_LENGTH];
while(getline(scribe_stream, scribe_stream_line))
{
split_scribe_line(scribe_stream_line, scribe_tokens);
num_lines++;
if(scribe_tokens[6][0] != '\0')
{
try
{
uint32_t item_type = stoi(scribe_tokens[2]);
fill(values, values + (MAX_TOKENS * MAX_TOKEN_LENGTH), '\0');
switch(item_type)
{
case 0:
case 1:
{
sprintf(values,
"%s,%s,%s,"
"%s,%s,"
"NULL,NULL,NULL,NULL,NULL,NULL,"
"%s,%s,%s",
scribe_tokens[0], scribe_tokens[1], scribe_tokens[2],
scribe_tokens[3], scribe_tokens[4], scribe_tokens[5],
scribe_tokens[6], scribe_tokens[7]);
break;
}
case 2:
{
sprintf(values,
"%s,%s,%s,"
"%s,%s,%s,%s,"
"NULL,NULL,NULL,NULL,"
"%s,%s,%s",
scribe_tokens[0], scribe_tokens[1], scribe_tokens[2],
scribe_tokens[3], scribe_tokens[4], scribe_tokens[5],
scribe_tokens[6], scribe_tokens[7], scribe_tokens[8],
scribe_tokens[9]);
break;
}
case 3:
{
sprintf(values,
"%s,%s,%s,"
"NULL,NULL,NULL,NULL,"
"NULL,NULL,NULL,NULL,"
"%s,%s,%s",
scribe_tokens[0], scribe_tokens[1], scribe_tokens[2],
scribe_tokens[3], scribe_tokens[4], scribe_tokens[5]);
break;
}
case 4:
{
sprintf(values,
"%s,%s,%s,"
"%s,%s,NULL,NULL,"
"%s,%s,%s,NULL,"
"%s,%s,%s",
scribe_tokens[0], scribe_tokens[1], scribe_tokens[2],
scribe_tokens[3], scribe_tokens[4], scribe_tokens[5],
scribe_tokens[6], scribe_tokens[7], scribe_tokens[8],
scribe_tokens[9], scribe_tokens[10]);
break;
}
case 5:
{
sprintf(values,
"%s,%s,%s,"
"NULL,NULL,NULL,NULL,NULL,NULL,NULL,"
"%s,%s,%s,%s",
scribe_tokens[0], scribe_tokens[1], scribe_tokens[2],
scribe_tokens[3], scribe_tokens[4], scribe_tokens[5],
scribe_tokens[6]);
break;
}
default:
log_mutex.lock();
cerr << "Thread " << tid << ": Unknown pq type " << item_type << "\n"
<< " " << scribe_stream_line << endl;
log_mutex.lock();
continue;
break;
}
output << values << endl;
}
catch(exception &ex)
{
log_mutex.lock();
cerr << "Thread " << tid << ": Error parsing scribe line\n '"
<< scribe_stream_line << "'\n" << " " << ex.what() << endl;
log_mutex.unlock();
scribe_stream.close();
output.close();
throw;
}
}
}
log_mutex.lock();
cout << "Thread " << tid << ": preparing " << num_lines << " lines took "
<< us_to_hhmmss(get_current_us_time() - start_time) << endl;
log_mutex.unlock();
string insert_query = "LOAD DATA LOCAL INFILE ";
insert_query.append("'" + output_filename + "' INTO TABLE "
+ table_name + " FIELDS TERMINATED BY ','");
log_mutex.lock();
cout << "Thread " << tid << ": Loading results into database." << endl;
log_mutex.unlock();
start_time = get_current_us_time();
if(mysql_query(thread_con, insert_query.c_str()))
{
log_mutex.lock();
cerr << "Thead " << tid << ": " <<mysql_error(thread_con) << endl;
log_mutex.unlock();
scribe_stream.close();
output.close();
mysql_close(thread_con);
return;
}
mysql_close(thread_con);
log_mutex.lock();
cout << "Thread " << tid << ": " << "Insertion took "
<< us_to_hhmmss(get_current_us_time() - start_time) << endl;
log_mutex.unlock();
scribe_stream.close();
output.close();
remove(output_filename.c_str());
}
file_list_mutex.unlock();
}
每次运行此测试时,我都会删除数据库
类似地,在所有9个输入文件上运行时,我得到了不同的结果,但没有显示出适当的加速:
Scribe DB CLI V1.07
有1个CPU核。
解析9个输入文件。
线程0:开始划线_20170511/short_划线_0.data
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:19
线程0:开始划线_20170511/短划线_1.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:20
线程0:开始划线_20170511/短划线_2.数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:20
线程0:开始划线_20170511/短划线_3.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:21
线程0:开始划线_20170511/短划线_4.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:21
螺纹0:开始划线_20170511/短划线_5.数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:21
线程0:开始划线_20170511/短划线_6.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:21
线程0:开始划线_20170511/short_划线_7.data
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:21
线程0:开始划线_20170511/短划线_8.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程0:插入时间为00:00:21
总运行时间:00:03:27
Scribe DB CLI V1.07
有8个CPU核。
解析9个输入文件。
螺纹3:开始划线_20170511/短划线_3.数据
螺纹1:开始划线_20170511/短划线_4.数据
螺纹2:开始划线_20170511/短划线_1.数据
线程0:开始划线_20170511/short_划线_0.data
螺纹4:开始划线_20170511/短划线_2.数据
螺纹5:开始划线_20170511/短划线_5.数据
线程3:准备1000000行花费了00:00:03
线程3:将结果加载到数据库中。
线程0:准备1000000行花费了00:00:03
线程0:正在将结果加载到数据库中。
线程2:准备1000000行花费了00:00:03
线程2:将结果加载到数据库中。
线程4:准备1000000行花费了00:00:03
线程4:将结果加载到数据库中。
线程1:准备1000000行花费了00:00:03
线程1:将结果加载到数据库中。
线程5:准备1000000行花费了00:00:03
线程5:将结果加载到数据库中。
线程0:插入时间为00:02:20
线程0:开始划线_20170511/短划线_6.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程1:插入时间为00:02:44
线程1:启动划线器_20170511/短划线器_7.数据
线程1:准备1000000行花费了00:00:01
线程1:将结果加载到数据库中。
线程5:插入时间为00:03:01
螺纹5:开始划线_20170511/短划线_8.数据
线程5:准备1000000行花费了00:00:01
线程5:将结果加载到数据库中。
线程3:插入时间为00:03:07
线程4:插入时间为00:03:10
线程2:插入时间为00:03:14
线程0:插入时间为00:01:37
线程1:插入时间为00:01:20
线程5:插入时间为00:01:06
总运行时间:00:04:14
Scribe DB CLI V1.08
有8个CPU核。
解析9个输入文件。
螺纹5:开始划线_20170511/短划线_4.数据
线程1:开始划线_20170511/短划线_1.数据
螺纹3:开始划线_20170511/短划线_2.数据
螺纹4:开始划线_20170511/短划线_5.数据
线程0:开始划线_20170511/short_划线_0.data
螺纹2:开始划线_20170511/短划线_3.数据
线程5:准备1000000行花费了00:00:03
线程5:将结果加载到数据库中。
线程4:准备1000000行花费了00:00:03
线程4:将结果加载到数据库中。
线程1:准备1000000行花费了00:00:03
线程1:将结果加载到数据库中。
线程3:准备1000000行花费了00:00:03
线程3:将结果加载到数据库中。
线程0:准备1000000行花费了00:00:03
线程0:正在将结果加载到数据库中。
线程2:准备1000000行花费了00:00:03
线程2:将结果加载到数据库中。
线程0:插入时间为00:01:43
线程0:开始划线_20170511/短划线_6.1数据
线程0:准备1000000行花费了00:00:01
线程0:正在将结果加载到数据库中。
线程5:插入时间为00:02:00
螺纹5:开始划线_20170511/短划线_7.数据
线程5:准备1000000行花费了00:00:01
线程5:将结果加载到数据库中。
线程2:插入时间为00:02:02
螺纹2:开始划线_20170511/短划线_8.数据
线程4:插入时间为00:02:04
线程3:插入时间为00:02:04
线程2:准备1000000行花费了00:00:01
线程2:将结果加载到数据库中。
线程1:插入时间为00:02:06
线程0:插入时间为00:00:59
线程5:插入时间为00:00:49
线程2:插入时间为00:00:48
总运行时间:00:02:57
我在看什么?我