如何从Mysql快速查找一条数据

前言

可能许多小伙伴在面试中会遇到这么样的一道面试题:如何以最高效率随机在 Mysql 数据表中查找一条数据

实际上,这个题包含了两个点

  • 在 Mysql 数据表随机查找一条数据

  • 保证效率最高


实战

我们平时常用的英语App,大部分都有 随机显示一个单词或者多个单词的功能,为了便于理解,我设计了以下代码,并往表里加了 30000 行数据。

CREATE TABLE `words` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `word` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=0;
  while i<30000 do
    insert into words(word) values(concat(char(97+(i div 1000)), char(97+(i % 1000 div 100)), char(97+(i % 100 div 10)), char(97+(i % 10))));
    set i=i+1;
  end while;
end;;
delimiter ;

call idata();

方法一

随机查找,你可能会想到最原始最直观的方法,使用 Mysqlrand() 方法

select * from words order by rand() limit 1;

使用 explain 查看执行计划,可以发现使用 rand() ,Extra字段显示 Using temporary,表示的是需要使用临时表;Using filesort,表示的是需要执行排序操作。因此这个 Extra 的意思就是,需要临时表,并且需要在临时表上排序。

在这里插入图片描述

我们的 Mysql 使用 InnoDB存储引擎,对于 InnoDB 的数据表来说,执行全字段排序会减少磁盘访问,因此会被优先选择。但是,对于内存表,回表过程只是简单地根据数据行的位置,直接访问内存得到数据,根本不会导致多访问磁盘。优化器没有了这一层顾虑,那么它会优先考虑的,就是用于排序的行越少越好了,所以,MySQL这时就会选择 rowid 排序,排序临时表。

也就是说,order by rand() 使用了内存临时表,内存临时表排序的时候使用了 rowid 排序方法(Using temporaryUsing filesort),查询的执行代价往往是比较大的。所以,在设计的时候,我们需要尽量避开这种写法。


方法二

思路大概如下:

  • 取得这个表的主键 id 的最大值 M 和最小值 N ;

    首先查询出数据表的所有记录数

select count(*) as num_rows from words;
  • 用随机函数生成一个最大值到最小值之间的数 X = (M-N)*rand() + N;
  • 取不小于X的第一个 ID 的行。

然后在 [0, num_rows] 范围中随机

select * from words limit [0, num_rows随机一个数X], 1;

方法三

那有没有可能,一句 sql 就完成 方法二 的查询,那当然是有的,SQL 如下:

SELECT * 
 FROM  `words` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM  `words`)-(SELECT MIN(id) FROM `words`))+(SELECT MIN(id) FROM `words`))  AS id) AS t2 
WHERE t1.id >= t2.id 
ORDER BY t1.id LIMIT 1;

当然,上述的 sql 有一个问题,如果要快速随机查询多条数据,修改上述的语句 limit nn 代表 n 条数据如修改成 limit 5,那么就会产生连续的 5 条记录。解决办法只能是每次查询一条,查询 5。次。

当然,上述的问题可以使用以下方法解决。

SELECT * FROM `words` 
WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM  `words`)-(SELECT MIN(id) FROM `words`)) + (SELECT MIN(id) FROM  `words`))) 
ORDER BY id LIMIT 5;

参考博客:

https://jishuin.proginn.com/p/763bfbd308d8

猜你喜欢

转载自blog.csdn.net/a549654065/article/details/122719835