2016-09-13 14 views
-2

私は現在、4.9452秒を実行している重いスクリプト(クエリ)を最適化しようとしています。 PHPのwhileループが返されるものに基づいていくつかの配列を設定しますが、それは別の問題です。MySQLスクリプトの最適化 - 異なるテーブルのユーザー、ユーザーアドレス、国

EDIT - usersテーブルは〜9000行、user_addressテーブルは〜3000行、shop_countries〜200行です。ここで

は私のクエリです:

SELECT 
      users.id AS user_id, 
      users.unique_code AS user_unique_code, 
      users.first_name AS user_first_name, 
      users.surname AS user_surname, 
      users.organisation AS user_organisation, 
      users.telephone AS user_telephone, 
      users.email AS user_email, 
      users.password AS user_password, 
      users.newsletter AS user_newsletter, 

      user_address.id AS user_address_id, 
      user_address.user_id AS user_address_user_id, 
      user_address.nickname AS user_address_nickname, 
      user_address.address_type AS user_address_type, 
      user_address.address_line_1 AS user_address_line_1, 
      user_address.address_line_2 AS user_address_line_2, 
      user_address.address_line_3 AS user_address_line_3, 
      user_address.city AS user_address_city, 
      user_address.postcode AS user_address_postcode, 
      user_address.country_id AS user_address_country_id, 

      shop_countries.printable_name 
      FROM users 
      LEFT JOIN user_address ON users.id = user_address.user_id 
      LEFT JOIN shop_countries ON shop_countries.id = user_address.country_id 
      WHERE (users.surname != "" OR users.first_name != "") 
      ORDER BY users.surname ASC, users.first_name ASC; 

私は、彼らがそれらに割り当てられたアドレスを持っている場合に関係なく、すべてのユーザーを選択し、[が利用可能アドレスがある場合、どの国を添付する必要があります。ここで

の結果は、EXTENDED

http://imgur.com/a/UlVX3

をEXPLAINされたこれまでのところ、私がちょうどJOINLEFT JOINを変更した場合、クエリは1秒未満で実行されるようです。問題がある場合は、アドレスを持っているかどうかにかかわらず、すべてのユーザーが必要です。

PHPスクリプト

私の設計上の参考のため、対応するPHP関数を参照してくださいしたい人のために、下記を参照してください。

function getAllUsersWithAddresses() { 

$customers = array(); 

$sql = 'SELECT 
      users.id AS user_id, 
      users.unique_code AS user_unique_code, 
      users.first_name AS user_first_name, 
      users.surname AS user_surname, 
      users.organisation AS user_organisation, 
      users.telephone AS user_telephone, 
      users.email AS user_email, 
      users.password AS user_password, 
      users.newsletter AS user_newsletter, 

      user_address.id AS user_address_id, 
      user_address.user_id AS user_address_user_id, 
      user_address.nickname AS user_address_nickname, 
      user_address.address_type AS user_address_type, 
      user_address.address_line_1 AS user_address_line_1, 
      user_address.address_line_2 AS user_address_line_2, 
      user_address.address_line_3 AS user_address_line_3, 
      user_address.city AS user_address_city, 
      user_address.postcode AS user_address_postcode, 
      user_address.country_id AS user_address_country_id, 

      shop_countries.printable_name 
      FROM users 
      LEFT JOIN user_address ON users.id = user_address.user_id LEFT JOIN shop_countries ON shop_countries.id = user_address.country_id WHERE (users.surname != "" OR users.first_name != "") ORDER BY users.surname ASC, users.first_name ASC;'; 

$users_query = mysql_query($sql); 

$customers = array(); 

while($row = getData($users_query)) { 
    if(!isset($customers[$row['user_id']])) { 
     $customers[$row['user_id']] = array(
      'id'   => $row['user_id'], 
      'unique_code' => $row['user_unique_code'], 
      'first_name' => $row['user_first_name'], 
      'surname'  => $row['user_surname'], 
      'organisation' => $row['user_organisation'], 
      'telephone' => $row['user_telephone'], 
      'email'  => $row['user_email'], 
      'password'  => $row['user_password'], 
      'newsletter' => $row['user_newsletter'] 
     ); 
    } 

    if(isset($customers[$row['user_id']]) && !empty($row['user_address_type'])) { 
     $customers[$row['user_id']]['addresses'][$row['user_address_type']][] = array(
      'id' => $row['user_address_id'], 
      'user_id' => $row['user_address_user_id'], 
      'nickname' => $row['user_address_nickname'], 
      'address_type' => $row['user_address_type'], 
      'address_line_1' => $row['user_address_line_1'], 
      'address_line_2' => $row['user_address_line_2'], 
      'address_line_3' => $row['user_address_line_3'], 
      'city' => $row['user_address_city'], 
      'postcode' => $row['user_address_postcode'] 
     ); 
    } else { 
     $customers[$row['user_id']]['addresses'] = array(); 
    } 
} 

return $customers; 
} 
+0

trhe heavy scriptはどこですか? –

+0

@bub MySQLクエリの読み込みに5秒かかります。 –

+0

EXPLAINはあなたに何を言ったのですか?適切なインデックスを設定しましたか? –

答えて

0

は、あなたの外国IDS

    のインデックスを作成します。
  • user_address.user_id
  • user_address.country_id
0

私はあなたの説明計画を見ることができません - それはあなたの質問にそれを投稿した場合に役立つでしょう。しかし、可能であっても、データベースの構造を知らなくても大したことはありません。create table構文とインデックスを含めてください。理想的な世界では、索引カーディナリティーも含めることになります。

クエリを高速化する方法は2つしかありません。データベースが調べる必要がある行の数を減らすか、DBMSが返す行を見つけやすくする。

私は、コストの大部分がクエリの2 LEFT JOINから来ると思います。確かにあなたは国の完全なリストを持っていますか?それほど多くはありません。したがって、2番目の外部結合を内部結合に置き換えることができます。 (users.surname!= "" OR users.first_name!= "")

は 'OR' を使用するmysqlのクエリで根本その動作を変更することができ

。名前が不明なお客様がたくさんいますか? 5%未満であれば....

WHERE LENGTH(users.surname) AND LENGTH(users.first_name) 

... 5%を超えてインデックス化されています。

WHERE users.surname LIKE '_%' AND users.first_name LIKE '_%' 

しかし、最大のメリットは、プライマリキーと外部キーのインデックスがあることを確認することです。