我有一个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
附言
如果有帮助的话,我使用sql alchemy来生成这个代码,sql alchemy代码是
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()
4条答案
按热度按时间hl0ma9xz1#
确保您在以下内容上有索引:
**编辑:**为了完整起见,我想我应该提供一些上下文。
SQL优化器查看语句,解析语句,然后根据查询、引用的表和可用的索引确定执行计划。如果执行
SELECT * FROM tab1
,它将对tab1执行全表扫描,因为没有其他方法可以执行。如果您使用
SELECT * FROM person WHERE lastname LIKE 'V%'
,并且您有一百万条记录,那么查询每一行会很慢,但是如果lastname
被索引,那么效率会高得多。对于像你这样的查询,其中一个表将是驱动表,不管索引如何,都可以简单地作为全表扫描来完成。这没有什么错。一个表必须驱动查询。如果有
WHERE
子句(用于连接条件以外的东西),这可能会改变,但否则它 * 通常 * 是真的。从这个驱动表开始,MySQL将开始把连接附加到执行计划中,这些连接需要另一端的索引来使其高效地工作。
对于三个表,你可能有一个表没有索引,但这并不重要,因为它驱动查询,对于第四个表,可能有两个未索引的表,这是一个问题,因为对于一个MySQL中的每一行,都必须对另一个进行全表扫描。
因此,基本上您可以在 * 每个 * 外键和连接列上创建一个索引,以便MySQL可以使用可用的索引为您给予的查询制定最佳执行计划。
最后,大多数工具都会告诉你关于数据库模式的信息。PHPMyAdmin是托管数据库的一个流行工具。就我个人而言,我实际上喜欢一个桌面应用程序来处理这类事情。Navicat Lite是一个不错的免费工具。
nsc4cvqm2#
您正在执行4个表的自然联接。而且,在"WHERE"语句中,没有特殊条件。
数据库引擎将执行以下操作:
它将首先对每个表中的所有数据进行递归乘积。
考虑表A、B和C中的以下行:
基本上,如果对这3个表执行自然连接,引擎将在内存中具有:
总共有27行被放入内存中,但是我们只需要3行:
如果你的数据库引擎不能自己优化,那么3个表的自然连接是非常昂贵的,而对于4个表,即使行数有限,也是不可想象的。
现在,我们怎样才能得到更好的东西呢?
首先,通过查看代码,我们知道我们只需要5个值。另外,在数据库优化中,据说你应该尽可能早地进行SELECT。
下面是一些未经测试的代码,可能会对你有所帮助。你可能需要修改它,这取决于你使用的是什么DB引擎:
通过这样做,应该感觉我们只有3个表,而不是4个表。但是,这并不是您真正想要的。如果一行"equipment"没有在其他表中引用,则最后得到的行将少于5行。但是,这只是一个示例,向您说明我们可能并不真正需要所有表中的所有行。
现在,我想你想要的可能是:
您可能会遇到以下问题:如果您引擎不是很好(mySQL,对不起),那么它可能需要很长时间。
如果您确实想自己进行优化:
瞧!即使你的引擎优化器不存在,这个查询也不会花太长时间。你的引擎将一次处理一个产品,并在将它与新表连接之前将坏行去掉,而不是对所有产品都做一个大的乘积。
试试看。
qvtsj1bj3#
可能是您要联接的第4个表比其他表大得多,也可能是您要联接的列没有索引。
icnyk63a4#
大多数SQL数据库都有“EXPLAINPLAN”或“EXPLAIN”的变体,你可以用它来查看它是如何解析查询的。在需要索引的地方寻找全表扫描。