2016-11-25 2 views
0

Как я могу улучшить производительность этого запроса, а также получить всю необходимую информацию ..Как повысить производительность множественного присоединяемой таблицы в SQL запросе

SELECT 
    tr.id, tr.request_status, tr.note, tr.created_date, 
    c.name AS customer_name, c.mobile_phONe, 
    u.full_name AS created_by_name, tt.name AS ticket_type_name 
FROM 
    ticket_request tr 
LEFT JOIN 
    ticket_type tt ON tt.id = tr.ticket_type_id 
LEFT JOIN 
    users u ON u.id = tr.created_by 
LEFT JOIN 
    customer c ON c.id = tr.customer_id 
WHERE 
    tr.is_deleted != 1 
    AND tr.user_id IN (SELECT u.id FROM users u WHERE u.status = '1') 
GROUP BY 
    tr.id 
ORDER BY 
    tr.created_date DESC 
LIMIT 0,20 

В настоящее время этот запрос выполняется в течение 7-10 секунд.

  • ticket_request таблица имеет около 100к строк
  • customers таблица имеет около 300к строк
  • users стол и ticket_type не так много (около 1k строк)
+0

Добавить индексы для всех объединяемых столбцов. Вы уже это сделали? –

+1

Я удалил несовместимые теги базы данных. Добавьте тег для базы данных, которую вы действительно используете. –

+0

@TimBiegeleisen Да, я сделал это –

ответ

1

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

SELECT tr3.id, tr3.request_status, tr3.note, tr3.created_date, 
     c.name AS customer_name, c.mobile_phONe, 
     u2.full_name AS created_by_name, 
     tt.name AS ticket_type_name 
    FROM 
    (
     SELECT tr1.id 
      FROM ticket_request tr1 
      JOIN users u1 ON u1.id = tr1.created_by 
      WHERE u1.status = '1' 
       AND tr1.is_deleted != 1 
      ORDER BY tr1.created_date DESC 
      LIMIT 0,20 
    ) AS tr2 
    JOIN ticket_request AS tr3 ON tr3.id = tr2.id 
    JOIN user AS u2 ON u2.id = tr3.created_by 
    LEFT JOIN ticket_type tt ON tt.id = tr3.ticket_type_id 
    LEFT JOIN customer c ON c.id = tr3.customer_id 
    ORDER BY tr3.created_date 

JOINs, после того, как один в "производной" таблицы TR2, касаются только 20 строк; это большая часть ускорения.

Это может быть одинаково хорошо:

SELECT d.id, d.request_status, d.note, d.created_date, 
     c.name AS customer_name, c.mobile_phONe, d.created_by_name, 
     tt.name AS ticket_type_name 
    FROM 
    (
     SELECT tr.id AS tr_id, tr.request_status, tr.note, tr.created_date, 
       tr.ticket_type_id, tr.customer_id 
       u.full_name AS created_by_name 
      FROM ticket_request tr 
      JOIN users u ON u.id = tr.created_by 
      WHERE u.status = '1' 
       AND tr.is_deleted != 1 
      ORDER BY tr.created_date DESC 
      LIMIT 0,20 
    ) AS d 
    LEFT JOIN ticket_type tt ON tt.id = d.ticket_type_id 
    LEFT JOIN customer c ON c.id = d.customer_id 
    ORDER BY d.created_date 
+0

Я еще этого не пробовал, но думаю, если вы положите LIMIT сверху, то некоторые удовлетворительные результаты в верхнем запросе LIMIT не смогут удовлетворить более низкие условия, тогда результат всего запроса может быть меньше 20 строк правильно. –

+0

@VinhDatHa - Пожалуйста, уточните, что вы подразумеваете под словом «сверху» и «сверху». Я думаю о «SELECTs» и «external» и «inner» или «output». («Производный») является техническим термином для такого «подзапроса». –

+0

ОК, я думаю, я получил его сейчас, спасибо –

0

Я предполагаю, что вы используете MySQL. Если нет, этот ответ может быть слегка изменен, чтобы соответствовать другой базе данных, но концепция должна оставаться неизменной. Вы можете добавить индексов для всех ID столбцов, которые участвуют в правой части левого соединяются с ticket_request колонки:

ALTER TABLE ticket_type ADD INDEX (id); 
ALTER TABLE users ADD INDEX (id); 
ALTER TABLE customer ADD INDEX (id);  -- important 

Чтобы объяснить, почему индекс помог бы, рассмотрите первый LEFT JOIN между ticket_request столом и стол ticket_type. Без индекса для каждой записи в ticket_request базе данных придется потенциально сканировать всю таблицу ticket_type, чтобы найти записи, которые соответствуют условию объединения. Это дорого стоит с точки зрения производительности. Но с индексом база данных может завершить эту операцию намного быстрее, так как она «знает», где искать точно (или почти точно) для соответствующих записей.

Хотя вы упомянули, что только таблица customer очень велика, вы можете добавить индексы к другим таблицам. В будущем они могут стать больше. Скорее всего, объединение, связанное с customer, является узким местом в вашем запросе.

+0

Да, я использую MySQL. Я предполагаю, что первичный индексируется по умолчанию, верно? И я также проиндексировал весь необходимый внешний ключ. –

+0

@VinhDatHa Я добавил для вас тег MySQL. Это имеет смысл, если вы это сделаете в первую очередь. –

0

Самая большая возможность для оптимизации здесь есть с LIMIT 0,20

  1. GROUP BY tr.id не имеют никакого смысла и должны быть удалены.

  2. create index ticket_request_ix_is_deleted_created_date on ticket_request (is_deleted,created_date) и изменение tr.is_deleted != 1 до tr.is_deleted = 0.

    Или

    create index ticket_request_ix_created_date on ticket_request (created_date)

0
SELECT 
    tr.id, tr.request_status, tr.note, tr.created_date, 
    c.name AS customer_name, c.mobile_phONe, 
    u.full_name AS created_by_name, tt.name AS ticket_type_name 
FROM 
    ticket_request tr 
LEFT JOIN 
    ticket_type tt ON tt.id = tr.ticket_type_id and tr.is_deleted != 1 
LEFT JOIN 
    users u ON u.id = tr.created_by 
JOIN 
    users u1 ON u1.id = tr.user_id and u1.status = '1' 
LEFT JOIN 
    customer c ON c.id = tr.customer_id 
GROUP BY 
    tr.id 
ORDER BY 
    tr.created_date DESC 
LIMIT 0,20 

попробовать это будет работать с улучшением производительности и настройки в соответствии с вашими требованиями

+0

Это даст неправильные результаты. –

-1

Другие, чем индексации, на уровне приложений можно использовать Memcached (в случае, если вы используете php), как вещи. Это также даст вам отличную производительность.

Смежные вопросы