2016-10-02 1 views
0

이상한 MySQL 성능 동작에 정말 놀랐습니다. 내 다음 쿼리를 실행하기 위해 약 3 시간 걸리는 :MySQL의 잘못된 OR 및 ISNULL 성능

UPDATE ips_invoice AS f SET ips_locality_id = (
     SELECT ips_locality_id 
     FROM ips_user_unit_locality AS uul 
     JOIN ips_user AS u ON u.id = uul.ips_user_id 
     WHERE 
      (u.id = f.ips_user_id OR u.ips_user_id_holder = f.ips_user_id) AND 
      uul.date <= f.date 

     ORDER BY `date` DESC 
     LIMIT 1 
) 
WHERE f.ips_locality_id IS NULL; 

내가 또한 다음을 시도했지만 얻을 동일한 성능 결과 :

UPDATE ips_invoice AS f SET ips_locality_id = (
     SELECT ips_locality_id 
     FROM ips_user_unit_locality AS uul 
     JOIN ips_user AS u ON u.id = uul.ips_user_id 
     WHERE 
      IFNULL(u.ips_user_id_holder, u.id) = f.ips_user_id 
      AND 
      uul.date <= f.date 

     ORDER BY `date` DESC 
     LIMIT 1 
) 
WHERE f.ips_locality_id IS NULL; 

논리는 경우 : "ips_user_id_holder"열이없는 경우 null, 나는 그것을 사용해야한다, 그렇지 않으면 "id"컬럼을 사용해야한다. 나는 두 개의 쿼리로 쿼리를 분할하는 경우

, 각각의 실행 15 초 정도 걸릴 :

 UPDATE ips_invoice AS f SET ips_locality_id = (
       SELECT ips_locality_id 
       FROM ips_user_unit_locality AS uul 
       JOIN ips_user AS u ON u.id = uul.ips_user_id 
       WHERE 
        u.ips_user_id_holder = f.ips_user_id 
        AND 
        uul.date <= f.date 

       ORDER BY `date` DESC 
       LIMIT 1 
     ) 
     WHERE f.ips_locality_id IS NULL; 

UPDATE ips_invoice AS f SET ips_locality_id = (
       SELECT ips_locality_id 
       FROM ips_user_unit_locality AS uul 
       JOIN ips_user AS u ON u.id = uul.ips_user_id 
       WHERE 
        u.id = f.ips_user_id 
        AND 
        uul.date <= f.date 

       ORDER BY `date` DESC 
       LIMIT 1 
     ) 
     WHERE f.ips_locality_id IS NULL; 

그렇지 내가 에 "OR"또는 "널 검사"MySQL의 문제에있어 처음으로 상대적으로 간단한 쿼리 (Why this mysql query (with is null check) is so slower than this other one?).

ips_invoice 테이블에는 약 400.000 개의 레코드가 있고, ips_user_unit_locality에는 약 100.000 개의 레코드가 있고 ips_user에는 약 35.000 개의 레코드가 있습니다.

저는 Ubuntu Amazon EC2 인스턴스에서 MySQL 5.5.49를 실행 중입니다.

그래서 첫 번째 및 두 번째 쿼리의 문제점은 무엇입니까? 중요한 성능 차이의 원인은 무엇입니까?

답변

1

첫 번째 및 두 번째 쿼리에는 "잘못된"것이 없습니다. 그러나 join 조건 (또는 이와 동등한 상관 관계의 하위 쿼리 조건)에서 or을 사용하면 일반적으로 엔진에서 인덱스를 사용할 수 없습니다.

이렇게하면 모든 것이 정말 느려집니다.

적어도 하나의 방법으로 문제를 해결하는 것이 이해되는 것 같습니다. 그래서 나는 다른 것을 제안하지 않을 것입니다.

편집 :

내가 쿼리 당신이 텍스트로 지정 정확히 무엇을하지 않습니다 것입니다. 두 사용자 ID 중 하나의 최신 날짜를 가져옵니다. ID의 우선 순위를 지정하려는 것 같습니다.

UPDATE ips_invoice f 
    SET ips_locality_id = 
     COALESCE((SELECT ips_locality_id 
        FROM ips_user_unit_locality uul JOIN 
         ips_user u 
         ON u.id = uul.ips_user_id 
        WHERE u.ips_user_id_holder, f.ips_user_id AND 
         uul.date <= f.date 
        ORDER BY uul.date DESC 
        LIMIT 1 
       ), 
        (SELECT ips_locality_id 
        FROM ips_user_unit_locality uul 
        WHERE uul.ips_user_id = f.ips_user_id AND 
         uul.date <= f.date 
        ORDER BY uul.date DESC 
        LIMIT 1 
       ) 
       ) 
WHERE f.ips_locality_id IS NULL; 
+0

와우, 재미있는 대안. 정말 고마워! –

0
  1. 를 사용하여 다중 테이블 UPDATE 대신 대신 OR

  2. = (SELECT ...)의, 두 개의 분리 된 UPDATEs 쓰기 : 그렇다면, 이것은 더 당신이 원하는 쿼리입니다.