Union All Query занимает слишком много времени - PullRequest
1 голос
/ 29 января 2012

Я уверен, что этот вопрос задавался несколько раз, но каждый случай индивидуален.

У меня настроен MySQL на сильном компьютере с 2 ГБ ОЗУ, он не делает слишком много, поэтому компьютера достаточно.

Следующий запрос был построен как представление:

create view view_orders as

select distinct 

    tbl_orders_order.order_date AS sort_col,
    tbl_orders_order.order_id AS order_id,
_utf8'website' AS src,tbl_order_users.company AS company,
tbl_order_users.phone AS phone,
tbl_order_users.full_name AS full_name,
time_format(tbl_orders_order.order_date,_utf8'%H:%i') AS c_time,
date_format(tbl_orders_order.order_date,_utf8'%d/%m/%Y') AS c_date,
tbl_orders_order.comments AS comments,
tbl_orders_order.tmp_cname AS tmp_cname,
tbl_orders_order.tmp_pname AS tmp_pname,
count(tbl_order_docfiles.docfile_id) AS number_of_files,
(case tbl_orders_order.status when 1 then _utf8'completed' when 2 then _utf8'hc' when 0 then _utf8'not-completed' when 3 then _utf8'hc-canceled' end) AS status,

tbl_orders_order.employee_name AS employee_name,
tbl_orders_order.status_date AS status_date,
tbl_orders_order.cancel_reason AS cancel_reason

 from 
        tbl_orders_order left join tbl_order_users on tbl_orders_order.user_id = tbl_order_users.user_id 
    left join 
        tbl_order_docfiles on tbl_order_docfiles.order_id = tbl_orders_order.order_id

    group by 
        tbl_orders_order.order_id 



union all

select distinct tbl_h.h_date AS sort_col,
(case tbl_h.sub_oid when 0 then tbl_h.order_number else concat(tbl_h.order_number,_utf8'-',tbl_h.sub_oid) end) AS order_id,
(case tbl_h.type when 1 then _utf8'פקס' when 2 then _utf8'email' end) AS src,_utf8'' AS company,
_utf8'' AS phone,_utf8'' AS full_name,time_format(tbl_h.h_date,_utf8'%H:%i') AS c_time,
date_format(tbl_h.h_date,_utf8'%d/%m/%Y') AS c_date,_utf8'' AS comments,tbl_h.client_name AS tmp_cname,
tbl_h.project_name AS tmp_pname,
tbl_h.quantity AS number_of_files,
_utf8'completed' AS status,
tbl_h.computer_name AS employee_name,
_utf8'' AS status_date,
_utf8'' AS cancel_reason 

from tbl_h;

В запросе использовался UNION, затем я прочитал статью о UNION ALL и теперь использую это.

Для выполнения одного запроса требуется около 3 секунд (UNION занимал 4,5-5,5 секунды) Каждая часть в отдельности выполняется в считанные секунды.

Приложение выполняет сортировку и выбор в этом представлении, что делает его время обработки еще больше - около 6 секунд при кэшировании запроса, около 12 секунд или более, если данные изменились.

Я не вижу другого способа объединить эти два результата, так как оба отсортированных должны отображаться пользователю, и я предполагаю, что что-то, что я делаю, неправильно.

Конечно, обе таблицы используют первичные ключи.

UPDATE !!!!

Это не помогло, я получил utf8 / case / date_format из запроса объединения и удалил различия, теперь запрос занимает 4 секунды (даже дольше). запрос без case / date / utf8 (только объединение) был сокращен до 2,3 секунд (улучшение на 0,3 секунды).

создать представление view_orders как

select *,
    (CASE src
        WHEN 1 THEN
             _utf8'fax' 
        WHEN 2 THEN 
            _utf8'mail' 
        WHEN 3 THEN
            _utf8'website'
    END) AS src,

    time_format(order_date,'%H:%i') AS c_time,
    date_format(order_date,'%d/%m/%Y') AS c_date,

    (CASE status 
        WHEN 1 THEN 
            _utf8'completed' 
        WHEN 2 THEN
             _utf8'hc handling' 
        WHEN 0 THEN
             _utf8'not completed' 
        WHEN 3 THEN
             _utf8'canceled'
    END) AS status

FROM
(
select 

    o.order_date AS sort_col,
    o.order_id,
    3 AS src,

    u.company,
    u.phone,
    u.full_name,

    o.order_date,

    o.comments,
    o.tmp_cname,
    o.tmp_pname,
    count(doc.docfile_id) AS number_of_files,

    o.status,

    o.employee_name,
    o.status_date,
    o.cancel_reason

 from 
        tbl_orders_order o
    LEFT JOIN
        tbl_order_users u ON u.user_id = o.user_id
    LEFT JOIN
        tbl_order_docfiles doc ON doc.order_id = o.order_id

    GROUP BY
        o.order_id 

union all

select 

    h.h_date AS sort_col,
    (case h.sub_oid when 0 then h.order_number else concat(h.order_number,'-',h.sub_oid) end) AS order_id,
    h.type as src,

    '' AS company,
    '' AS phone,
    '' AS full_name,

    h.h_date,

    '' AS comments,
    h.client_name AS tmp_cname,
    h.project_name AS tmp_pname,
    h.quantity AS number_of_files,
    1 AS status,

    h.computer_name AS employee_name,
    '' AS status_date,
    '' AS cancel_reason 

from tbl_h h

)

Ответы [ 3 ]

4 голосов
/ 29 января 2012

Подумайте об использовании ключевых слов UNION и DISTINCT.Может ли ваш запрос привести к дублированию строк?Если да, оптимальный запрос для удаления дубликатов, вероятно, будет иметь следующий вид:

SELECT ... -- No "DISTINCT" here
UNION
SELECT ... -- No "DISTINCT" here

Вероятно, нет необходимости в DISTINCT в двух подзапросах.Если дубликаты все равно невозможны, попробуйте использовать эту форму.Это будет самое быстрое выполнение вашего запроса (без дальнейшей оптимизации подзапросов):

SELECT ... -- No "DISTINCT" here
UNION ALL
SELECT ... -- No "DISTINCT" here

Обоснование: UNION и DISTINCT применяют операцию "UNIQUE SORT" к вашим промежуточным наборам результатов.В зависимости от того, сколько данных возвращают ваши подзапросы, это может быть очень дорого.Это одна из причин, почему пропустить DISTINCT и заменить UNION на UNION ALL гораздо быстрее.

ОБНОВЛЕНИЕ Другая идея, если вам действительно нужно удалить дубликаты: сначала удаляйте дубликаты ввнутренний запрос и форматирование дат и кодов только после этого во внешнем запросе.Это ускорит операцию "UNIQUE SORT", поскольку сравнение 32/64-bit integers обходится дешевле, чем сравнение varchars:

SELECT a, b, date_format(c), case d when 1 then 'completed' else '...' end
FROM (
  SELECT a, b, c, d ... -- No date format here
  UNION
  SELECT a, b, c, d ... -- No date format here
)
0 голосов
/ 30 января 2012

Можете ли вы попробовать это:

SELECT 
    o.order_date AS sort_col,
    o.order_id AS order_id,
    _utf8'website' AS src,
    u.company AS company,
    u.phone AS phone,
    u.full_name AS full_name,
    time_format(o.order_date,_utf8'%H:%i') AS c_time,
    date_format(o.order_date,_utf8'%d/%m/%Y') AS c_date,
    o.comments AS comments,
    o.tmp_cname AS tmp_cname,
    o.tmp_pname AS tmp_pname,
    COALESCE(d.number_of_files, 0) AS number_of_files,
    ( CASE o.status WHEN 1 THEN _utf8'completed'
                    WHEN 2 THEN _utf8'hc' 
                    WHEN 0 THEN _utf8'not-completed' 
                    WHEN 3 THEN _utf8'hc-canceled' 
      END ) AS status, 
    o.employee_name AS employee_name,
    o.status_date AS status_date,
    o.cancel_reason AS cancel_reason    
 FROM 
       tbl_orders_order AS o
   LEFT JOIN 
       tbl_order_users AS u
     ON o.user_id = u.user_id 
   LEFT JOIN
       ( SELECT order_id
              , COUNT(*) AS number_of_files
         FROM tbl_order_docfiles
         GROUP BY order_id 
       ) AS d
     ON d.order_id = o.order_id

UNION ALL

SELECT 
    tbl_h.h_date AS sort_col,
  ...

FROM tbl_h
0 голосов
/ 29 января 2012

Это может быть связано с тем, что UNION запускает преобразование набора символов. Например, cancel_reason в одном запросе определяется как utf8, а в другом - не указан.

Проверьте, есть ли очень высокий всплеск процессора при выполнении этого запроса, это будет означать конверсию.

Лично я бы сначала сделал объединение необработанных данных, а затем применил операторы case и преобразования. Но я не уверен, что это повлияет на производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...