2011-06-30 14 views
4

このクエリをより速く実行させるにはどうすればよいですか?事前にこのクエリをより速く実行させるにはどうすればよいですか?

 
SELECT account_id, 
      account_name, 
      account_update, 
      account_sold, 
      account_mds, 
      ftp_url,   
      ftp_livestatus, 
      number_digits, 
      number_cw, 
      client_name, 
      ppc_status, 
      user_name 
FROM  
     Accounts, 
     FTPDetails, 
     SiteNumbers, 
     Clients, 
     PPC, 
     Users 

WHERE Accounts.account_id = FTPDetails.ftp_accountid 
AND  Accounts.account_id = SiteNumbers.number_accountid 
AND  Accounts.account_client = Clients.client_id  
AND  Accounts.account_id = PPC.ppc_accountid 
AND  Accounts.account_designer = Users.user_id 
AND  Accounts.account_active = 'active' 
AND  FTPDetails.ftp_active = 'active' 
AND  SiteNumbers.number_active = 'active' 
AND  Clients.client_active = 'active'  
AND  PPC.ppc_active = 'active' 
AND  Users.user_active = 'active' 
ORDER BY 
     Accounts.account_update DESC 

感謝:)

は、クエリ結果をEXPLAIN:

first part of table

second part of table

私は本当に設定外部キーを持っていません...私は、データベースに変更を加えるのを避けようとしていましたが、完了する必要がありますすぐにオーバーホール。

主キーのみが各テーブルのIDです。 account_id、ftp_id、ppc_id ...

+1

あなたがテーブルの上にどのようなインデックスを持っていますか? –

+1

索引と、評価する人のためのEXPLAIN出力を掲示します。さもなければ彼らはちょうど推測するでしょう。 – jishi

+1

...とEXPLAINプラン、および各テーブルの行数とインデックスの基数 – symcbean

答えて

3

EXPLAINを使用して、使用できるインデックスと実際に使用されているインデックスを確認します。必要に応じて適切なインデックスを作成します。

FTPDetails.ftp_activeには2つの有効なエントリがある場合は、'active''inactive'のデータタイプとしてBOOLを使用してください。サイドノートとして

:私は強く、明示的な使用することをお勧め代わりに、暗黙的なものの加入:結合条件が結合されているテーブルの名前に近いため

SELECT 
    account_id, account_name, account_update, account_sold, account_mds, 
    ftp_url, ftp_livestatus, 
    number_digits, number_cw, 
    client_name, 
    ppc_status, 
    user_name 
FROM Accounts 
INNER JOIN FTPDetails 
    ON Accounts.account_id = FTPDetails.ftp_accountid 
    AND FTPDetails.ftp_active = 'active' 
INNER JOIN SiteNumbers 
    ON Accounts.account_id = SiteNumbers.number_accountid 
    AND SiteNumbers.number_active = 'active' 
INNER JOIN Clients 
    ON Accounts.account_client = Clients.client_id 
    AND Clients.client_active = 'active' 
INNER JOIN PPC 
    ON Accounts.account_id = PPC.ppc_accountid 
    AND PPC.ppc_active = 'active' 
INNER JOIN Users 
    ON Accounts.account_designer = Users.user_id 
    AND Users.user_active = 'active' 
WHERE Accounts.account_active = 'active' 
ORDER BY Accounts.account_update DESC 

これは、クエリがはるかに読みやすくなります。

+0

ありがとうthats 2秒速く:) 私は説明を実行しましたが、情報が実際に私に何を伝えているのか分かりませんか?または使用方法... – JPickup

+0

@JPickup:ここに説明プランを掲載し、質問に追加してください。 –

0

説明、異なるベンチマークをベンチマークする。まず、いくつかのクエリがこのモンスターより速くなると確信しています。まず、クエリオプティマイザは、どの結合順序が最適かを調べるのに多くの時間を費やすので(5!= 120の可能性)次に、SELECT ... WHERE ....active = 'active'のようなクエリがキャッシュされます(データの変更量にもよりますが)。

+0

私は今までに複数のステートメントを使用してきましたが、ユーザーが任意の値で結果をフィルタリングするための関数を追加するように求められました...そして、その中のすべてのデータを選択せず​​に行う方法を知らないselectステートメント? – JPickup

+0

良いオプティマイザはすべての可能性を調べません。このクエリは120をはるかに超えます(JOINを実行する順序だけでなく、すべてのJOINにどのようなメソッドを使用するか、条件を確認するためにどのインデックスを使用するか)。 –

+0

@ypercube良いオプティマイザは[設定可能]です(http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#sysvar_optimizer_search_depth)。 – DrTyrsa

4

インデックス

  • あなたが必要 - 少なくともからJOIN条件で使用されているすべてのフィールドにインデックス。

  • WHEREまたはGROUP BYまたはORDER BYの句に表示されるフィールドのインデックスも、ほとんどの場合便利です。

  • JOIns(またはWHEREまたはGROUP BYまたはORDER BY)で2つ以上のフィールドが使用されている場合、これらの(2つ以上の)フィールドの複合インデックスが別々のインデックスより優れている可能性があります。たとえば、SiteNumbersテーブルでは、可能なインデックスは、化合物(number_accountid, number_active)または(number_active, number_accountid)です。

  • ブール型(ON/OFF、アクティブ/非アクティブ)のフィールドの条件は、インデックスが選択的でないため、あまり有用ではないため、クエリが遅くなることがあります。その場合、テーブルの再構築(父親の正規化)はオプションですが、複雑さを避けることができます。通常のアドバイスのほか


私はあなたのクエリに部分的デカルト製品があることに気づくを(必要に応じて、インデックス、クエリのテストのバリエーションを追加し、EXPLAIN計画を検討します)。テーブルAccountsは、3つのテーブルFTPDetails,SiteNumbersおよびPPCと1対多の関係を持っています。これは、たとえば1000個のアカウントを持ち、すべてのアカウントが10個のFTPDetails、20個のSiteNumbers、3個のPPCに関連している場合、クエリはすべてのアカウント600行(10x20x3の積)で返されます。多くのデータが複製される合計600,000行。

代わりに、ベースデータ(アカウントと残りのテーブル)のクエリを3つ以上に分割することもできます。

Accounts JOIN Clients JOIN Users 
    (with all fields needed from these tables) 
    1K rows 

Accounts JOIN FTPDetails 
    (with Accounts.account_id and all fields from FTPDetails) 
    10K rows 

Accounts JOIN SiteNumbers 
    (with Accounts.account_id and all fields from SiteNumbers) 
    20K rows 

Accounts JOIN PPC 
    (with Accounts.account_id and all fields from PPC) 
    3K rows 

し、次いで合わせた情報を表示するクライアント側の4つのクエリからのデータを使用する:その方法は、(短い長さを有する)のデータのみ34K行が転送されることになります。



私は、次のインデックス追加します。あなたの主な問題の

Table Accounts 
    index on (account_designer) 
    index on (account_client) 
    index on (account_active, account_id) 
    index on (account_update) 

Table FTPDetails 
    index on (ftp_active, ftp_accountid) 

Table SiteNumbers 
    index on (number_active, number_accountid) 

Table PPC 
    index on (ppc_active, ppc_accountid) 
+0

なぜ 'テーブルクライアント インデックス(クライアントID、クライアントアクティブ)'と 'テーブルユーザ インデックス(user_id、user_active)'? – Ron

+1

@sunrong「クライアント」と「ユーザ」にインデックス提案を追加しなかった理由を覚えていません。私の答えと質問を読み返してみると、(クライアントとユーザー)は、1対1の関係ではなく、アカウントと1対1の関係を持つように扱われていたと思います。インデックスもそこに役立つはずです。 –

0

一つはここにある:x.y_active = 'active'

問題:アクティブなフィールドがある
低カーディナリティブール値フィールドは2つの可能な値を持ち、カーディナリティーが非常に低くなります。 MySQL(または、その行に30%以上の行が同じ値を持つ場合、その問題のSQLはインデックスを使用しません)。
インデックスを強制的に使用すると、クエリーが遅くなります。

ソリューション:ソリューションはactive列で、あなたのテーブルを分割することである
あなたのテーブルを分割します。
これは非アクティブなフィールドをすべて考慮から除外し、実際にxxx-activeフィールドに実際のインデックスがあるかのようにselectを動作させます。

追記
これまで暗黙のwhereが、それはあまりにもエラーが発生しやすいと有用であることがconsufingだ、結合を使用しないでください。
代わりにOswald's answerのような構文を使用してください。

リンク:
カーディナリティ:http://en.wikipedia.org/wiki/Cardinality_(SQL_statements)
カーディナリティとインデックス:http://www.bennadel.com/blog/1424-Exploring-The-Cardinality-And-Selectivity-Of-SQL-Conditions.htm
MySQLのパーティショニング:http://dev.mysql.com/doc/refman/5.5/en/partitioning.html

+0

データベースの設計とSQL文についてお勧めする書籍や資料がありますか? – JPickup

関連する問題