2012-01-29 3 views
1

Этот вопрос задан несколько раз. Я уверен, но каждый случай отличается.Union Весь запрос занимает слишком много времени

У меня есть настройка 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 секунды (даже дольше). запрос без случая/даты/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 

)

+2

оба запроса должны быть DISTINCT ли? Учитывая возвращаемые поля, я бы предположил, что каждая запись уже уникальна. Удалите это, если это возможно. – Digbyswift

+0

Чтобы быть уверенным: 'tbl_order_users.user_id' и' tbl_orders_order.order_id' _are_ первичные ключи, не так ли? – Thomas

+0

Да, они ... – Avi

ответ

0

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

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

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

+0

Пожалуйста, просмотрите обновление выше. – Avi

4

Подумайте об использовании 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 намного быстрее.

UPDATE Другая идея, если вам нужно удалить дубликаты: сначала удалите дубликаты во внутреннем запросе, а затем форматируйте даты и коды только во внешнем запросе. Это ускорит "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

По крайней мере, левая часть OP 'UNION' определенно не нуждается в 'DISTINCT' просто потому, что она использует группировку по столбцу первичного ключа. –

+0

@AndriyM: Хорошая точка. –

+0

Пожалуйста, просмотрите обновление выше. – Avi

0

Вы можете попробовать это:

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

он застрял мой mysql, нет хорошего – Avi

+0

Вы запускаете это как есть? Или положить его в представление, а затем добавить 'ORDER BY'? –

+0

Было бы хорошо, если бы вы добавили в свой вопрос определения таблиц, индексы, которые у вас есть, и план запроса (вывод EXPLAIN). –