2017-12-23 10 views
1

は私が要求されたデータかどうかが存在する、だから、どのパスがより効率的高速であるかどうかを確認したい、私はそれからデータを引き出し億を超える記録長期間および重いデータでは、どのPDO SQLクエリが高速ですか?表から

を持っていますもう一方? idPRIMARY (INT)で、aid, ridはほとんど測定可能とあなたはほぼ確実に等価です示しINDEXED (INT)

+0

FYI問合せの最適化に関するヘルプを求める質問は、問合せの各表に対する「SHOW CREATE TABLE」の出力を含める必要があるため、データ型、索引および制約を推測する必要はありません。多くの人のようにスクリーンショットとしてではなく、テキストで投稿してください。 –

答えて

1

二つの方法、であることを念頭に

$Query = ' 
    SELECT n.id 
    FROM names n 
    INNER JOIN ages a ON n.id = a.aid 
    INNER JOIN regions r ON n.id = r.rid 
    WHERE id = :id 
'; 

$stmt->prepare($Query); 
$stmt->execute(['id' => $id]); 
if ($stmt->rowCount() == 1) { 
    $row = $stmt->fetch(); 
    ...................... 
} else { 
    exit(); 
} 

または

$EXISTS = 'SELECT EXISTS (
    SELECT n.fname, n.lname, a.age, r.region 
    FROM names n 
    INNER JOIN ages a ON n.id = a.aid 
    INNER JOIN regions r ON n.id = r.rid 
    WHERE id = :id 
    LIMIT 1 
) 
'; 
$stmt->prepare($EXISTS); 
$stmt->execute(['id' => $id]); 
if ($stmt->fetchColumn() == 1) { 
    $stmt->prepare($Query); 
    $stmt->execute(['id' => $id]); 
    $row = $stmt->fetch(); 
    ...................... 
} else { 
    exit(); 
} 

キープパフォーマンスの違い。

SELECT n.id 
FROM names n 
INNER JOIN ages a ON n.id = a.aid 
INNER JOIN regions r ON n.id = r.rid 
WHERE id = :id 

names.idは、そのテーブルの主キーです。主キーの参照は非常に高速です。

そして、それは、他の2つのテーブルに二次キーのルックアップを行いますと、それらのテーブルの他の列への参照がありませんので、それは、索引のみのアクセスとなります。

あなたはMySQLの最適化計画を分析するためにEXPLAINを使用する方法を学ぶ必要があります。これは、SQLクエリのパフォーマンスを向上させたいときはいつでも練習すべきスキルです。

は、我々は、各テーブルへのアクセスは、(あなたがあなたの質問であなたのSHOW CREATE TABLEを提供しなかったけれども、私は、インデックスを想定しています)インデックスを使用していることがわかりhttps://dev.mysql.com/doc/refman/5.7/en/using-explain.html

mysql> explain SELECT n.id 
    ->  FROM names n 
    ->  INNER JOIN ages a ON n.id = a.aid 
    ->  INNER JOIN regions r ON n.id = r.rid 
    ->  WHERE id = 1; 

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 
| 1 | SIMPLE  | n  | NULL  | const | PRIMARY  | PRIMARY | 4  | const | 1 | 100.00 | Using index | 
| 1 | SIMPLE  | a  | NULL  | ref | aid   | aid  | 5  | const | 1 | 100.00 | Using index | 
| 1 | SIMPLE  | r  | NULL  | ref | rid   | rid  | 5  | const | 1 | 100.00 | Using index | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 

を参照してください。

サブクエリは、最初のクエリの最適化プランと同じに見えますSELECT EXISTS(...)

mysql> explain SELECT EXISTS (
    ->  SELECT n.id 
    ->  FROM names n 
    ->  INNER JOIN ages a ON n.id = a.aid 
    ->  INNER JOIN regions r ON n.id = r.rid 
    ->  WHERE id = 1 
    ->  LIMIT 1); 

+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+ 
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref | rows | filtered | Extra   | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+ 
| 1 | PRIMARY  | NULL | NULL  | NULL | NULL   | NULL | NULL | NULL | NULL |  NULL | No tables used | 
| 2 | SUBQUERY | n  | NULL  | const | PRIMARY  | PRIMARY | 4  | const | 1 | 100.00 | Using index | 
| 2 | SUBQUERY | a  | NULL  | ref | aid   | aid  | 5  | const | 1 | 100.00 | Using index | 
| 2 | SUBQUERY | r  | NULL  | ref | rid   | rid  | 5  | const | 1 | 100.00 | Using index | 
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+ 

と第二の溶液と比較。同じ方法でインデックスを使用します。しかし、それはサブクエリに委ねられています。おそらく大きな違いはありませんが、それはもう一つのことです。

唯一の利点は、SELECT EXISTS...クエリがtrue/falseの値を1行のみを返すことが保証されていることです。最初のクエリは、クエリのJOINに一致する数に応じて、ゼロ、1つ、または複数の行を含む結果セットを返すことがあります。違いはパフォーマンスの違いではありません(結果セットをクライアントに転送するのに時間がかかったり、クライアントで結果セットを保持するために大量のメモリを使用する行が多すぎる場合を除きますが)。あなたがそれをコードする方法。

+0

'LIMIT 1'を削除した場合、' SELECT EXISTS - > SELECT'をチェックする方が早いでしょうか? – Toleo

+0

マイクロ最適化に落としたときは、[microtime()](http://php.net/microtime)で両方の方法と時間を試してみてください。 –

+0

データをインデックス化すると、レコード数が100万'時代遅れ?私は100万のデータを索引付けしても、索引付けされていないかのように多くの時間がかかると考えていたので、そして、あなたが予測した通り、すべての行は、使用されるとインデックスされます。 – Toleo

0

年齢を正規化しないでください。それは単に空間と時間の無駄です。 age(それは年であると仮定)は、1バイトのTINYINT UNSIGNED(範囲:0 255)に収まるとJOIN検索を避けます。 aidは4バイトのINTのように見えますが、これは数十億の異なる値を保持できます。何十億という異なる年月がありますか?

多分regionsを変更する価値があります。

最初のクエリでは、2つのJOINsは何もしませんが、年齢と地域に行があることを確認します。それはおそらくです。

EXISTSは、1つの行が見つかると停止します。従ってLIMIT 1は非常に不必要です。

関連する問題