2012-11-19 130 views
0

我有以下查詢,這是超級慢(需要4-5秒的結果。我想知道是否有人可以看到任何事情,我可以做不同的查詢,以加快它?MySql查詢超慢

感謝

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   ║ 
╠═════════════╬════════════════════════╬════════╬══════════════════════════╬═════════════════════╬═════════╬════════════════════════════════════════════╬═══════╬═════════════════════════════╣ 
║ simple  ║ opportunities   ║ range ║ sales_stage, idx_deleted ║ sales_stage   ║  78 ║ null          ║ 25161 ║ Using where; Using filesort ║ 
║ simple  ║ users     ║ 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 ║ Using where; Using index ║ 
║ simple  ║ accounts    ║ eq_ref ║ PRIMARY,idx_accnt_id_del ║ PRIMARY    ║  108 ║ version4.accounts_opportunities.account_id ║  1 ║ Using where     ║ 
║ simple  ║ opportunities_cstm  ║ eq_ref ║ PRIMARY     ║ PRIMARY    ║  108 ║ version4.opportunities.id     ║  1 ║        ║ 
╚═════════════╩════════════════════════╩════════╩══════════════════════════╩═════════════════════╩═════════╩════════════════════════════════════════════╩═══════╩═════════════════════════════╝ 
+0

'使用filesort'是最糟糕的。 – Kermit

+0

是的,如果你看到'使用filesort',你基本上死在水中,特別是有大量受影響的行。你將不得不考慮在你的ORDER列中加入索引的方法。 – tadman

+0

你已經建立了哪些指標? –

回答

0

不要在使用的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); 
+0

鮑里斯 - 我不知道我將如何使用現場存在。你能解釋一下嗎? – swhitlow

+0

我擴大了我的答案 –

+1

你能解釋一下「在mysql中工作緩慢」嗎?我同意IN是否是一個子查詢...但我不同意這種情況,因爲他使用的是字面值列表。 – bobwienholt

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... 

讓我知道,如果它使任何改善(但也可能會比較慢)。另一個想法是使用一個表,你需要過濾的各個階段:

CREATE TABLE filter_stage (
    stage varchar(255)); 

(255或嘗試匹配sales_stage的實際長度,如果你索引此列還它的更好),您輸入的所有字符串過濾:

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

那麼你在第一次查詢中刪除你的IN子句,和你從此就變成了:

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

讓我知道,如果它的工作原理!

+0

fthiella - 我試過你的例子,但它使它更長。這次約6-7秒。 – swhitlow

+0

@swhitlow有時會起作用,但可能會發生,這會讓它變得更慢......您是否還嘗試使用filter_stage表?但沒有實際的數據,我不能建議你很多...我建議你做的是嘗試使用不同的子查詢組合,或嘗試用圓括號將連接的表分組... – fthiella

1

我看到兩個問題。

首先,您使用兩個不同的WHERE (... IS NULL OR ... = 0)條件。那些無法形容的緩慢。這是因爲索引對查找NULL值沒有用處。如果可以在deleted列中刪除NULL的可能性,可以聲明它們爲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 

這很可能會減少你的左邊的基數加快速度JOIN操作:做這樣的事情。

+0

我還會補充說多date_entered,deleted和sales_stage的列索引(按該順序)也可能有幫助。我真的希望MySQL會實現降序排序索引。 – bobwienholt

+0

Ollie - 感謝您的反饋。我剛剛嘗試了上面提供的查詢。但是,我收到了錯誤消息。以下是我收到的錯誤:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LEFT JOIN users ON opportunities.assigned_user_id = users.id LEFT JOIN accounts' at line 37
swhitlow

+0

我沒有機會調試我的查詢,很抱歉地說。 (我沒有你的數據。) –