mysql 200K数据库查询结果耗时太长,加速提示?

krugob8w  于 2022-12-26  发布在  Mysql
关注(0)|答案(4)|浏览(183)

我有一个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()
hl0ma9xz

hl0ma9xz1#

确保您在以下内容上有索引:

  • 设备(轮胎图)
  • 轮胎图(轮胎ID)
  • 轮胎Map(工作Map)
  • 工作参照(aMap)
  • 工作参照(b贴图)
  • tirework(工作图)
    **编辑:**为了完整起见,我想我应该提供一些上下文。

SQL优化器查看语句,解析语句,然后根据查询、引用的表和可用的索引确定执行计划。如果执行SELECT * FROM tab1,它将对tab1执行全表扫描,因为没有其他方法可以执行。
如果您使用SELECT * FROM person WHERE lastname LIKE 'V%',并且您有一百万条记录,那么查询每一行会很慢,但是如果lastname被索引,那么效率会高得多。
对于像你这样的查询,其中一个表将是驱动表,不管索引如何,都可以简单地作为全表扫描来完成。这没有什么错。一个表必须驱动查询。如果有WHERE子句(用于连接条件以外的东西),这可能会改变,但否则它 * 通常 * 是真的。
从这个驱动表开始,MySQL将开始把连接附加到执行计划中,这些连接需要另一端的索引来使其高效地工作。
对于三个表,你可能有一个表没有索引,但这并不重要,因为它驱动查询,对于第四个表,可能有两个未索引的表,这是一个问题,因为对于一个MySQL中的每一行,都必须对另一个进行全表扫描。
因此,基本上您可以在 * 每个 * 外键和连接列上创建一个索引,以便MySQL可以使用可用的索引为您给予的查询制定最佳执行计划。
最后,大多数工具都会告诉你关于数据库模式的信息。PHPMyAdmin是托管数据库的一个流行工具。就我个人而言,我实际上喜欢一个桌面应用程序来处理这类事情。Navicat Lite是一个不错的免费工具。

nsc4cvqm

nsc4cvqm2#

您正在执行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。
下面是一些未经测试的代码,可能会对你有所帮助。你可能需要修改它,这取决于你使用的是什么DB引擎:

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个表。但是,这并不是您真正想要的。如果一行"equipment"没有在其他表中引用,则最后得到的行将少于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

瞧!即使你的引擎优化器不存在,这个查询也不会花太长时间。你的引擎将一次处理一个产品,并在将它与新表连接之前将坏行去掉,而不是对所有产品都做一个大的乘积。
试试看。

qvtsj1bj

qvtsj1bj3#

可能是您要联接的第4个表比其他表大得多,也可能是您要联接的列没有索引。

icnyk63a

icnyk63a4#

大多数SQL数据库都有“EXPLAINPLAN”或“EXPLAIN”的变体,你可以用它来查看它是如何解析查询的。在需要索引的地方寻找全表扫描。

相关问题