2017-08-30 9 views
1

私は8,566件の結果を出すクエリを持っています。しかし、EXPLAINは233,190行を検索する1つのテーブルを表示していますが、なぜ表示されません。 それは、ステータス 'キーを使用して、問題テーブル(ppi_sar_status)を示しているが、クエリは「loanID」MySQL JOINが多すぎる行を検索しています

View the EXPLAIN results

SELECT DISTINCT 
     ppi_loan.loanID, 
     ppi_loan.lender, 
     ppi_loan.customerID, 
     ppi_loan.agreementNo, 
     loan_number, 
     ppi_lenders.name, 
     ppi_status.status, 
     ppi_statuses.description, 
     ppi_loan.broker, 
     (SELECT sarSent 
      FROM ppi_sar 
      WHERE ppi_sar.customerID = ppi_loan.customerID 
       AND ppi_sar.lender = ppi_loan.lender 
      ORDER BY sarSent DESC 
      LIMIT 1) as sarSent, 
     (SELECT COUNT(DISTINCT(groupID)) 
      FROM ppi_mdrs 
      WHERE ppi_mdrs.customerIDfk = ppi_loan.customerID 
       AND ppi_mdrs.lender = ppi_loan.lender 
       AND sent_to_lender = '0000-00-00 00:00:00') AS mdrs_sent, 
     (SELECT sent 
      FROM ppi_mdrs 
      WHERE ppi_mdrs.customerIDfk = ppi_loan.customerID 
       AND ppi_mdrs.lender = ppi_loan.lender 
      ORDER BY sent DESC 
      LIMIT 1) AS mdr_last_sent, 
     mobilePhone, 
     homePhone, 
     title, 
     firstName, 
     lastName, 
     loaSent 
    FROM 
     ppi_loan 
     JOIN ppi_sar_status 
      ON ppi_loan.loanID = ppi_sar_status.loanID 
     JOIN ppi_customer 
      ON ppi_loan.customerID = ppi_customer.customerID 
     JOIN ppi_lenders 
      ON ppi_loan.lender = ppi_lenders.id 
     JOIN ppi_status 
      ON ppi_loan.customerID = ppi_status.customerID 
      JOIN ppi_statuses 
       ON ppi_status.status = ppi_statuses.status 
     LEFT JOIN ppi_mdrs 
      ON ppi_loan.customerID = customerIDfk 
      AND ppi_loan.lender = ppi_mdrs.lender 
    WHERE 
      ppi_loan.customerID != 10 
     AND ppi_status.status != 9 
     AND ppi_status.status != 32 
     AND ppi_status.status != 54 
     AND ppi_status.status != 58 
     AND ppi_status.status != 59 
     AND ppi_status.status != 61 
     AND ppi_status.status != 69 
     AND ppi_status.status != 60 
     AND ppi_status.history = 0 
     AND ppi_loan.customerID 
     IN (SELECT customerID 
       FROM ppi_status 
       WHERE (status = 5 || status = 6 || status = 79) 
        AND timestamp > '2015-04-01' 
        AND ppi_status.customerID = ppi_loan.customerID) 
     AND ppi_sar_status.status = 16 
     AND ppi_sar_status.history = 0 
     AND (cc_type = '' || (cc_type != '' AND cc_accepted = 'no')) 
     AND ppi_loan.deleted = 'no' 
+0

テーブルにインデックスを設定していますか? –

+1

はい、EXPLAINの結果には可能なキーが表示されます – swdee

答えて

1

イッツによるWHERE句にdifferntキーに、そのテーブルに結合します。

ppi_sar_status.status = 16 

私はたぶんこのことを言っているが、インデックスヒントを試してみてください。 https://dev.mysql.com/doc/refman/5.7/en/index-hints.html

(しかしhttp://www.mysqldiary.com/the-battle-between-force-index-and-the-query-optimizer/警告を読むことを忘れないでください)

+0

はいppi_sar_status.status = 16ですが、結果内のローンだけがppi_sar_status.loanID = ppi_loan.loanIDに参加しています。 – swdee

+0

@swdeeクエリオプティマイザが決定したと思いますそれがより速くなると思ったので、最初にやること。このクエリに特定のパフォーマンス上の問題がありますか?クエリオプティマイザは完全に解放されているので、あるテーブルを後ではなくそのテーブルに結合する前に*必要と言った結果に切り下げることができます。それを行う順序は保証されていません。 –

+0

'ppi_sar_status.status = 16'を削除した場合、いくつの結果が得られますか? – ivo

0

クエリの可読性を清掃し、編集を掲示した後、私は「||」を見ました典型的には、言語において論理ORに関連するコンポーネントである。しかし、MySQLでは、文字列などの値を連結するものを表すようです。

あなたは、このような

WHERE (status = 5 OR status = 6 OR status = 79) 

とも..

 AND (cc_type = '' OR (cc_type != '' AND cc_accepted = 'no')) 
などの論理 "OR" を持っているべきであるように、あなたのWHERE句...

WHERE (status = 5 || status = 6 || status = 79) 
        AND timestamp > '2015-04-01' 
        AND ppi_status.customerID = ppi_loan.customerID) 
     AND ppi_sar_status.status = 16 
     AND ppi_sar_status.history = 0 
     AND (cc_type = '' || (cc_type != '' AND cc_accepted = 'no')) 

の後半では、それが見えます

改訂のお知らせ

私はあなたの明示的なインデックスを知っていませんが、インデックスをカバーし、このクエリをさらに最適化するのに役立ちます、私はあなたのそれぞれのテーブルに次のインデックスを提案します。

table   index 
ppi_sar   (customerID, lender) *or lender,customerid either way* 
ppi_mdrs  (customerIdfk, lender, sent_to_lender) *or lender,customerid,sent...* 
ppi_sar_status (loanid, status, history) 
ppi_status  (customerID, status, history, timestamp) *timestamp optional* 

しかし、今のところ私はもう1つのことをやります。 MySQLには特別なキーワード「STRAIGHT_JOIN」があります。これは、MySQLにあなたに言った順序でクエリを実行するように指示します。あなたのステータス表をプライマリとして試しています。しかし、あなたの本当の運転台はローンのものであり、FROM句の最初のものであるため、それがクエリの基礎となるべきである(SHOULD)。だから私は

に変更する
SELECT STRAIGHT_JOIN DISTINCT ... rest of query 
+0

結果は同じです。 – swdee

+0

[|| MySQLの論理OR用](https://dev.mysql.com/doc/refman/5.7/en/logical-operators.html)を参照してください。 Oracle SQLの文字列連結演算子ですが、MySQLで文字列連結に使用することはできません。それにもかかわらず、より標準的なので、論理ORに "OR"を使用するほうがよいでしょう。 –

+0

@swdee、索引と新しい特別キーワードの改訂版を参照してください。 – DRapp

関連する問題