我有一个sql语句,我正在加入大约4个表,每个表有200K行。查询运行,但一直冻结。当我在3个表上进行连接时,它返回行(大约需要10秒)。有什么建议吗?建议加快?
谢谢!
代码
SELECT *
FROM equipment, tiremap, workreference, tirework
WHERE equipment.tiremap = tiremap.`TireID` AND
tiremap.`WorkMap` = workreference.`aMap` AND
workreference.`bMap` = tirework.workmap
LIMIT 5
P.S
如果它有帮助,我使用sql alchemy生成此代码,sqlalchemy代码为
query = session.query(equipment, tiremap, workreference, tirework)
query = query.filter(equipment.c.tiremap == tiremap.c.TireID)
query = query.filter(tiremap.c.WorkMap==workreference.c.aMap)
query = query.filter(workreference.c.bMap == tirework.c.workmap)
query = query.limit(5)
query.all()
答案 0 :(得分:5)
确保您拥有索引:
编辑:我想我应该为完整性提供一些背景信息。
SQL优化器查看语句,解析它,然后根据查询,引用的表和可用索引确定它的执行计划。如果你SELECT * FROM tab1
那么它会对tab1进行全表扫描,因为没有其他方法可以执行它。
如果您执行SELECT * FROM person WHERE lastname LIKE 'V%'
并且您有一百万条记录,则查询每一行的速度都会很慢,但如果lastname
被编入索引,则会更有效率。
使用像你这样的查询,其中一个表将是驱动表,无论索引如何都可以简单地作为全表扫描完成。这没什么不对。一个表必须驱动查询。如果有一个WHERE
子句(除了连接条件之外的其他内容),这可能会改变,但是否则通常为真。
从该驱动表开始,MySQL将开始将连接附加到执行计划中。这些连接将需要另一方的索引才能有效地工作。
因此,对于三个表,您可能有一个未编入索引的表,但它并不重要,因为它驱动查询。对于第四个表,可能有两个未编制索引的表,现在这是一个问题,因为对于一个MySQL中的每一行,都必须对另一个进行全表扫描。
所以基本上你在每个外键和连接列上创建一个索引,这样MySQL可以使用可用的东西来为你提供的查询制定最佳的执行计划。
最后,大多数工具会告诉您有关数据库架构的信息。 PHPMyAdmin是托管数据库的流行版本。我个人真的喜欢这种桌面应用程序。 Navicat Lite是一个不错的免费工具。
答案 1 :(得分:1)
您正在进行4个表的自然连接。此外,在您的“WHERE”语句中,没有特殊条件。
数据库引擎将执行以下操作:
它将首先对每个表中的所有数据执行递归产品。
考虑表A,B和C中的以下行:
A = rowA1
rowA2
rowA3;
B = rowB1
rowB2
rowB3;
C = rowC1
rowC2
rowC3;
基本上,如果你对这3个表进行自然连接,引擎将具有内存:
rowA1 - rowB1 - rowC1
rowA1 - rowB1 - rowC2
rowA1 - rowB1 - rowC3
rowA1 - rowB2 - rowC1
rowA1 - rowB2 - rowC2
rowA1 - rowB2 - rowC3
rowA1 - rowB3 - rowC1
rowA1 - rowB3 - rowC2
rowA1 - rowB3 - rowC3
...
...
...
rowA3 - rowB3 - rowC1
rowA3 - rowB3 - rowC2
rowA3 - rowB3 - rowC3
总共有27行存入内存。但是,我们只想要3行:
rowA1 - rowB1 - rowC1
rowA2 - rowB2 - rowC2
rowA3 - rowB3 - rowC3
如果您的数据库引擎本身不进行优化,则3表的自然连接非常昂贵。对于4个表,即使对于有限数量的行,也是不可想象的。
现在,我们怎样才能让事情变得更好?
首先,通过查看代码,我们知道我们只需要5个值。此外,在数据库优化中,据说您应该尽早选择SELECT。
以下是一些可以帮助您的未经测试的代码。您可能需要修改它,具体取决于您使用的数据库引擎:
SELECT *
FROM (SELECT * FROM equipment LIMIT 5) e, tiremap, workreference, tirework
WHERE e.tiremap = tiremap.TireID AND
tiremap.WorkMap = workreference.`aMap` AND
workreference.`bMap` = tirework.workmap
通过这样做,它应该感觉我们只有3个表,而不是4.但是,这不是你想要的。如果在其他表中没有引用一行“设备”,则最后将得到少于5行。但是,这个例子向您展示我们可能并不真正需要所有表中的所有行。
现在,我认为你想要的是:
SELECT * FROM equipment
INNER JOIN tiremap ON equipment.tiremap = tiremap.TireID
INNER JOIN workreference ON tiremap.WorkMap = workreference.aMap
INNER JOIN tirework ON workreference.bMap = tirework.workmap
LIMIT 5
你可能在这里遇到问题:如果你的引擎不太好(mySQL,对不起),可能需要很长时间。
如果你真的想自己做优化:
SELECT * FROM tirework,
(SELECT * FROM workreference,
(SELECT * FROM tiremap,
(SELECT * FROM equipment) e
WHERE e.tiremap = tiremap.TireID) t
WHERE t.WorkMap = workreference.aMap) w
WHERE w.bMap = tirework.workmap
LIMIT 5
瞧!即使您的引擎优化程序不存在,该查询也不会花费太长时间。你的引擎不是制造一切产品,而是一次只做一件产品,并在加入新工作台之前将坏行排除在外。
试试吧。
答案 2 :(得分:0)
你加入的第四张桌子可能比其他桌子大得多。也可能是您加入的列没有索引。
答案 3 :(得分:0)
大多数SQL数据库都有一些“EXPLAIN PLAN”或“EXPLAIN”变体,您可以使用它来查看它如何解析查询。寻找全表扫描作为您需要索引的地方。