哪个sql查询更快:多个选择还是加入?

时间:2015-02-10 15:12:19

标签: mysql

需要确定哪个查询更快:

查询1

select xyz.user, count(*) as score
from xyz join
     (select qid, min(time) as mintime
      from xyz
      group by qid
     ) q
     on xyz.qid = q.qid and xyz.time = q.mintime
group by xyz.user;

QUERY2

select user,count(*) 
  from (select * 
          from (select * 
                  from xyz 
                 order by time ASC
               ) as temp1 
         group by temp1.qid
        ) As temp2
  group by temp2.user

两者都返回用户对每个qid“第一”的次数。

DB:

CREATE TABLE xyz (
id INT PRIMARY KEY AUTO_INCREMENT,
  user VARCHAR(20),
  time INT,
  qid INT
);

INSERT INTO xyz VALUES (    1  ,  'abc' ,  15  , 1);
INSERT INTO xyz VALUES (    2  ,  'abc' ,  6  , 1);
INSERT INTO xyz VALUES (    3  ,  'xyz' ,  11  , 1);
INSERT INTO xyz VALUES (    4  ,  'abc' ,  4  , 1);
INSERT INTO xyz VALUES (    5  ,  'xyz' ,  13  , 2);
INSERT INTO xyz VALUES (    6  ,  'abc' ,  11  ,2);
INSERT INTO xyz VALUES (    7  ,  'abc' ,  9  , 3);
INSERT INTO xyz VALUES (    8  ,  'xyz' ,  10  , 3);
INSERT INTO xyz VALUES (    9  ,  'xyz' ,  2  , 3);
INSERT INTO xyz VALUES (    10  ,  'xyz' ,  2  , 4);

编辑:建议更快地更换。

4 个答案:

答案 0 :(得分:1)

您的第一个查询包含此子查询。

 select qid, min(time) as mintime
   from xyz
  group by qid

(qid,time)上的复合索引可以使效率非常高。 MySQL将使用所谓的loose index scan.来满足该查询。因此,如果我是你,我会使用您的第一个查询。

但你应该使用EXPLAIN来确保我是对的。如果您的表格的行数是现在的100倍,您应该在将来的某个时间重新审视此问题。

答案 1 :(得分:1)

除此之外,您应该在用于搜索或比较的列上为表添加索引:

ALTER TABLE `xyz`
ADD INDEX (`qid`),
ADD INDEX (`time`);

然后将EXPLAIN放在每个查询的前面,并根据您在手册中找到的the recommendations检查结果。仔细查看有关“加入类型”“额外信息”的部分。

有或没有索引,请避免第二个查询。这是最糟糕的,无法改善。

我建议您使用另一种查询来产生相同的结果,甚至比第一种方法更快:

SELECT uif.user, COUNT(*) AS score
FROM xyz uif                  # "uif" from "user is first"
  LEFT JOIN xyz sm            # "sm" from "smaller time"
    ON uif.qid = sm.qid AND sm.time < uif.time
WHERE sm.time IS NULL         # keep only when there is no "smaller time"
GROUP BY uif.user

它将xyz表(别名为uif)与其自身连接(别名为sm)。 uif中的每一行都与sm中具有相同qid和更小时间(sm.time < uif.time)的所有行配对。 LEFT JOIN确保uif中的所有行都会显示在已加入的集合中。如果uif中的某一行没有来自sm的一对(因为sm中的行没有时间较短),sm中的列将填充{ {1}}。

NULL条件仅保留WHEREuif中没有对的行(没有“较小的时间”);这意味着它只保留sm中具有较小时间的行。

uifSELECT条款会照顾您的原始目标(返回次数)。始终只在GROUP BY条款中添加uid的列(因为SELECT的列全部都是sm

答案 2 :(得分:1)

这是关于速度的典型性能方案。至于任何此类情况,您必须进行测试和测量。

这本身就是一个非常棘手的任务,因为在第一次运行后,db引擎会缓存您的查询,并且后续执行会相当快。 在系统中测试和测量性能需要您考虑要正确完成许多变量。

另一方面:

我的估计是JOIN的查询速度最快。现代sql数据库引擎擅长优化,JOIN允许引擎自由优化查询。

答案 3 :(得分:0)

SELECT user, count(*) AS score
FROM xyz JOIN
     (SELECT qid, min(time) AS mintime
      FROM xyz
      GROUP by qid
     ) q
     ON qid = q.qid AND time = q.mintime
GROUP BY user;

我认为xyz.gidxyz.time不是必需的