一、主题研究来源:最近在做一个随机组卷的功能,试题类型有单选题、多选题、判断题、简答题和应用题,该部分的业务需求是根据随机组卷规则,也就是各类型题规定需选多少道,对应在数据库中随机获取不重复的记录数。
二、需求说明:根据题库类型、试题类型和查询记录数在数据库随机查询不重复的记录进行返回。以下sql语句中的试题类型、题库类型以及随机返回记录数都分别设置为1(单选题),8(一级题库),5。
三、根据需求亲试研究给出针对Mysql数据库以下四种SQL语句(供君参考):
提示:1.测试数据为50万条,每条sql性能测试十次取平均值
2.以下四种sql语句耗时由高到低进行排列
One/Sql:1.耗时最少,位于性能杀手排行榜榜首
2.测试十次耗时:0.00026 0.00026 0.00030 0.00024 0.00023 0.00024 0.00022 0.00042 0.00024 0.00025
3.十次测试平均时间:0.000266
4.查出记录的主键ID是有序排列的
#question_test:表名 q_bank_type:试题库类型 question_type:试题类型
SELECT t1.id,t1.title,t2.id FROM question_test AS t1 JOIN(SELECT ROUND(RAND() * (SELECT MAX(id) FROM question_test)) AS id) AS t2
WHERE t1.id >= t2.id AND t1.q_bank_type=8 AND t1.question_type =1
ORDER BY t1.id ASC LIMIT 5;
One/Explain:1.SELECT MAX(id) FROM question_test 从试题表中获取最大的Id值
2.RAND() * (SELECT MAX(id) FROM question_test 随机获取0到最大值之间的数(单独测试前面加上SELECT)
3.SELECT ROUND(RAND() * (SELECT MAX(id) FROM question_test)) 四舍五入随机获取0到最大值之间的数
4.JOIN()主要把满足WHERE条件的question_test表记录 和 JOIN括号里获得的数一个个进行拼接返回
5.ORDER BY 语句对以上结果集按表主键进行排序,Limit 5 表示查五条
One/Image:
Two/Sql:1.耗时位于性能杀手排行榜第二位
2.测试十次耗时:0.000346 0.000272 0.000262 0.000274 0.000251 0.000259 0.000273 0.000250 0.000272 0.000345
3.测试十次平均时间:0.000280
4.查出记录的主键ID是有序排列的
#question_test:表名 q_bank_type:试题库类型 question_type:试题类型
SELECT t1.id,t1.title,t2.id FROM question_test AS t1 JOIN(SELECT ROUND(RAND()* ((SELECT MAX(id) FROM question_test) - (SELECT MIN(id) FROM question_test))
+ (SELECT MIN(id) FROM question_test)) AS id) AS t2
WHERE t1.id >= t2.id AND AND t1.q_tank_type=8 AND t1.question_type =1 ORDER BY t1.id LIMIT 5;
Two/Explain:没明白请参照第一条SQL的解析模式,一步步进行分析吧!
Two/Image:
Three/Sql:1.耗时位于性能杀手排行榜第三位
2.测试十次耗时:1.973573 1.965968 1.935895 1.949896 1.951759 1.947297 1.941950 1.944946 1.977690 1.945701
3.十次平均测试时间:1.9534675
4.查出记录的主键ID呈乱序排列的
#question_test:表名 q_bank_type:试题库类型 question_type:试题类型
SELECT id, title FROM question_test WHERE q_bank_type=8 AND question_type =1 ORDER BY RAND() LIMIT 5;
Three/Explain:无
Three/Image:
Four/Sql:1.耗时位于性能杀手排行榜榜末
2.测试十次耗时:100.854251 70.259152 117.024592 76.072386 74.670738 74.066505 73.781441 43.795168 83.694435 84.508763
3.十次测试平均时间:79.872743
4.查出记录的主键ID呈乱序排列的 且查询的时候电脑风扇加速转动
#question_test:表名 q_bank_type:试题库类型 question_type:试题类型
SELECT id,title FROM `question_test`
WHERE q_bank_type=8 AND question_type =1 AND id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `question_test`)
ORDER BY id LIMIT 5;
Four/Explain:FLOOR() 为取整函数,其他部分请参照第一条SQL的解析模式
Four/Image:
SQL总结(从左到右性能):OneSQL 稍大于 TwoSQL 大于 ThreeSQL 远大于 FourSQL
四、如何查看一个sql语句执行完后的耗时呢?
步骤1.每条SQL语句执行完了之后,查询该SQL执行时间请执行该语句:"SHOW profiles;",如果不行,紧接着操作以下步骤2
步骤2.执行SQL语句:" SET profiling=1",之后每执行完一条SQL语句,再执行该语句:"SHOW profiles;",就可以查看耗时了
五、如何往一个表中一次性添加大量测试数据?
步骤1.清空表记录语句:TRUNCATE question_test;
步骤2.创建存储过程语句,请把以下语句一起执行:
#创建存储过程,注意以下语句一起执行
DELIMITER &&
CREATE PROCEDURE quetion_test()
BEGIN
DECLARE i INT;
SET i=1;
WHILE i<500000 DO
INSERT INTO question_test (`title`,`question_type`,`q_tank_type`,`score`,`level`,`difficult`,`correct`,`create_user`,`status`,`create_time`,`deleted`)
VALUES(CONCAT('试题',i),1,8,20,5,1,'D',1,1,'2020-06-09 10:05:29','\0');
SET i=i+1;
END WHILE;
END
&&
步骤3.执行存储过程语句:"CALL quetion_test();"
提示:经过以上三步骤,就往question_test表里一次性成功添加了50万条测试数据了;如果需要删除已存在的存储过程,执行SQL语句:"DROP PROCEDURE IF EXISTS quetion_test;" 即可!
六、总结
以上SQL语句都经过亲自挑选并在SQLyang中一一进行测试,可以放心使用;有啥不足的地方,欢迎随时指正!