2015-08-26 6 views
0

У меня есть этот запрос:MySQL с JOINS очень медленно

select 
b.user as user1, b.timestamp as ts1, 
c.user as user2, c.timestamp as ts2, 
d.user as user3, d.timestamp as ts3, 
e.user as user4, e.timestamp as ts4, 
f.user as user5, f.timestamp as ts5, 
g.user as user6, g.timestamp as ts6, 
h.user as user7, h.timestamp as ts7, 
i.user as user8, i.timestamp as ts8, 
j.user as user9, j.timestamp as ts9, 
k.user as user10, k.timestamp as ts10, 

a.beschreibung, a.auftragsnummer, a.faellig, a.subkunde, 
(SELECT firma from kunden where id=a.kunde limit 0,1) as kunde, 
(SELECT kommision from kommision where id=a.kommision limit 0,1) as kommision 
from auftrag a 
    left join details b on (b.beschreibung='Step1' AND b.auftrags_id=a.id) 
    left join details c on (c.beschreibung='Step2' AND c.auftrags_id=a.id) 
    left join details d on (d.beschreibung='Step3' AND d.auftrags_id=a.id) 
    left join details e on (e.beschreibung='Step4' AND e.auftrags_id=a.id) 
    left join details f on (f.beschreibung='Step5' AND f.auftrags_id=a.id) 
    left join details g on (g.beschreibung='Step6' AND g.auftrags_id=a.id) 
    left join details h on (h.beschreibung='Step7' AND h.auftrags_id=a.id) 
    left join details i on (i.beschreibung='Step8' AND i.auftrags_id=a.id) 
    left join details j on (j.beschreibung='Step9' AND j.auftrags_id=a.id) 
    left join details k on (k.beschreibung='Step10' AND k.auftrags_id=a.id) 



where a.erledigt='1' 

Он работает очень, очень медленно и занимает около 1 минуты, чтобы получить набор результатов. Таблица «auftrag» имеет 820 строк и таблицу «детали» около 7000 строк. Что я делаю неправильно?

Благодаря Патрик

CREATE TABLE auftrag 
( 
    id INT(10) NOT NULL AUTO_INCREMENT, 
    beschreibung VARCHAR(255) NULL DEFAULT '0', 
    auftragsnummer VARCHAR(50) NULL DEFAULT '0', 
    faellig VARCHAR(50) NULL DEFAULT NULL, 
    kunde INT(11) NULL DEFAULT NULL, 
    subkunde VARCHAR(50) NULL DEFAULT NULL, 
    kommision VARCHAR(50) NULL DEFAULT NULL, 
    notiz TEXT NULL, 
    werbeanbringung TEXT NULL, 
    erledigt INT(1) NULL DEFAULT NULL, 
    INDEX Schlüssel 1 (id), 
    INDEX Schlüssel 2 (id, auftragsnummer, kunde, subkunde, beschreibung) 
) COLLATE='latin1_swedish_ci' ENGINE=MyISAM AUTO_INCREMENT=850 ; 

CREATE TABLE details 
( 
    id INT(11) NOT NULL AUTO_INCREMENT, 
    auftrags_id VARCHAR(50) NULL DEFAULT '0', 
    beschreibung VARCHAR(50) NULL DEFAULT '0', 
    user VARCHAR(50) NULL DEFAULT '0', 
    timestamp VARCHAR(50) NULL DEFAULT '0', 
    notiz VARCHAR(255) NULL DEFAULT NULL, 
    INDEX Schlüssel 2 (user, timestamp, beschreibung, auftrags_id), 
    INDEX Schlüssel 1 (id, user, timestamp, beschreibung) 
) COLLATE='latin1_swedish_ci' ENGINE=MyISAM AUTO_INCREMENT=7260 ; 
+0

Вы можете сделать с индексом подробные сведения о покрытии beschreibung и auftrags_id – Kickstart

+0

. См. Похожие вопросы о производительности MySQL и запросов, вы увидите, как предоставить вывод 'EXPLAIN'. Кроме того, вставлять запросы в комментарии не помогает никому, особенно вам. Удалите их, чтобы мы могли прочитать это без проблем. Kickstart был достаточно любезен, чтобы изменить ваш исходный вопрос с помощью запросов. –

+0

Привет, Теперь ему нужно 25 секунд, но он все еще медленный. Есть ли что-нибудь еще, я могу сделать? – user2849380

ответ

1

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

В таблице auftrag добавьте индекс на столбец erledigt.

На столе детали добавить индекс, который охватывает как beschreibungandauftrags_id колонны

Он также может быть возможным, чтобы избежать большинства стыков, если вы готовы, чтобы обработать полученные данные впоследствии (то есть, разделите возвращаемое поле в массив). Но немного неаккуратно: -

SELECT 
    GROUP_CONCAT(CONCAT_WS('##', b.beschreibung, b.user, b.timestamp)), 
    a.beschreibung, a.auftragsnummer, a.faellig, a.subkunde, 
    (SELECT firma from kunden where id=a.kunde limit 0,1) as kunde, 
    (SELECT kommision from kommision where id=a.kommision limit 0,1) as kommision 
FROM auftrag a 
LEFT OUTER JOIN details b on b.auftrags_id=a.id AND b.beschreibung IN ('Step1', 'Step2', 'Step3', 'Step4', 'Step5', 'Step6', 'Step7', 'Step8', 'Step9', 'Step10') 
WHERE a.erledigt='1' 
GROUP BY a.id 

EDIT - я только заметил, что идентификатор на столе Auftrag является полем INT (как я бы ожидать), но auftrags_id столбец таблицы деталей является VARCHAR (50) поле. Это резко повлияет на производительность, поскольку для преобразования значений для каждого отдельного сравнения необходимо преобразовать значения.

Обратите внимание, что комментарий Гордона над порядком полей в индексе действительно применяется (сколько будет зависеть от фактических данных - например, сколько других значений beschreibung есть), но без исправления этой проблемы с несогласованными типы данных, изменяющие индекс, почти наверняка не помогут.

0

Для вашего запроса, вы хотите следующие показатели:

auftrag(erledigt, id) 
details(auftrags_id, beschreibung) 
kunden(kunde, firma) 

Вы также можете переписать запрос в виде условной агрегации, но правильные индексы будут большим подспорьем.

Примечание: порядок столбцов в составных индексах важен.

0

Это, вероятно, случай, когда InnoDB станет явным победителем над MyISAM. В details, есть PRIMARY KEY(auftrags_id, beschreibung).

Между тем, в auftrag, PRIMARY KEY(id). И индексы Гордона предлагают для auftrag и kunden.

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