SQL使用C - 瓶颈在哪里
SQL using C++ - Where is the bottleneck?
我正在尝试通过行读取纯文本文件,构造SQL插入语句,执行查询并继续进行。目前,我有一个解决方案,可以在约4岁的桌面上每秒完成约200行。但是,我有大约1.2亿行可以通过,并希望将其作为日常任务实施。花费几个小时才能完成,但是花了将近一周的时间是一个选择。
这些线将包含一个字符串,从5到9个整数从布尔值(我用作tinyint(1))到午夜以来的微秒(bigint)。
一旦从文件中读取(通过getline()),该函数将对线进行标记:
#define MAX_TOKENS 10
#define MAX_TOKEN_LENGTH 32
char tokens[MAX_TOKENS][MAX_TOKEN_LENGTH];
//...
void split_line(const string &s)
{
char raw_string[MAX_TOKENS * MAX_TOKEN_LENGTH];
char *rest;
char *token_string;
strcpy(raw_string, s.c_str());
if(tokens[0][0] != ' ')
{
fill(tokens[0], tokens[0]+(MAX_TOKENS*MAX_TOKEN_LENGTH), ' ');
}
for(uint32_t token = 0; token < MAX_TOKENS; token++)
{
if(token == 0) token_string = strtok_r(raw_string, " ", &rest);
else token_string = strtok_r(nullptr, " ", &rest);
if(token_string == nullptr) break;
if(token >= 1)
{
//if it's not a number...
if(token_string[0] < 48 || token_string[0] > 57)
{
if(token_string[0] != 45) //negative numbers are allowed
{
clear_tokens();
break;
}
}
}
strcpy(tokens[token], token_string);
}
}
我尝试了该令牌的更为STL派生版本,但事实证明太慢了。它在呼叫图中仍然排名很高,但不如适当的STL字符串高。
无论如何,下一步是构建SQL查询。为此,我尝试了一些事情。一个选项是弦乐。
string insert_query = "INSERT INTO data_20170222";
stringstream values;
string query;
while(getline(input_stream, input_stream_line))
{
split_line(input_stream_line);
if(tokens[5][0] != ' ') //the smallest line will have six tokens
{
try
{
query = insert_query;
uint32_t item_type = stoi(tokens[2]);
switch(item_type)
{
case 0: //one type of item
case 1: //another type of item
{
values << " (valueA, valueB, valueC, valueD, valueE, valueF,"
" valueG, valueH) values('"
<< tokens[0] << "', " << tokens[1] << ", "
<< tokens[2] << ", " << tokens[3] << ", "
<< tokens[4] << ", " << tokens[5] << ", "
<< tokens[6] << ", " << tokens[7] << ")";
break;
}
//...
}
query.append(values.str());
values.str(string());
values.clear();
if(mysql_query(conn, query.c_str()))
{
string error(mysql_error(conn));
mysql_close(conn);
throw runtime_error(error);
}
}
catch(exception &ex)
{
cerr << "Error parsing linen '" << input_stream_line
<< "'n" << " " << ex.what() << endl;
throw;
}
}
当我运行此版本时,我看到Callgrind的样本中有30%在std ::操作员&lt;&lt;在std :: basic_ostream。
我最初尝试用字符串进行所有操作,ala:
string values;
values = " (valueA, valueB, valueC, valueD, valueE, valueF,"
" valueG, valueH) values('" +
string(tokens[0]) + "', " + tokens[1] + ", "
tokens[2] + ", " + tokens[3] + ", "
tokens[4] + ", " + tokens[5] + ", "
tokens[6] + ", " + tokens[7] + ")";
事实证明是相同的速度,但是这次是将30%的样本分配给std :: operator std :: basic_string。
最后,我切换到了直sprintf()。
char values[MAX_TOKENS * MAX_TOKEN_LENGTH];
sprintf(values, " (valueA, valueB, valueC, valueD, valueE, valueF,"
" valueG, valueH) values('%s', %s, %s, %s, %s, %s, %s, %s)",
tokens[0], tokens[1], tokens[2], tokens[3],
tokens[4], tokens[5], tokens[6], tokens[7]);
弦乐流比字符串快一些(尽管在合理的误差范围内)。Sprintf()比这两个都快10%,但这还不够快。
肯定有一种完善的方法可以通过如此大的数据集来完成此任务。在这一点上,我将感谢任何指导。
编辑
哦,哇。我一时兴起评论了对mysql_query()的电话。事实证明,尽管Valgrind所说的话,但这就是我所有的放缓。没有该障碍,它从每秒200行增加到每秒120万行。这还差不多!太糟糕了,我需要数据库中的数据...
我猜这已经成为一个问题,为什么Mariadb现在似乎运作如此慢。我在这个系统中有一个很好的SSD,16GB RAM等。它使我的硬件不可能阻止它。
更加好奇。预先感谢您的任何帮助!
批处理 INSERTing
100行每 INSERT
语句的运行快10倍。
您需要每天插入120m行吗?每秒1400。您是否计算出多久才能用完磁盘空间?
让我们看看SHOW CREATE TABLE
。当INT
(4个字节)就足够时,请勿使用BIGINT
(8个字节)。当MEDIUMINT
(3个字节)会这样做时,请勿使用INT
。等。
您将使用数十亿行的数据做什么?请记住,即使使用SSD,也需要很长时间的SELECT
与索引差的表相差很长。
可以将一个字符串归一化?
考虑将一堆布尔人包装到SET
中(每8个布尔值1个字节)或某种尺寸int。
让我们看看SHOW CREATE TABLE
和主SELECTs
。
innodb_flush_log_at_trx_commit
的值是多少?使用2。