查询结果在200K数据库上耗时太长,加快提示?

时间:2010-04-17 01:10:53

标签: sql mysql postgresql sqlalchemy

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

4 个答案:

答案 0 :(得分:5)

确保您拥有索引:

  • 设备(轮胎图)
  • tiremap(TireID)
  • 轮胎图(工作地图)
  • workreference(aMap)
  • workreference(bMap)
  • 轮胎工作(工作地图)

编辑:我想我应该为完整性提供一些背景信息。

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”变体,您可以使用它来查看它如何解析查询。寻找全表扫描作为您需要索引的地方。