我有一些表格:
object
person
project
[...] (some more tables)
type
对象表具有所有其他表的外键。
现在我进行如下查询:
SELECT * FROM object
LEFT JOIN person ON (object.person_id = person.id)
LEFT JOIN project ON (object.project_id = project.id)
LEFT JOIN [...] (all other joins)
LEFT JOIN type ON (object.type_id = type.id)
WHERE object.customer_id = XXX
ORDER BY object.type_id ASC
LIMIT 25
即使对于大型结果集,这也非常有效且快速。例如,我有90000个对象,查询大约需要3秒。结果非常大,因为表中有很多列,并且所有列都被提取。有关信息:我正在使用Symfony与Propel,InnoDB和“doSelectJoinAll”函数。
但是,如果做一个查询(按type.name排序):
SELECT * FROM object
LEFT JOIN person ON (object.person_id = person.id)
LEFT JOIN project ON (object.project_id = project.id)
LEFT JOIN [...] (all other joins)
LEFT JOIN type ON (object.type_id = type.id)
WHERE object.customer_id = XXX
ORDER BY type.name ASC
LIMIT 25
查询大约需要200秒!
说明:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
1 | SIMPLE | object | ref | object_FI_2 | object_FI_2 | 4 | const | 164966 | Using where; Using temporary; Using filesort
1 | SIMPLE | person | eq_ref | PRIMARY | PRIMARY | 4 | db.object.person_id | 1
1 | SIMPLE | ... | eq_ref | PRIMARY | PRIMARY | 4 | db.object...._id | 1
1 | SIMPLE | type | eq_ref | PRIMARY | PRIMARY | 4 | db.object.type_id | 1
我在进程列表中看到,MySQL正在为连接表上的这种排序创建一个临时表。
向type.name添加索引并未提高性能。只有大约800种类型的行。
我发现很多连接和大结果都是问题所在,因为如果我只使用一个连接进行查询:
SELECT * FROM object
LEFT JOIN type ON (object.type_id = type.id)
WHERE object.customer_id = XXX
ORDER BY type.name ASC
LIMIT 25
它的工作速度与预期一样快。
有没有办法在包含许多连接表的大型结果集上改进此类排序查询?或者,对连接表列进行排序只是一个坏习惯,不管怎么说都不应该这样做?
谢谢
答案 0 :(得分:0)
LEFT
阻碍了重新排列表格的顺序。没有任何LEFT
的速度有多快?你得到同样的答案吗?
LEFT
可能是一个红色的鲱鱼......以下是优化程序可能会做的事情:
WHERE
过滤和任何LEFTs
。由于WHERE object.customer_id = XXX
,object
可能是最好的表格。object
获取满足WHERE
。JOINs
)。ORDER BY
**排序,见下文**让我们深入研究这两个:
WHERE object.customer_id = XXX ORDER BY object.id
WHERE object.customer_id = XXX ORDER BY virtually-anything-else
你有INDEX(customer_id)
,对吗?表是InnoDB,对吗?好吧,每个二级索引都隐含地包含PRIMARY KEY
,就像你说INDEX(customer_id, id)
一样。第一个WHERE + ORDER BY
的最佳索引正是如此。它将找到XXX并扫描25行,然后停止。你可能会说步骤2,4,5混合在一起。
第二个WHERE
只是通过第4步收集所有内容。这可能是数千行。因此它可能会慢很多。