0

現在、一連の計算を行う sql 関数があり、次のものが適切な代替になるかどうか疑問に思っています。SQL Server を呼び出してデータを取得し、データテーブルにダンプする C# フロントエンド アプリを構築することを考えています。そこから、データをリストまたはベクトル (sqldataadaptor クラスの行) として C++ にフィードします。これはおそらく計算に適しています。ここにいくつかの仮定があります。

1.C#で行う必要があり、問題はC++を導入するかどうかだけです

2.Sql 関数は現在、一意のグループ化基準 (最大 10 個のパラメーター) を持つデータに対して 3 つまたは 4 つの select ステートメントを実行します。

-C# から C++ の事前グループにデータを渡す必要があります (または、代わりに並べ替えることができますか?)。C++ に、ある種のツリーマップまたは辞書を作成してテーブルを反復処理させることで、これを処理させる必要があります。C# で sql ステートメントを実行し、すべてのデータを既にグループ化するのは簡単ですが、C++ ジョブはやや役に立たず、粒度が高くなる可能性があります。

3.置き換えようとしているSQLの計算は、次の形式です

  select a = exp(sum(log(x))),
     b = exp(sum(log(x))),
     c = exp(sum(log(y))),
     d = exp(sum(log(z))),
     e = exp(sum(log(u)))
  from data_table
  group by e,f,g,h,k

複雑すぎず、非常に基本的な数学です。

-繰り返しになりますが、C# でこのステートメントを実行してグループ化された要素を返すのは簡単ですが、それは sum() と log() が C# で実行され、C++ が役に立たなくなることを意味します。しかし、反復ごとにテーブルに数千行、場合によっては数万行があり、これが 1 日に複数回実行される場合、C++ は数学の点で有利になります (私の直感ではそうではありません)。

4. 上記の計算は 1 つの「アカウント」に対応します。数百のアカウントがあり、data_table にはアカウントごとにそれ以上の行がない場合でも数千の行があり、これは 24 時間年中無休で実行される可能性があります。

C# の書き直しは避けられませんが、速度のために C++ を活用する理由は本当にありますか。これは主に速度のためであり、将来のメンテナンスのために分離する可能性がありますが、全体的な速度です。私がC++を使用する場合、これが進むべき道であり、このデータを操作してSQL機能の一部をエミュレートするのに最も適したデータ構造はどれでしょうか。私は基本的にグループ化する必要があり、それを非常に高速に反復します。代替手段はありますか?C++ は強制されているように感じますか? 完全に不必要です。ありがとう。

4

2 に答える 2

2

C++ は、特に問題を解決する前に、余分な複雑さを正当化するのに十分なパフォーマンス向上にはなりません。最初に C# を使用してから、ニーズが既に満たされているかどうかを確認してください。
ilent2 がコメントで述べたように、いつでもコア計算を C++ で実行し、C# から呼び出すことができます - C# コードの大部分を再利用します。

また、あなたの問題を見ると、速度の 99% は、どの言語を選択するかではなく、ソリューションをどのように実装するかにかかっているようです。取りに行こう!

于 2013-09-16T16:36:19.507 に答える
2

C# や C++ でこの種の計算を実行する利点があるとしたら、私は非常に驚かれることでしょう。SQL サーバーから C# または C++ プログラムにデータを転送するのにかかる時間は、速度の違いをはるかに上回ります。SQL サーバーは、C++ または C# コードが使用するのと同じ C または C++ ライブラリ (または少なくとも 1 つに非常に類似したもの) を引き続き使用することに注意してください。そのため、実際のexp計算log自体の速度は非常に似ています。オーバーヘッドは、SQL 要素の解析から発生します。そして、私はまったく大きな違いがあるとは思わない。

これが問題だと本当に思うなら (私はしませんが、私はあなたがしている作業に責任を負いません...)、現実的な値を持ついくつかのテーブルでテストケースを構築することをお勧めします.と現実的なサイズ (そしておそらく少し大きい) を比較し、値を計算する速度と値を直接フェッチする速度を比較します (純粋な SQL コードで - 使用できる SQL コマンドライン ツール、またはいくつかの Web があると思います)。 -インターフェイスまたは計算を実行できるようにするもの)。おそらくsum、値だけを返すこともできます。

編集: 私は PHP をいくつか書きました (私のマシンには既に PHP + MySQL 環境がほとんどインストールされているため)。[いいえ、それらは私のユーザー名とパスワードの組み合わせではありません。そのような公開サーバーに投稿するつもりはありません!]

<?php

$dbconnect = mysql_connect("localhost", "username", "password");
if (!$dbconnect)
{
    die('Could not connect: ' . mysql_error());
}
mysql_select_db("test", $dbconnect) 
    or die ("Couldn't connect to database: " . mysql_error() );

echo "Argv[1]=" . $argv[1] . "\n";


if ($argv[1] == "Create")
{
    $rm = getrandmax();
    for($i = 0; $i < 100000; $i++)
    {
        $a = rand() / $rm;
        $b = rand() / $rm;
        $c = rand() / $rm;
        $d = rand() / $rm;
        $e = rand() / $rm;
        $f = rand() / $rm;
        $sql = "INSERT INTO test1 (id, a, b, c, d, e, f) VALUES (" 
            . $i . 
            ", " .  $a . ", " . $b . ", " . $c . ", " . $d . ", " . $e
            . ", " . $f . ");";
        if (mysql_query($sql, $dbconnect) === false)
        {
            die("Could not add element " . mysql_error());
        }
    }
}

if ($argv[1] == "ExpSumLog")
{
    $sql = "SELECT exp(sum(log(a))) AS a1,
                 exp(sum(log(b))) AS b1,
                 exp(sum(log(c))) AS c1,
                 exp(sum(log(d))) AS d1,
                 exp(sum(log(e))) AS e1
          FROM test1
          GROUP BY e,f,id";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    $sum = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }

    echo "Sum=" . $sum . ", count=" . $count . "\n";
}


if ($argv[1] == "Sum")
{
    $sum = 0;
    $sql = "SELECT sum(a) AS a1,
                 sum(b) AS b1,
                 sum(c) AS c1,
                 sum(d) AS d1,
                 sum(e) AS e1
          FROM test1
          GROUP BY e,f,id";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }

    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

if ($argv[1] == "List")
{
    $sum = 0;
    $sql = "SELECT * FROM test1;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a'];
    }

    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

if ($argv[1] == "SumA")
{
    $sum = 0;
    $sql = "SELECT sum(a) FROM test1;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['sum(a)'];
    }

    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

if ($argv[1] == "ExpSumLogA")
{
    $sum = 0;
    $sql = "SELECT sum(exp(log(a))) AS a1 FROM test1;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }
    echo "Sum=" . $sum . ", count=" . $count . "\n";
}   
?>

作成には約 55 分かかります... 幸いなことに、他の手順ははるかに高速です。

Argv[1]=ExpSumLog
Sum=50017.011061374, count=100000

real    0m1.102s
user    0m0.289s
sys 0m0.066s
Argv[1]=Sum
Sum=50017.011061374, count=100000

real    0m1.004s
user    0m0.278s
sys 0m0.055s
Argv[1]=List
Sum=50017.011061374, count=100000

real    0m0.993s
user    0m0.322s
sys 0m0.060s
Argv[1]=SumA
Sum=50017.011061374, count=1

real    0m0.068s
user    0m0.019s
sys 0m0.012s
Argv[1]=ExpSumLogA
Sum=50017.011061374, count=1

real    0m0.095s
user    0m0.024s
sys 0m0.017s

ご覧のとおり、実際の計算を実行するのにかかる時間は、すべてのデータをコピーするのにかかる時間よりもはるかに短いです。また、データを sum(exp(log(a))) と sum(a) として計算する場合の違いはわずかに異なります (ただし一貫して異なります - ExpSumLogA と SumA では、すべての実行が約 20 ~ 30 ミリ秒遅くなります)。

主要なポイントがデータ転送であることを証明するために、次の 4 つのバリアントを追加しました。

if ($argv[1] == "SortedA")
{

    $sum = 0;
    $sql = "SELECT a AS a1 FROM test1 ORDER BY a;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }
    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

if ($argv[1] == "SortedExpLogA")
{

    $sum = 0;
    $sql = "SELECT exp(log(a)) AS a1 FROM test1 ORDER BY a;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }
    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

if ($argv[1] == "UnsortedA")
{

    $sum = 0;
    $sql = "SELECT a AS a1 FROM test1;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }
    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

if ($argv[1] == "UnsortedExpLogA")
{

    $sum = 0;
    $sql = "SELECT exp(log(a)) AS a1 FROM test1;";
    $result = mysql_query($sql, $dbconnect) or die("Failed " . mysql_error());
    $count = 0;
    while($row = mysql_fetch_assoc($result))
    {
        $count++;
        $sum += $row['a1'];
    }
    echo "Sum=" . $sum . ", count=" . $count . "\n";
}

明らかに、これらの亜種はすべてのデータをエクスポートするよりも速く実行されますが、「値を 1 つだけ返す」ものよりは遅くなります。

Argv[1]=SortedA
Sum=50017.011061375, count=100000

real    0m0.375s
user    0m0.194s
sys 0m0.027s
Argv[1]=SortedExpLogA
Sum=50017.011061375, count=100000

real    0m0.394s
user    0m0.202s
sys 0m0.023s

Argv[1]=UnsortedA
Sum=50017.011061374, count=100000

real    0m0.353s
user    0m0.206s
sys 0m0.018s
Argv[1]=UnsortedExpLogA
Sum=50017.011061374, count=100000

real    0m0.383s
user    0m0.223s
sys 0m0.025s

ご覧のとおり、ソート済みの方が未ソートよりも時間がかかります (100K のアイテムをソートする必要がある場合は、時間が追加されると予想されます)。 A」の変種。このようにかなり一貫しています。

于 2013-09-16T16:42:51.240 に答える