【问题标题】:MySQL: Does unified select is always faster than seperated simple selects?MySQL:统一选择总是比单独的简单选择快吗?
【发布时间】:2018-06-17 16:11:03
【问题描述】:

我有 3 张桌子:

# config - only 1 line in table
# Config (maxCount int) 
Create Table Config(maxCount int)  
# files- 20k lines in table
# Files(fileid int (pk), filename varchar (unique), revCount int) 
Create Table Files ( 
   fileid int(10) unsigned not null auto_increment,
   filename varchar(255) not null,
   revCount int(10) unsigned default 1,
   primary key(fileid),
   unique key filename(filename) 
);
# Revitions - 26k lines in table
# Revisions(revid (pk),  fileid int (fk), revname varchar,...) 
create table Revisions( 
   revid int(10) unsigned not null auto_increment,
   fileid int(10) unsigned not null, 
   revname varchar(255) not null,
   mtime  timestamp default CURRENT_TIMESTAMP,
   deleted boolean default false,
   primary key(revid),
   KEY fr_fileid_fk_idx (fileid),
   CONSTRAINT fr_fileid_fk FOREIGN KEY(fileid)
     REFERENCE Files(fileid)
     ON DELETE CASCADE ON UPDATE CASCADE 
);

并具有以下存储过程:

create procedure test1(in file_id int,out max_count int, out rev_count int, out last_revid int)
begin 
  select maxCount into max_count from Config limit 1;
  select revCount into rev_count from Files where fileid=file_id;
  select max(revid) into last_revid from Revitions where fileid=file_id;
end

我通过为文件 (20k) 中的每个 fileid 调用它来检查 test1 的性能,调用它大约需要 2.7 秒才能运行

测试过程是:

create procedure t1()
begin
  declare done int default 0;
  declare file_id,last_revid,max_count,rev_cout int default 0;
  declare c1 cursor for select fileid from files;
  declare continue handle for not found select 1 into done from (select 1) as t;
  open c1;
  read1: loop
    fetch c1 into file_id;
    if done=1 then
      leave read1;
    end if;
    call test1(file_id, max_count,rev_cout,last_revid);
  end loop;
  close c1;
end 

我尝试了其他解决方案,将 3 个选择统一为 1 个查询,如下所示:

create procedure test2(in file_id int,out max_count int, out rev_count int, out last_revid int)
begin 
  select maxCount, revCount, max(revid) 
  into   max_count,rev_count,last_revid 
  from Config, Files, Revitions 
  where Files.fileid=file_id AND Revitions.fileid=file_id
  limit 1;
end

我通过将call test1 更改为call test2t1 更改为t2

结果是性能显着提高,第二个 (t2) 花了大约 2 秒(效率提高了 25%!),我重复测试了很多次,结果始终相同。

有什么原因吗?

我认为表的连接效率较低,然后从每个表中单独选择,但显然第二个更快。

所以我可以指望它并且总是更喜欢统一来自多个表的选择查询,还是应该检查每种情况下哪个是最好的?

【问题讨论】:

  • 您是否尝试过对这些查询中的任何一个运行 EXPLAIN
  • @TimBiegeleisen 没有,只​​在 mysql workbench 中检查查询持续时间。
  • 不要忘记连续两次运行相同的查询会产生异常的计时结果。在尝试获得可重现的查询时间时,使用SELECT SQL_NO_CACHE ... 来避免这个问题。另外,请阅读此内容。 meta.stackoverflow.com/a/271056 请特别注意查询性能部分。请edit您的问题提供更多详细信息。事实上,你只是在让我们猜测。
  • @O.Jones 谢谢,我添加了 create table 语句,使用 SQL_NO_CACHE 进行统一选择的持续时间稍长一些,但性能仍然提高了 20%-25%。跨度>

标签: mysql select stored-procedures query-performance


【解决方案1】:

运行单个组合查询并不总是比运行三个单独查询更快。有时是,有时不是。

问:[单个组合查询比三个单独查询快]有什么原因吗?

答:从过程运行查询有开销,就像从任何客户端运行查询一样。有从过程到数据库引擎的上下文切换,以及语句的数据库引擎开销......解析,语法检查,语义检查,确定访问计划,执行查询,具体化结果并将其返回给客户端,如以及语句关闭时的清理。

我们可以使用单个组合语句来避免一些这种开销,一次往返数据库,而不是三个单独的往返语句执行。

但不能保证合并语句会更快。这实际上取决于语句的执行计划,以及执行每个查询需要多少时间。

如果单个组合查询的执行时间明显高于三个单独语句的总执行时间,这将有效地抵消任何开销节省,并且总体上可能会变慢。


问:我可以依靠它并且总是更喜欢统一来自多个表的选择查询,还是应该检查每种情况下哪个是最好的?

答:通常组合查询会更快。但在一般情况下,我们不能“指望”它。我们需要检查每个案例。

【讨论】:

    【解决方案2】:

    只要你在比较技术,试试这个:

    SELECT
      ( select maxCount FROM Config limit 1 ) AS max_count,
      ( select revCount FROM Files where fileid=file_id ) AS rev_count,
      ( select max(revid) FROM Revitions where fileid=file_id ) AS last_revid ;
    

    (不需要存储过程。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-22
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多