2017-01-18 2 views
0

여러 개의 UNION을 포함하는 긴 MySQL 쿼리를 실행해야합니다. 일부 하위 쿼리는 많은 시간을 사용하여 실행 시간이 오래 걸립니다. 테이블에 인덱스를 만들었지 만 실행하는데 약 15 초 걸립니다. 실행 시간을 1 초로 줄여야합니다.UNION을 사용하여 MySQL 쿼리 최적화

SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, NULL AS Ink_Type, NULL AS Industry, 
NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, pi.prd_img_name 
FROM products p 
LEFT JOIN product_image_p pi ON p.prd_id = pi.prd_id 
WHERE p.is_deleted = 'no' 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, GROUP_CONCAT(decoration.dm_name SEPARATOR ', ') AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_dm pdm ON pdm.prd_id = p.prd_id 
JOIN decoration_method decoration ON decoration.dm_id = pdm.dm_id 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 

SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, GROUP_CONCAT(rush.rush_title SEPARATOR ', ') AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_rush_title prt ON prt.prd_id = p.prd_id 
JOIN rush_title rush ON rush.rush_id = prt.rush_id 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, NULL AS Pattern, 
NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 19 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 10 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 18 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, GROUP_CONCAT(ao.option_name SEPARATOR ', ') AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id IN (1, 13, 14) 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, GROUP_CONCAT(ao.option_name) AS Themes, 
NULL AS Material, NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 17 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, GROUP_CONCAT(ao.option_name) AS Material, 
NULL AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 12 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
GROUP_CONCAT(ao.option_name) AS Pattern, NULL AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 2 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, GROUP_CONCAT(ao.option_name) AS Country_Origin, NULL AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 11 
WHERE p.is_deleted = 'no' 
group by prd_id 

UNION 
SELECT p.prd_id, NULL AS manu_name, NULL AS brand_name, NULL AS Categories, NULL AS Item_Color, 
NULL AS Ink_Type, NULL AS Industry, NULL AS Size, NULL AS Decoration_Method, NULL AS Rush_Production, NULL AS Themes, NULL AS Material, 
NULL AS Pattern, NULL AS Country_Origin, GROUP_CONCAT(ao.option_name) AS Ships_From, NULL AS prd_img_name 
FROM products p 
JOIN product_attributes pa ON pa.prd_id = p.prd_id 
JOIN attributes_options ao ON ao.attr_opt_id = pa.attr_opt_id AND ao.attr_id = 8 
WHERE p.is_deleted = 'no' 
group by prd_id 
+0

당신이 느린 이들 중 어떤 확인 했습니까? – xzoert

+1

우리에게 귀하의 질의에 대한 설명을 보여주십시오. –

+0

ao.attr_id = 19 인 것은 매우 느리고 1 초 이상 걸립니다. – Mainuddin

답변

3

당신이 발생한 문제는 반복 된 제품 속성과 제품 옵션에 가입하고 전체 쿼리를 수행 한 기록이 당신이 찾고있는 각 구성 요소에 대해 반환 받고 있습니다 : 여기

는 쿼리입니다. 또한 옵션 테이블에서 나오는 모든 파트를 사용하여 각 제품에 대해 한 번 사전 쿼리 한 다음 각 구성 요소를 해당 PRD_ID에 대한 하나의 레코드로 리턴 할 수 있습니다. 시스템이로 돌아갈 필요가 없도록

Table     Index 
product_attributes (prd_id, attr_opt_id) 
attributes_options (attr_opt_id, attr_id, option_name) 
products    (is_deleted, prd_id) 
product_dm   (prd_id, dm_id) 
decoration_method  (dm_id, dm_name) 
product_rush_title (prd_id, rush_id) 
rush_title   (rush_id, rush_title) 

이 인덱스는 인덱스를 "포함하는"것이다 (아직없는 경우) 다음 인덱스 난 강력하게 제안 해당 구성 요소를 최적화 할 수 있도록

... 원시 데이터 페이지가 다른 테이블에서 온 장식 때문에 ... 그런 짓을 내부 사전 쿼리와 각 부분을 얻기 위해, 그리고

를 그것의 대부분에 대한 결과

을 준비하고 컨텐츠를 급히 , 그것도 prequeried 수 있습니다 요약 다만 제품 ID를 기반으로화된 다음

SELECT 
     p2.prd_id, 
     GROUP_CONCAT(case when ao.attr_id = 19 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Item_Color, 
     GROUP_CONCAT(case when ao.attr_id = 10 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Ink_Type, 
     GROUP_CONCAT(case when ao.attr_id = 18 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Industry, 
     GROUP_CONCAT(case when ao.attr_id = 17 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Themes, 
     GROUP_CONCAT(case when ao.attr_id = 12 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Material, 
     GROUP_CONCAT(case when ao.attr_id = 2 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Pattern, 
     GROUP_CONCAT(case when ao.attr_id = 11 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Country_Origin, 
     GROUP_CONCAT(case when ao.attr_id = 8 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Ships_From, 
     GROUP_CONCAT(case when ao.attr_id IN (1, 13, 14) 
         then ao.option_name else null end SEPARATOR ', ') 
      AS Size 
    from 
     products p2 
     JOIN product_attributes pa 
      ON p2.prd_id = pa.prd_id 
      JOIN attributes_options ao 
       ON pa.attr_opt_id = ao.attr_opt_id     
    WHERE 
     p2.is_deleted = 'no' 
    group by 
     p2.prd_id 

이 그럼 당신은 기본 쿼리에 하위 쿼리로 그 전체 쿼리를 롤하지만 단순화 별칭 참조 및 각 사전 그룹 CONCAT 필드의 결과를 사용할 수 있습니다 왼쪽에 합류

SELECT 
     p.prd_id, 
     NULL AS manu_name, 
     NULL AS brand_name, 
     NULL AS Categories, 
     preQuery.Item_Color, 
     preQuery.Ink_Type, 
     preQuery.Industry, 
     preQuery.Themes, 
     preQuery.Material, 
     preQuery.Pattern, 
     preQuery.Country_Origin, 
     preQuery.Ships_From, 
     preQuery.Size, 
     tmpDeco.Decoration_Method, 
     tmpRush.Rush_Production, 
     pi.prd_img_name 
    FROM 
     products p 
     LEFT JOIN product_image_p pi 
      ON p.prd_id = pi.prd_id 

     LEFT JOIN 
     (THE PRE-QUERY SAMPLE ABOVE) PreQuery 
      ON p.prd_id = PreQuery.prd_id 

     LEFT JOIN 
     (select 
       p2.prd_id, 
       GROUP_CONCAT(decoration.dm_name SEPARATOR ', ') AS Decoration_Method 
       FROM 
       products p2 
        JOIN product_dm pdm 
         ON p2.prd_id = pdm.prd_id 
         JOIN decoration_method decoration ; 
          ON decoration.dm_id = pdm.dm_id 
       WHERE 
       p2.is_deleted = 'no' 
       group by 
       p2.prd_id) as tmpDeco 
      ON p.prd_id = tmpDeco.prd_id 

     LEFT JOIN 
     (select 
       p2.prd_id, 
       GROUP_CONCAT(rush.rush_title SEPARATOR ', ') AS Rush_Production 
       FROM 
       products p2 
        JOIN product_rush_title prt 
         ON p2.prd_id = prt.prd_id 
         JOIN rush_title rush 
          ON prt.rush_id = rush.rush_id 
       WHERE 
       p2.is_deleted = 'no' 
       group by 
       p2.prd_id) as tmpRush 
      ON p.prd_id = tmpRush.prd_id 

    WHERE 
     p.is_deleted = 'no' 

한 번에 같은 테이블에서 발생하는 모든 공통 설명 요소를 가져온 다음 단일 별칭 참조를 기반으로 완료되면 가입하는 단순한 컨텍스트를 볼 수 있기를 바랍니다.

필자는 유형 -o 또는 2를 가질 수 있지만 필요에 따라 다르게 정확하다고 생각합니다. 또한 Manu_Name, Brand_Name, Category에 대한 항목이 없으므로 해당 구성 요소를 완료해야합니다. 최근에

FOLLOW-UP을 ...을 바탕으로, 내가 무엇을 할 것이라고하는 것은 각 필드를 개최 제품 테이블에 어떤 필드를 추가합니다. 그런 다음 제품에 추가 할 때 제품 속성 테이블에 대한 삽입/갱신/삭제를위한 트리거를 작성하십시오. 영향이있을 경우 해당 필드에서 간단한 sql-select group_concat()을 실행하고 주요 제품 테이블을 즉시 업데이트하십시오. 예, 이것은 한 범위로 비정규 화되지만 집중적 인 쿼리를 수행하고 성능을 저하시킬 필요를 완전히 단순화합니다.

내 대답을보십시오 in this other stack question. 비슷한 트리거를 만들고 있습니다. 이렇게하면 기본 테이블이 이미 사전 집계되어 준비가되어 있으며 단일 제품에 대해 하나의 필드 만 수행하기 때문에 트리거가 거의 즉시 작동해야합니다.

+0

이 위대한 노력에 감사드립니다. 그러나 제안 된 쿼리는 현저한 향상을 이루지 못했습니다. 내 쿼리는 5.7 초가 걸리며 4.7 초 걸립니다. 병목 현상을 일으키는 다른 것이 있다고 생각합니다. – Mainuddin

+0

@Mainuddin, 설명을 위해 수정 된 답변 및 트리거를 구현하는 다른 스택 게시물로 리디렉션. – DRapp

+0

필자는 마침내 검색 관련 데이터 만 포함하는 전용 테이블을 검색하기로 결정했습니다. 트리거는 제품 및 다른 테이블에서 변경 될 때마다 업데이트를 유지합니다. 따라서 예상대로 빠른 속도를 낼 수 있습니다. @DRapp에 다시 한번 감사드립니다. – Mainuddin

0

성능 문제 may의 일부는 "over-normalization"때문일 수 있습니다. GROUP_CONCAT(ao.option_name)이 속성 테이블에서 오는 것이 아니라 다른 JOIN을 통해 전달되는 방법에 유의하십시오. ao을 제거하고 option_namesproduct_attributes으로 옮길 것을 제안하십시오.

(이 외에도되는 쿼리의 병폐의 수를 포함 할 수 있습니다., 표면에 보인다 DRapp의 대답은, @)