2012-11-19 2 views
0

다음과 같은 쿼리가 매우 느립니다. (결과가 4-5 초 밖에 걸리지 않습니다. 누구든지이 쿼리를 사용하여 속도를 다르게 할 수 있는지 궁금합니다.)MySql Query Super Slow

덕분에 여기

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

'파일 사용 중'이 최악입니다. – Kermit

+0

네,'Using filesort'를 본다면 기본적으로 물속에서 죽어 있습니다. 당신은 당신의'ORDER' 컬럼에 인덱스를 통합하는 방법을 살펴야 할 것입니다. – tadman

+0

이미 설정된 색인은 무엇입니까? –

답변

0

는 MySQL의 느린 작품에서는 사용하지 마십시오는 사용

을 존재
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

보리스 (Boris) - 나는 현장에서 어떻게 사용하는지 잘 모르겠습니다. 설명해 주시겠습니까? – swhitlow

+0

내 대답을 확장했습니다 –

+1

"IN IN slow in 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 

이 매우 가능성이 왼쪽의 카디널리티를 줄여 가지 속도를 수있는 작업을 가입 조인의 오른쪽에서 레코드의 무리를 제거하여.

+0

나는 또한 멀티 date_entered, deleted 및 sales_stage의 열 인덱스 (이 순서대로)가 도움이 될 것입니다. MySQL이 정렬 된 인덱스를 내림차순으로 구현하기를 바랍니다. – bobwienholt

+0

- 피드백에 감사드립니다. 방금 위에서 제공 한 쿼리를 시도했습니다. 그러나 오류 메시지가 나타났습니다.받은 오류는 다음과 같습니다.

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

내 검색어를 디버깅 할 기회가 없었습니다. 죄송합니다. (귀하의 데이터가 없습니다.) –