使用JOINS的MySQL非常慢

时间:2015-08-26 10:13:06

标签: mysql performance

我有这个问题:

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 ;

3 个答案:

答案 0 :(得分:1)

您的表上没有对此查询有用的索引,并且您正在重复连接一个表。

在auftrag表上添加 erledigt 列的索引。

在详情表上添加一个涵盖 beschreibung和 auftrags_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

编辑 - 我刚刚注意到auftrag表上的id是一个INT字段(正如我所料),但详细信息表上的auftrags_id列是一个VARCHAR(50)字段。这将极大地影响性能,因为它需要转换每次比较的值。

请注意,Gordons在上面评论索引上的字段顺序确实适用(多少取决于实际数据 - 例如beschreibung有多少其他值),但没有用不匹配的数据解决这个问题改变索引的类型几乎肯定无济于事。

答案 1 :(得分:0)

对于您的查询,您需要以下索引:

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

您还可以将查询重写为条件聚合,但正确的索引将是一个很大的帮助。

注意:复合索引中列的顺序很重要。

答案 2 :(得分:0)

这可能是InnoDB明显胜过MyISAM的情况。在details中,有PRIMARY KEY(auftrags_id, beschreibung)

同时,在auftragPRIMARY KEY(id)。而Gordon为auftragkunden建议的指数。