2012-01-06 12 views
1

データベース上の複数の列にわたって1つの入力をクエリするMETAデータ(列名)を収集する必要のあるAJAXクエリを構築しています。MySQL MySQL /クエリ効率でSELECT *が実際にどのように機能するのですか

// The joins might not make sense I took the database name out, since it is 
// the same as the company I work for... 
$querySyntax = "SELECT 
        idAccount, 
        FirstName, 
        LastName, 
        Email, 
        Phone, 
        CCCity, 
        CCState 
       FROM 
        account Right Join 
        states On account.CCState = 
        states.ID WHERE "; 

$cols = $dbo->query("SELECT * FROM account"); 

$colcount = (count($cols) > 0 ? $cols->columnCount() : count($cols)); 

for ($ii=0; $ii < count($search); $ii++) { 
    if ($ii>0) 
     $querySyntax = $querySyntax . " AND "; 
     $querySyntax = $querySyntax . "("; 

    for ($i=0; $i<$colcount; $i++) { 
     if ($i>0) 
      $querySyntax = $querySyntax . " OR "; 
      $meta = $cols->getColumnMeta($i); 
      $colNames[$i] = $meta['name']; 
      $querySyntax = $querySyntax . $colNames[$i] . " LIKE '%" . $search[$ii] . "%'"; 

     } 
     $querySyntax = $querySyntax . ")"; 

    } 

    $querySyntax .= " LIMIT 50"; 

$found = $dbo->query($querySyntax); 
for($i=0; $row=$found->fetch();$i++) { 
     $result[$i] = $row; 
} 

[OK]を、それと言っている:ジョン・アンダーソンと[email protected]の電子メールアドレス、「とは」アンダーソンと[email protected]

クエリは次のようになりますが、一致します"SELECT * ..."クエリよりも列名を取得する方が良い方法はありますか?

SELECT *を実行すると、実際には各レコードがメモリに読み込まれて格納されますか?私たちが持っている何千ものレコードがデータベースに取り込まれると、これは非常に遅くなる可能性があります。

+3

であるべき。 – jValdron

+0

列のリストの後にある場合は、単に「制限1」を使用して単一のレコードを取得するだけでは、メタデータが必要な場合はすべてのレコードを返す必要はありませんか? – dougajmcdonald

+1

問題が発生するまでパフォーマンスを心配しないでください。それまでは、製品をドアの外に出すなど、もっと重要なことに重点を置いています。 – cdeszaq

答えて

2

これはかなり無駄です。はい、このテーブルからすべてのレコードを取得します。列の一覧表示だけに興味がある場合は、おそらくSHOW COLUMNS FROM <your table>ステートメント(docs)を使用して列の一覧を取得することができます。また、すべてのクエリの前に、の前に行うべきではありません。ユーザーセッション中に実際に変更する可能性が低いので、一度やり直してから列リストを保存する方がいいでしょうか?

+0

ありがとう!結果を保存するための非常に良いアイデア! – guyfromfl

4

SHOW COLUMNS(およびほとんどの他のSHOWコマンドはクエリメタデータ)は、内部的にINFORMATION_SCHEMAに対するクエリとして機能します。 When you do thatのInnoDBテーブルに対して、MySQLはそれぞれのテーブルからランダムなページを照会してテーブルの統計情報を更新しようとします。その結果、INFORMATION_SCHEMAに対するSHOWコマンドとクエリは非常に遅いです。

いくつかの回避策があります。

  1. SET GLOBAL innodb_stats_on_metadata=0テーブルの統計の自動再計算にあなたがInnoDBテーブルのメタデータを表示するたびに無効にします。

    Peter Zaitsevの最近のブログSolving INFORMATION_SCHEMA slownessとマニュアルDynamically Changing innodb_stats_on_metadataを参照してください。

  2. を使用すると、INFORMATION_SCHEMAを照会するよりもはるかに高速です。

  3. PDOStatement::getColumnMeta()を使用してください。ただし、query()の代わりにprepare()を使用してください。そのため、クエリは解析されますが、実行されたり結果の行を取得しようとはしません。 getColumnMeta()が "experimental"で、たぶんバグがあるので注意深くテストしてください。

しかし、あなたはそのLIKE '%search%'述語will perform poorly anywayがあります。 Sphinx SearchやApache Solrのようなフルテキスト検索ソリューションを使うべきです。


PS:PHPでループをコーディングする場合は、ループの繰り返しごとではなく、ループの前に一度カウントを計算する方がよいでしょう。あなたがやったようにあなたは、それらすべてに名前を付けるに固執する、すべてのフィールドを使用していない場合

for ($ii=0; $ii < count($search); $ii++) { 

$c = count($search); 
for ($ii=0; $ii < $c; $ii++) { 
+0

ヒントありがとう!あなたは本当にあなたのMySQLを知っています。以前あなたの投稿に投稿しました。ループチップにも感謝します。私はそれについて考えたことはありませんでしたが、count()関数のテストを1回終了しました... PS、私はあなたの本を注文しました:D – guyfromfl

+0

セカンダリを作成するとMySQLの 'FULLTEXT'インデックス機能を使うこともできますMyISAM型の検索用のテーブルです。 – tadman

+1

@tadman、ええと、ありがたいことにInnoDBの全文はMySQL 5.6に入っています。 –

関連する問題