#include <vector>
#include <algorithm>
#include <iostream>
#include <time.h>
using namespace std;
int main(void)
{
vector<int> values;
srand(time(0));
// vectorに適当な値を入れる
for ( int i = 0; i < 1024*1024*1024 / sizeof(int); i++ ) {
values.push_back((int)(rand()*rand()-i));
}
// ソートする
clock_t t = clock();
sort( values.begin(), values.end());
cout << "Time(sort) is "
<< (double)(clock() - t) / CLOCKS_PER_SEC << "sec." << endl;
return 0;
}
Time(sort) is 43.895sec.なるほど、確かに30秒からそう離れていません。
#include <iostream>
#include <vector>
#include <time.h>
using namespace std;
class myobject {
int myvalue;
public:
myobject() : myvalue(0){};
};
myobject *myobjects[10*1000*1000];
int test(int v)
{
return v * 1000;
}
int main(void)
{
clock_t t = clock();
// new(1千万回)
t = clock();
for ( int i = 0; i < 10 * 1000 * 1000; i++ ) {
myobjects[i] = new myobject();
}
cout << "Time(new) is "
<< (double)(clock() - t) / CLOCKS_PER_SEC << "sec." << endl;
// delete(1千万回)
t = clock();
for ( int i = 0; i < 10 * 1000 * 1000; i++ ) {
delete myobjects[i];
}
cout << "Time(delete) is "
<< (double)(clock() - t) / CLOCKS_PER_SEC << "sec." << endl;
// 関数呼出し(1千万回)
t = clock();
for ( int i = 0; i < 10 * 1000 * 1000; i++ ) {
test(i);
}
cout << "Time(function call) is "
<< (double)(clock() - t) / CLOCKS_PER_SEC << "sec." << endl;
return 0;
}
以下、実行結果(Core i7-920 Windows7 コンパイルVC++2008 デバッグモード)Time(new) is 2.065sec. Time(delete) is 2.35sec. Time(function call) is 0.26sec.Windows環境でC++だと、おおむね1秒間に約数百万個のオブジェクトが作れるようです。また、関数呼び出しは数千万回できるようです。
void replace_regex_all(
string &srcstr, const char *fstr, const char *repstr, string &dststr)
{
string tmp;
boost::regex fnd(fstr);
ostringstream t(ios::out | ios::binary);
ostream_iterator<char, char> oi(t);
boost::regex_replace(
oi,
srcstr.begin(),
srcstr.end(),
fnd,
repstr,
boost::match_default | boost::format_all);
dststr = t.str();
}
TABLE_A a INNER JOIN TABLE_B b a.KEY = b.KEYをもとにしたSQLをC++で書き実際に実行させてその実行時間をみてみましょう。
SELECT Price.CODE, RDATE, OPEN, CLOSE, NAME FROM Price INNER JOIN Company ON (Price.CODE = Company.CODE)
#include <iostream>
#include <time.h>
#include "../kz_odbc.h"
using namespace std;
int main(void)
{
kz_odbc db("DSN=Trade",true);
kz_stmt stmt(&db);
time_t t = time(NULL);
// テーブルからデータの取得
stmt, "SELECT Price.CODE, RDATE, OPEN, CLOSE, NAME "
" FROM Price INNER JOIN Company ON (Price.CODE=Company.CODE)"
, endsql;
kz_string_array result = stmt.next();
int cnt = 0;
while ( !result.empty() ) {
cout << result[0] << "," << result[1] << ","
<< result[2] << "," << result[3] << ","
<< result[4] << "\n";
result = stmt.next();
cnt++;
}
cerr << "Execute time is " << time(0) - t << "sec." << endl;
cerr << "Record count is " << cnt << "." << endl;
return 0;
}
コードですが、Wordpressに合わせて編集してますので、変なところで改行が入っていますが御勘弁を。Execute time is 131sec. Record count is 4671568.となりました。プログラムは標準出力に出力していますが、実行に際しては標準出力をファイルにリダイレクトしています。その方が実行速度は速くなります。
#include <iostream>
#include <time.h>
#include "../kz_odbc.h"
using namespace std;
int main(void)
{
kz_odbc db("DSN=Trade",true);
kz_stmt stmt(&db);
time_t t = time(NULL);
// テーブルからデータの取得
stmt, "SELECT CODE,RDATE,OPEN,CLOSE FROM Price", endsql;
kz_string_array result = stmt.next();
int cnt = 0;
while ( !result.empty() ) {
// JOINの実行(ネステッドループ)
kz_stmt stmt2(&db);
stmt2, "SELECT NAME FROM Company WHERE CODE = ? "
, result[0].c_str(), endsql;
kz_string_array result2 = stmt2.next();
cout << result[0] << "," << result[1] << ","
<< result[2] << "," << result[3] << ","
<< result2[0] << "\n";
result = stmt.next();
cnt++;
}
cerr << "Execute time is " << time(0) - t << "sec." << endl;
cerr << "Record count is " << cnt << "." << endl;
return 0;
}
実行結果は以下のとおりです。Execute time is 1714sec. Record count is 4671568.これはものすごく遅いですね。生島さんが、
#include <iostream>
#include <time.h>
#include "../kz_odbc.h"
using namespace std;
int main(void)
{
kz_odbc db("DSN=Trade",true);
kz_stmt stmt(&db);
time_t t = time(NULL);
// マスターの取得・マップの作成
map< string, string> company;
stmt, "SELECT CODE, NAME FROM Company ", endsql;
kz_string_array result = stmt.next();
while ( !result.empty() ) {
company.insert( pair< string, string>( result[0], result[1]) );
result = stmt.next();
}
// テーブルからデータの取得
stmt, "SELECT CODE,RDATE,OPEN,CLOSE FROM Price ", endsql;
result = stmt.next();
int cnt = 0;
while ( !result.empty() ) {
cout << result[0] << "," << result[1] << ","
<< result[2] << "," << result[3] << ","
<< company[ result[0] ] << "\n";
result = stmt.next();
cnt++;
}
cerr << "Execute time is " << time(0) - t << "sec." << endl;
cerr << "Record count is " << cnt << "." << endl;
return 0;
}
結果ですが、以下のとおり、実験1のコードよりも早くなっております。Execute time is 108sec. Record count is 4671568.
実験1(SQL) | 131秒 |
実験2(C++側でネステッドループ) | 1714秒 |
実験3(C++側でハッシュ) | 108秒 |
明確に結果が出ているかと思います。こんなに単純なテストの結果からでも
「SQLをばらしてJOINをC++で行えば速くなる場合がある」
ということは理解していただけれるかと思います。
また、
『SQLはオブジェクト指向言語の数十倍の効率』
というのは、単純に
「OO言語側の最適化が不十分である可能性がある」
ということも言えるでしょう。
ただ、実験3では、高々十数%しか速くなっていません。
ということであれば、通常はやはり実験1のようなコードの方がトータル(開発効率と実行効率を考えると)としては良いと思われる。実験3のような事実はあくまでも知識としてしておきたいところです。
追記、コメント欄の議論を踏まえて再度記事をアップしました。
追記、コメント欄の指摘(ローカルマシンで動かしている)を受けまして再度環境を作成して実験しました。
追記、まとめ記事を作成しました。
/**********************************************************************
数値の3桁区切り
試したコンパイル環境
VC++ .NET 2003 / WINDOWS XP Professional 64 bit edition.
GCC C++ 3.3.6 / glibc 2.3.4 / Vine Linux 4.2
**********************************************************************/
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <sstream>
std::string formatNumber(int num)
{
std::vector<int> sepnum;
int number = abs(num);
int sgn = num >= 0 ? 1 : -1;
while ( number / 1000 ) {
sepnum.push_back(number % 1000);
number /= 1000;
}
std::stringstream ss;
ss << number * sgn;
for ( std::vector<int>::reverse_iterator i = sepnum.rbegin();
i < sepnum.rend(); i++ ) {
ss << "," << std::setfill('0') << std::setw(3) << *i;
}
return std::string(ss.str());
}
using namespace std;
int main(int argc, char* argv[])
{
cout << formatNumber(0) << endl;
cout << formatNumber(1) << endl;
cout << formatNumber(12) << endl;
cout << formatNumber(123) << endl;
cout << formatNumber(1234) << endl;
cout << formatNumber(12345) << endl;
cout << formatNumber(123456) << endl;
cout << formatNumber(1234567) << endl;
cout << formatNumber(12345678) << endl;
cout << formatNumber(123456789) << endl;
cout << formatNumber(1234567890) << endl;
cout << formatNumber(-1) << endl;
cout << formatNumber(-12) << endl;
cout << formatNumber(-123) << endl;
cout << formatNumber(-1234) << endl;
cout << formatNumber(-12345) << endl;
cout << formatNumber(-123456) << endl;
cout << formatNumber(-1234567) << endl;
cout << formatNumber(-12345678) << endl;
cout << formatNumber(-123456789) << endl;
cout << formatNumber(-1234567890) << endl;
}