2013-02-18 97 views
2

我试图优化查询速度慢,大约需要5分钟,我的服务器在我的电脑上运行,大约相同的时间(即具有RAM的8GB)慢MySQL的子查询

SELECT 
    buyer_id as bid, 
    date_sold as dsold, 
    (
     SELECT seller_id 
     FROM sale 
     WHERE buyer_id = bid 
     ORDER BY date_acquired 
     LIMIT 1 
    ) as sid 
from sale 
WHERE seller_id = 3585328; 

我我为这个查询创建了一个测试索引。

| sale |   1 | test    |   1 | buyer_id   | A   |  4900222 |  NULL | NULL |  | BTREE  |   | 
| sale |   1 | test    |   2 | date_acquired | A   | 14700667 |  NULL | NULL |  | BTREE  |   | 

当我运行一个解释,我得到

mysql> EXPLAIN SELECT buyer_id as bid,date_sold as dsold, (SELECT seller_id FROM sale WHERE buyer_id = bid ORDER BY date_acquired LIMIT 1) as sid from sale WHERE seller_id = 3585328; 
+----+--------------------+-------+------+---------------+------+---------+-------+-------+------------------------------------------+ 
| id | select_type  | table | type | possible_keys | key | key_len | ref | rows | Extra         | 
+----+--------------------+-------+------+---------------+------+---------+-------+-------+------------------------------------------+ 
| 1 | PRIMARY   | sale | ref | test   | test | 8  | const | 12466 | Using index        | 
| 2 | DEPENDENT SUBQUERY | sale | ref | test   | test | 8  | func |  3 | Using where; Using index; Using filesort | 

我明白,一个子查询可能会很慢,但我跑出来的关于如何优化的想法。 我不确定它是否有意义,但如果我通过buyer_id进行分组,则查询运行速度显着加快。 因为我依靠子查询中的“限制1”,所以用连接代替感觉很棘手。

+0

是那个date_acquired索引降序或升序? – iiro 2013-02-18 10:19:36

+0

我可能在这里误解了一些东西,但是您的子查询不会只是每次都返回您的'WHERE'子句中指定的买家ID?在这种情况下,它有什么意义? – 2013-02-18 10:20:32

+0

'slow mysql',是不是其中的那些单词冗余? – 2013-02-18 10:20:35

回答

0

首先,您的查询看起来很奇怪。除非我没有得到你想要做的事,否则我不会理解你为什么要做这个子查询,因为你想得到“buyer_id”,但是其中buyer_id = 3585328;第二,事件如果这是一个错字,并且你想做别的事情,如果你ORDER BY date_acquired,你应该在date_acquired上有一个索引;

+0

对不起,这是我的错误。我改变了子查询来反映它的正确用法。它应该返回seller_id。 关于索引,由于mysql不能对同一个查询使用两个索引,是不是应该在(buyer_id,date_acquired)上有一个索引? – user2082807 2013-02-18 10:29:02

+0

你想得到什么?给定卖家的最近买家?给定买家的最近卖家? – 2013-02-18 16:58:37

0

如果您的目的是为了获得最新的sid;尝试类似:

SELECT 
    t1.buyer_id AS bid, 
    t1.date_sold AS dsold, 
    t1.id AS sid 
FROM 
    sale AS t1 
LEFT OUTER JOIN 
    sale AS t2 
    ON (t1.buyer_id = t2.buyer_id AND t1.date_acquired < t2.date_acquired) 
WHERE t2.date_acquired IS NULL;