0

私は非常に遅い次のクエリを持っています (結果だけで 4 ~ 5 秒かかります)。このクエリを高速化するために、このクエリで別の方法で実行できることを誰かが見ることができるかどうか疑問に思っていましたか?

ありがとう!

SELECT
accounts.id AS account_id,
accounts. NAME AS account_name,
accounts.assigned_user_id account_id_owner,
users.user_name AS assigned_user_name,
opportunities_cstm.firstname_c, opportunities_cstm.lastname_c,
opportunities.`name`, TRIM(
    Concat(
        Ifnull(
            opportunities_cstm.firstname_c,
            ''
        ),
        ' ',
        Ifnull(
            opportunities_cstm.lastname_c,
            ''
        )
    )
) AS 'cfull' FROM
opportunities 
LEFT JOIN users ON opportunities.assigned_user_id = users.id 
LEFT JOIN accounts_opportunities ON opportunities.id = accounts_opportunities.opportunity_id 
LEFT JOIN accounts ON accounts_opportunities.account_id = accounts.id
LEFT JOIN opportunities_cstm ON opportunities.id = opportunities_cstm.id_c
WHERE
(
    (
        opportunities.sales_stage IN (
            'Prospecting',
            'Appointment Set',
            'MeetAndGreet',
            'Qualification',
            'Needs Analysis',
            'Locating Vehicle',
            'Demo',
            'Trade Evaluation',
            'Negotiation',
            'Manager T/O',
            'Write Up',
            'Credit App Submitted',
            'Pending Finance',
            'Loan Approval',
            'Deposit',
            'Delayed Decision',
            'Sold-Vehicle Ordered',
            'Sold-Pending Finance',
            'Sold/Pending Delivery',
            'Price Quoted',
            'Service Pending'
        )
    )
)
AND (
accounts_opportunities.deleted IS NULL
OR accounts_opportunities.deleted = 0
)
AND (
accounts.deleted IS NULL
OR accounts.deleted = 0
)
AND opportunities.deleted = 0
ORDER BY
opportunities.date_entered DESC,
opportunities.id DESC
LIMIT 0,21

同じクエリからの説明は次のとおりです。

╔═════════════╦════════════════════════╦════════╦═ ═════════════════════════╦═════════════════════╦══ ═══════╦══════════════════════════════════════════ ══╦═══════╦═════════════════════════════╗
║ select_type ║ table ║ type ║ possible_keys ║ key ║ key_len ║ ref ║ rows ║ extra ║
╠═════════════╬════════════════════════╬════════╬═ ═════════════════════════╬═════════════════════╬══ ═══════╬══════════════════════════════════════════お問い合わせ
║ シンプル ║ 機会 ║ 範囲 ║ sales_stage, idx_deleted ║ sales_stage ║ 78 ║ null ║ 25161 ║ where を使用する; ファイルソートの使用 ║
║ シンプル ║ ユーザー ║ eq_ref ║ PRIMARY、idx_id_deleted ║ PRIMARY ║ 108 ║ version4.opportunities.assigned_user_id ║ 1 ║ ║
║ simple ║ accounts_opportunities ║ ref ║ idx_oppid_del_accid ║ idx_oppid_del_accid ║ 111 ║ version4.opportunities.id ║ 1 ║ where; を使用する。インデックス║の使用
║ シンプル ║ アカウント ║ eq_ref ║ PRIMARY,idx_accnt_id_del ║ PRIMARY ║ 108 ║ version4.accounts_opportunities.account_id ║ 1 ║ where の使用 ║
║ シンプル ║ Opportunities_cstm ║ eq_ref ║ PRIMARY ║ PRIMARY ║ 108 ║ version4.opportunities.id ║ 1 ║ ║
╚═════════════╩════════════════════════╩════════╩═ ═════════════════════════╩═════════════════════╩══ ═══════╩══════════════════════════════════════════ ══╩═══════╩═════════════════════════════╝
4

3 に答える 3

1

2つの問題があります。

まず、2つの異なるWHERE (... IS NULL OR ... = 0)基準を使用しています。それらは言葉では言い表せないほど遅いです。これは、インデックスがNULL値の検索に役立たないためです。これらの列でNULLの可能性を取り除くことができる場合はdeleted、おそらくそれらを宣言することで、NOT NULL DEFAULT 0これらの基準をに変更できますWHERE ... = 0。これは多くのことをスピードアップするはずです。これは、インデックスがNULL値の検索に役立たないためです。

次に、大きな結合結果セットを作成し、それを並べ替えて最新のアイテムを検索します。

参加する前に、「機会」テーブルからアイテムを事前に選択してみてください。このようなことをします:

SELECT   whatever....
FROM (
         SELECT * 
           FROM opportunities
          WHERE opportunities.deleted = 0
            AND opportunities.sales_stage IN (
            'Prospecting',
            'Appointment Set',  etc etc  ...
            'Service Pending' )
       ORDER BY opportunities.date_entered DESC,
                opportunities.id DESC
          LIMIT 0,21
      ) opportunities 
LEFT JOIN users ON opportunities.assigned_user_id = users.id
...
ORDER BY
opportunities.date_entered DESC,
opportunities.id DESC
LIMIT 0,21

これは、結合の右側から大量のレコードを削除することにより、LEFT JOIN操作のカーディナリティを減らすことにより、処理を高速化できる可能性があります。

于 2012-11-19T23:01:01.163 に答える
0

INは使用しないでください。INはmysqlで遅く動作します。Existsを使用してください

DROP TABLE IF EXISTS tempTable;
CREATE TEMPORARY TABLE tempTable ( sales_stage VARCHAR(50) NOT NULL );
insert into tempTable () values ('Prospecting'),('Appointment Set'),('MeetAndGreet'),...,('Service Pending');

SELECT
...
WHERE EXISTS(select sales_stage from tempTable where opportunities.sales_stage = sales_stage);
于 2012-11-19T17:08:28.190 に答える
0

それが改善されるかどうかはわかりませんが、私が試みるのはこれです:

SELECT your_fields
FROM
  (SELECT * --or just the fields you need
   FROM
     opportunities
   WHERE
     opportunities.deleted = 0 AND
     opportunities.sales_stage IN (stage1, stage2, ...)
  ) opportunities1
  LEFT JOIN users ON opportunities1.assigned_user_id = users.id 
  LEFT JOIN accounts_opportunities ON opportunities1.id = ...etc...
WHERE
  (accounts_opportunities.deleted IS NULL
   OR accounts_opportunities.deleted = 0)
  AND (accounts.deleted IS NULL OR accounts.deleted = 0)
ORDER BY ...etc...

改善が見られるかどうか教えてください(ただし、遅くなる可能性もあります)。もう1つのアイデアは、フィルタリングする必要のあるすべてのステージを含むテーブルを使用することです。

CREATE TABLE filter_stage (
  stage varchar(255));

(255またはsales_stageの実際の長さに一致させてください。この列にもインデックスを付けるとよいでしょう)ここで、フィルタリングするすべての文字列を入力します。

INSERT INTO filter_stage VALUES ('Prospecting'), ('Appointment Set'), ('...'), ...

次に、最初のクエリからIN句を削除すると、FROMは次のようになります。

FROM
  opportunities INNER JOIN filter_stage
  ON opportunities.sales_stage = filter_stage.stage
  LEFT JOIN ...

それがうまくいくかどうか私に知らせてください!

于 2012-11-19T17:40:01.703 に答える