2014-01-17 111 views
0

编辑: 所以这是我使用查询:优化MySQL查询与IN子句为10000条记录

SELECT * 
    FROM contacts 
    WHERE id in 
     (
    SELECT DISTINCT contacts.id 
    from contacts INNER 
    JOIN contacts2tags ON contacts.id = contacts2tags.contactid 
    WHERE (tagid in (178))) 

它运行很慢。建议优化它? 我已经添加了索引,但它仍然需要改进!

联系人表包含id,first_name,last_name,..and 标签表包含id,name。 contacts2tags表中包含的ContactID和标签识别哪些是相同contacts.id和tags.id分别 说明: enter image description here

请看看:optimise mysql query with LIKE operator for 10k records

这是愚蠢的我张贴的一部分在这里查询。对不起:P

+2

你可以把创建语法表格联系人和联系人标签以及查询中的解释。既然你使用了会有一个文件夹和临时表。所以,这也取决于你的服务器容量。 –

+0

我希望你有一个关于c.id和t.tagid索引的索引,在这种情况下,我希望MySQL能够找到contacts2tags表上的记录,然后将这些记录与联系人联系起来。如果在t.tagid上没有索引,而是在t.contactid上有一个索引,则它必须在一个或另一个表上执行非键控搜索,具体取决于它首先使用哪个索引。 – Kickstart

+0

谢谢。我确实在索引编号和编号 – user415

回答

0

我刚刚比较了查询
select benchmark(1000000,1 in(1,2,3,4,5));花费0.122秒
选择基准(1000000,(1 = 1或1 = 2或1 = 3或1 = 4或1 = 5));花了0.088秒

所以,你可以尝试使用或代替我不知道,但在索引也没有使用,所以只是试一试。

0

使用或代替IN。

您的查询应该是: SELECT c.id FROM接触℃的内部加入contacts2tags吨上c.id = t.contactid WHERE (t.tagid = 7或t.tagid = 4) GROUP BY c.id HAVING count(distinct t.tagid)= 2

0

您向我们显示的计划表示优化器只希望获取3行数据。如果它的“缓慢”(你没有说速度有多慢),那么大概这个计划并不是最优的,或者你的数据是非常不正确的。

我要检查的第一件事是索引统计是否是最新的。然后我试试...

SELECT count(*) 
    FROM contacts c 
inner join contacts2tags t 
    on c.id = t.contactid 
    WHERE t.tagid in (7,4) 

要了解DBMS实际处理多少行以解决查询。如果这个数字非常高,那么你不可能通过调整查询来获得很大的性能提升。

....但一个潜在的解决方案将....

SELECT c.id 
FROM contacts c, 
    contacts2tags t4, 
    contacts2tags t7, 
WHERE c.id = t4.contactid 
AND c.id = t7.contactid 
AND t4.contactid=t7.contactid 
AND t4.tagid=4 
AND t7.tagid=7; 
+0

上都有索引,对不起,实际的行数是11000.我正在编辑与实际快照(如在实际服务器上)的帖子 – user415

+0

你真的没有主键在contacts.id? ?? !!!! – symcbean

+0

of course我拥有它 – user415

0

不能看到你更新的查询使用子查询的需要。尝试以下(尽管最好使用来自联系人而非联系人的所需列的名称。*)。

SELECT DISTINCT contacts.* 
FROM contacts 
INNER JOIN contacts2tags ON contacts.id = contacts2tags.contactid 
WHERE tagid IN (178) 

确保contacts2tags表上的tagid上有一个索引。

如果contacts2tags上的contactid/tagid是唯一的(我希望),那么不需要DISTINCT。这可以通过在tagid/contactid上添加一个唯一的覆盖索引来强制执行(以便允许在WHERE子句中使用此密钥)。

+0

那不好?!假设每个标签有多个ID,您将获得多个联系人记录,然后您可以再次使用DISTINCT“修复”这些记录,从而为服务器提供比严格需要的更多工作。 – deroby

+0

另一种方法是针对子查询使用连接,这会导致连接未被编入索引,或者使用IN作为原始文章中的子查询,这将再次变为非索引。在这种情况下,它可能会针对对索引tagid列的contacts2tags进行查询,然后将其与使用主键id字段的联系人进行连接。如果IN子句中有多个tagid,则区别是一个令人讨厌的问题,但不能真正避免任何效率。 – Kickstart

0

我想知道为什么你会先在子查询中加入联系人和contacts2tags,然后再用它来过滤联系人!

我推测原因是你已经将DISTINCT优化​​到了id(精简)id字段,而不是之后在整个联系人*记录中进行。

不管怎么说,你实际上应该做恕我直言如下:

SELECT * 
FROM contacts 
WHERE EXISTS (SELECT * 
       FROM contacts2tags 
       WHERE contacts2tags.contactid = contacts.id 
        AND tagid in (178)) 

这不会双触点记录作为查询处理器知道它可以停止搜索,一旦发现在contacts2tags表中的第一次打击。

至于使用IN()对使用或者......我怀疑它将使一个很大的区别,作为内部它可能被转换为同样的事情呢(?!)

+0

嘿,请看看http://stackoverflow.com/questions/21154636/optimise-mysql-query-with-like-operator-for-10k-records/21155012#21155012我想因为在contacts2tags中有很多记录表以及,当我使用WHERE EXISTS(..)或者可能是其他原因时,查询变得更慢。我是MySQL的业余爱好者。感谢您对这篇文章的支持。 :D – user415

+0

另一篇文章主要关注LIKE和文本匹配;我怀疑WHERE EXISTS()与那个有什么关系。在我的(基于MSSQL的)经验中,WHERE EXISTS()永远不应该比JOINING慢,尤其是当那个JOIN稍后再需要额外的DISTINCT时。但也许MySQL是奇特的? – deroby