2010-11-19 113 views
0

考虑以下两个查询:添加WHERE子句使查询很慢

select a.*, c.* 
from account a 
join customer c on a.customer_id = c.id 
join import i on a.import_id = i.id 
join import_bundle ib on i.import_bundle_id = ib.id 

select a.*, c.* 
from account a 
join customer c on a.customer_id = c.id 
join import i on a.import_id = i.id 
join import_bundle ib on i.import_bundle_id = ib.id 
where ib.id = 8 

第一个查询速度快,第二个是超级慢。任何想法为什么?我猜我需要一个索引或其他东西,但我不明白索引的工作原理。我正在使用MySQL。

这里的,如果我在第二查询做一个EXPLAIN会发生什么:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE ib const PRIMARY  PRIMARY  8 const 1 Using index 
1 SIMPLE c ALL  PRIMARY   144858 
1 SIMPLE a ref  fk_account_customer_id,fk_account_import_id  fk_account_customer_id 8 mcif.c.id 2 
1 SIMPLE i eq_ref PRIMARY,import_bundle_id PRIMARY  8 mcif.a.import_id 1 Using where 

我不知道如何解释,虽然。

编辑:这是我最后使用:

select a.*, 
     c.* 
    from account a 
    join customer c on a.customer_id = c.id 
    join (select id, 
       import_bundle_id 
      from import 
     where import_bundle_id = 8) i on a.import_id = i.id 
    join import_bundle ib on i.import_bundle_id = ib.id 

import_bundle.id添加索引什么也没做。

+0

查询计划看起来像什么?索引涵盖ib.id? – 2010-11-19 19:46:08

+0

你是什么意思,“查询计划看起来像什么?” – 2010-11-19 20:14:10

+0

有时,事情并不像他们看起来那样。你如何比较这两个查询?你看过检索_first_记录的时间还是_last_记录。后者是应该测量的东西,但如果您是从SQL客户端应用程序开始工作,则只需查看前者即可。 – Axn 2010-11-19 20:20:39

回答

1
  • 关于性能,在您的查询中,您确实需要a。*和c。*?

  • 因此,索引的使用不够好。我不熟悉mysql,但你可以试试像这样的子查询连接?

 
    select a.*, c.* 
    from account a 
    join customer c on a.customer_id = c.id 
    join 
    ( 
     SELECT id, import_bundle_id FROM import WHERE id = 8 
    ) as i on a.import_id = i.id 
    join import_bundle ib on i.import_bundle_id = ib.id 
    where ib.id = 8 
  • 也许,最好的指标是:对import.import_bundle_id索引和import_bundle.id另一个指标。
+0

注意:为了使它实际工作('where where id = 8'应该是'where import_bundle_id = 8'),我不得不编辑这个查询,但子查询的想法奏效了。该指数没有改变任何东西。 – 2010-11-22 14:17:47

1

后者查询强制MySQL发现结果与ib.id = 8

集如果添加一个索引来import_bundle.id内的结果,那么MySQL将能够快速找到相应的记录,而不必全部检查它们。

数据库索引就像教科书中的索引,而不是查看每个页面,然后转到后面的索引,找到要查找的内容的页码并直接进入该索引。

+0

嗯,我做了'CREATE INDEX id_index ON import_bundle(id)',对速度没有明显的影响。我做错了吗? – 2010-11-19 19:55:06

+0

@Jason Swett不一定,该指数有望加速限制结果集的过程,但仍需要一些时间。 – Orbling 2010-11-19 20:15:16

+0

@Jason Swett我从你的查询计划中看到,import_bundle.id已经是该表的主键了吗?主键本身就是一个独特的索引,因此添加额外的索引对速度没有影响。它根据计划使用WHERE子句的PRIMARY索引。 – Orbling 2010-11-19 20:19:26

0

我并不熟悉mysql,但ib.id上的索引几乎肯定会有所帮助。您在JOIN或WHERE子句中使用的任何字段通常应该被编入索引。此外,你可以尝试过滤i.import_bundle_id而不是ib.id,看看是否有帮助。

索引通常用于加快查找信息的速度。与其不必遍历遍布整个数据库的每个项目来找到合适的项目,他们可以使用散列表或类似的方法来缩小它们必须查看的范围,可能将范围缩小到正确的记录。 Wikipedia explains it远比我可以。 :)

0

其他答案指出你在正确的方向至ib.id索引。但是,ib.id看起来像主键(PK)。它在数据库中设置为PK吗?如果是这样,它应该通过成为一名PK自动获得索引。如果它没有设置为PK,并且确实是应为的列,那么数据库的问题不仅仅是性能问题。

简而言之,如果ib.id应该是一个主键,那么将其设为1,并且您的性能应该会提高,因为它会自动获取索引(并且您不必担心单独向其中添加任何索引)。

+0

这是一个PK。出于某种原因,堆栈溢出注释必须至少有一定的长度,所以我在这里输入更多的东西。 – 2010-11-19 20:05:51