我正在开发一个c应用程序,它从mysql表中读取数据,处理它然后将其插入到oracle数据库中的100个不同的表中。问题在于应用程序的性能存在巨大问题。在我提到的mysql表中,有4,800,000个,其中有92列。 90个主题只是整数。因此,在我的应用程序中,每个条目为4,800,000,我正在运行for循环,如下所示。
for (col = 1; col < 92; col++) {
if (row[col] != NULL) {
sum += strtol(row[col], NULL, 10);
} else
sum = sum + 0;
if (col == 14) {
p1_2weeks = sum;
} else if (col == 31) {
p2_1month = sum;
} else if (col == 90) {
p3_2month = sum;
}
}
因此,由于这会进行大量迭代,所以我认为可能会减少使用常规添加所需的时间来完成此操作。
p1_2weeks = strtol(row[1], NULL, 10) +
strtol(row[2], NULL, 10) +
... +
strtol(row[14], NULL, 10);
p2_1months = p1_2weeks +
strtol(row[15], NULL, 10) +
... +
strtol(row[31], NULL, 10);
p3_3months = p2_1months +
strtol(row[32], NULL, 10) +
... +
strtol(row[91], NULL, 10);
所以有人可以建议哪一个更好或者其他一些方法做得对。
答案 0 :(得分:7)
使用显式添加的for
循环或手动展开不会产生显着差异。大部分时间都花在从MySQL读取并将字段转换为字符串,并将结果插入Oracle中。如果程序花费99%的时间在数据库代码中,这不会让我感到惊讶,优化这个循环将是一个没有实际意义的点。
您可能希望寻找一种从MySQL中提取不会将整数转换为字符串的值的不同方法。
分析将告诉您编译器/选项/ cpu / memory / dataset的给定组合的瓶颈在哪里,但是告诉您在程序中花费的时间以及等待Oracle进程或MySQL连接所花费的时间可能会很棘手。经过的时间是最终的判断。
请注意,您提议的替代方法在语义上不等效:在显式添加的序列中,您不测试NULL
字段。如果列不能为NULL
,则可以删除if (row[col] != NULL)
测试,如果它们可以是NULL
,则必须修改添加以添加更多测试,这将使其非常笨拙。此外,正如seleciii44所暗示的那样,提出的替代方案会生成更大的代码,这也会产生影响。
节点也认为循环非常简单,而添加的顺序容易出错:很容易产生剪切和粘贴错误并错过索引或重复索引。如果你去添加,请使用代码布局,使索引清晰。看看我如何重新格式化你的代码。
确实你在循环中有拼写错误(p2_1month
/ p2_1months
,p3_2month
/ p3_3months
)并且添加不会以同样的方式计算p3_3months
:循环总和90
天,其中加法总和为91
天。但当然,一个季度的天数从89
到92
天不等。
另请注意,sum = sum + 0;
是一个应删除的无操作,但编译器很可能不会为其生成代码。
如果您担心每次迭代执行14,31和90天的额外测试,您可以使用:
long temp[92];
for (col = 1; col < 92; col++) {
if (row[col] != NULL) {
sum += strtol(row[col], NULL, 10);
}
temp[col] = sum;
}
p1_2weeks = temp[14];
p2_1month = temp[31];
p3_3months = temp[90];
它可能比带有测试的版本更有效,但只有仔细的基准测试才会告诉您,因为现代处理器的分支预测会在将91
值存储到本地数组中时将这些测试的成本降至最低额外费用。
顺便问一下,您确定col < 92
吗?您的循环会处理91
列,但您写的只有90
列的92
是整数。
同样,我首先会寻找一种从MySQL中提取值作为整数的方法。
答案 1 :(得分:4)
我不认为自己编写附加内容会让这更快。但优化不是通过猜测进行的,而是通过测量进行的。
我对您的代码的评论是:
else
sum = sum + 0;
我希望你的编译器摆脱这个东西,否则你只是在这里浪费时间。
if (col == 14) {
p1_2weeks = sum;
} else if (col == 31) {
p2_1month = sum;
} else if (col == 90) {
p3_2month = sum;
}
虽然分支预测可以在这里帮到你很多,但也许最好将它移出for-loop。你可以在几个循环中分离,中间的每个部分计算。 (循环到14,分配p1_2weeks,循环到31,保存p2_1个月...)
答案 2 :(得分:3)
对这样的问题唯一合理的答案是对其进行分析。以最直观的方式编写它,然后看看它是否值得花费大量时间来优化并调试所有优化。
答案 3 :(得分:2)
展开循环可以通过消除循环开销提供一个小优势,但是如果循环非常大并且其中的操作非常简单< em>,在这种情况下都不是。
添加是非常简单的操作(一台机器指令),但是你错过了房间里的大象 strtol()
- 你有一个函数调用开销加上将字符串转换为整数的任何内容,该整数将是许多机器指令(也在循环中)。
此外,如果有一些可能的显着优势,编译器优化器能够自行执行循环展开。因此,这种手写的微优化几乎总是徒劳的,并且使代码难以理解且难以维护。您最好考虑整体设计和算法复杂性,并让编译器执行 作业。
无论如何,鉴于这是一个数据库应用程序,它确实会在很大程度上受到磁盘和/或网络性能的限制,并且任何代码优化总体上可能无关紧要。快速的服务器和大量的RAM可能会比任何类型的代码优化更快地加速您的应用程序。