0

異なる(!)テーブルの行数をカウントし、ある種の統計のために結果を保存する必要があります。スクリプトは非常にシンプルで期待どおりに機能しますが、(この場合は)8つのサブクエリで単一のクエリを使用する方がよいのか、それとも個別の8つのクエリを使用する必要があるのか​​、それとももっと優れた、より高速な、より多くのクエリがあるのか​​疑問に思っています。高度なソリューション...

プリペアドステートメントでMySQLiを使用しているため、単一のクエリは次のようになります。

$sql = 'SELECT
            (SELECT COUNT(cat1_id) FROM `cat1`),
            (SELECT COUNT(cat2_id) FROM `cat2`),
            (SELECT COUNT(cat2_id) FROM `cat2` WHERE `date` >= DATE(NOW())),
            (SELECT COUNT(cat3_id) FROM `cat3`),
            (SELECT COUNT(cat4_id) FROM `cat4`),
            (SELECT COUNT(cat5_id) FROM `cat5`),
            (SELECT COUNT(cat6_id) FROM `cat6`),
            (SELECT COUNT(cat7_id) FROM `cat7`)';

$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($var1, $var2, $var3, $var4, $var5, $var6, $var7, $var8);
$stmt->fetch();
$stmt->free_result();
$stmt->close();

個別のクエリは次のようになります(x 8):

$sql = 'SELECT
            COUNT(cat1_id)
        FROM
            `cat1`';

$stmt = $db->prepare($sql);
$stmt->execute();
$stmt->bind_result($var1);
$stmt->fetch();
$stmt->free_result();
$stmt->close();

したがって、この種のクエリ(統計、カウンターなど)に関連して、より高速または「より良いスタイル」になります。

4

4 に答える 4

0

私の傾向は、可能であれば、クエリをSELECTではなくFROMに入れることです。この例では、テーブル間の相互結合が必要です。

select c1.val, c2.val . . .
from (select count(cat1_id) as val from cat1) c1 cross join
     (select count(cat2_id as val from cat2) c2 cross join
     . . .

パフォーマンスは同じである必要があります。ただし、cat2テーブルには次のような利点があります。

select c1.val, c2.val, c2.valnow, . . .
from (select count(cat1_id) as val from cat1) c1 cross join
     (select count(cat2_id) as val
             count(case when date >= date(now()) then cat2_id end)
      from cat2
     ) c2 cross join
     . . .

2つの値を取得するためにテーブルを2回スキャンする必要がないため、ここで実際の節約が得られます。これは、複数の値を返すようにクエリを変更する必要があることに気付いた場合にも役立ちます。

クロス結合とselect-within-selectのパフォーマンス特性は同じだと思います。本当に確認する唯一の方法は、さまざまなバージョンをテストすることです。

于 2012-08-21T01:33:33.140 に答える
-1

より良い方法は、1つのクエリのみを使用することです。これは、データベースとの接続が1つだけであるためです。多くのクエリを使用する場合は、データベースとの接続が多くなります。このプロセスには、接続と切断が含まれますが、これはより低速です。

于 2012-08-21T01:18:49.243 に答える
-1

コメントをフォローアップするために、私のDBの1つを使用した例を次に示します。ここでプリペアドステートメントを使用しても、何も購入できません。この複数のクエリは、実際にはD/Bエンジンに対して1つのRPCのみを実行します。他のすべての呼び出しは、PHPランタイムシステムに対してローカルです。

$db = new mysqli('localhost', 'user', 'password', 'blog');
$table  = explode( ' ', 'articles banned comments config language members messages photo_albums photos');
foreach( $table as $t ) {
   $sql[] = "select count(*) as count from blog_$t";
}
if ($db->multi_query( implode(';',$sql) )) {
  foreach( $table as $t ) {
    if  ( ($rs  = $db->store_result() ) &&
          ($row = $rs->fetch_row()    ) ) {
       $result[$t] = $row[0];
       $rs->free();
       $db->next_result(); // you must execute one per result set
    }
  }
}
$db->close();
var_dump( $result );

興味がないので、私はstraceこれについて行いました。関連する4行は次のとおりです。

16:54:09.894296 write(4, "\211\1\0\0\3select count(*) as count fr"..., 397) = 397
16:54:09.895264 read(4, "\1\0\0\1\1\33\0\0\2\3def\0\0\0\5count\0\f?\0\25\0\0\0\10\201"..., 16384) = 544
16:54:09.896090 write(4, "\1\0\0\0\1", 5) = 5
16:54:09.896192 shutdown(4, 2 /* send and receive */) = 0

クエリとMySQLdプロセスへの応答とMySQLdプロセスからの応答の間に約1ミリ秒がありました(これはローカルホスト上にあり、結果がクエリキャッシュにあるためです)。0.8ミリ秒後にDBクローズが実行されました。そして、それは私の4歳のラップトップにあります。

于 2012-08-21T15:32:32.387 に答える
-2

TerryEの例とmulti_query(!)を使用するためのアドバイスに関して、マニュアルを確認し、ニーズに合わせてスクリプトを変更しました。最終的に、次のようなソリューションが得られました。

$sql  = 'SELECT COUNT(cat1_id) as `cat1` FROM `cat1`;';
$sql .= 'SELECT COUNT(cat2_id) as `cat2` FROM `cat2`;';
$sql .= 'SELECT COUNT(cat2_id) as `cat2_b` FROM `cat2` WHERE `date` >= DATE(NOW());';
$sql .= 'SELECT COUNT(cat3_id) as `cat3` FROM `cat3`;';
$sql .= 'SELECT COUNT(cat4_id) as `cat4` FROM `cat4`;';
$sql .= 'SELECT COUNT(cat5_id) as `cat5` FROM `cat5`;';
$sql .= 'SELECT COUNT(cat6_id) as `cat6` FROM `cat6`;';
$sql .= 'SELECT COUNT(cat7_id) as `cat7` FROM `cat7`;';

if ($db->multi_query($sql))
{ 
    do
    {
        if ($stmt = $db->store_result())
        {
            while ($row = $stmt->fetch_assoc())
            {
                foreach ($row as $key => $value)
                {
                    $count[$key] = $value;
                }
            }
            $stmt->free_result();
        }
    } while ($db->more_results() && $db->next_result());
}

TerryEの例にはいくつかの違いがありますが、結果は同じです。最初にほぼ同じ7行があることは承知していますが、WHERE句などが必要になるとすぐに、手動でクエリを追加したり例外を使用したりする必要があるforeachループよりもこのソリューションの方が好きです。とif { ... }..。

私が見る限り、私の解決策に問題はないはずです、または私は何かを逃しましたか?

于 2012-08-22T04:53:56.180 に答える