MySQL 使用自定义变量进行查询优化


Posted in MySQL onMay 14, 2021

优化排序查询

自定义变量的一个重要特性是你可以同时将该变量的数学计算后的结果再赋值给该变量,类似于我们的 i = i + 1这种方式。下面是一个用于计算数据表行号的例子:

SET @rownum := 0;
SELECT actor_id, @rownum := @rownum + 1 AS rownum
FROM sakila.actor LIMIT 3;

 

actor_id rownum
1 1
2 2
3 3

得到的结果也许看起来没什么意义,这是因为主键是从1自增的,因此行号和主键值是一样的。但是,这种方式可以用于做排序。例如需要查询饰演电影数量最多的前10名演员,通常的做法是像下面这样写:

SELECT actor_id, COUNT(*) as cnt
FROM sakila.film_actor
GROUP BY actor_id
ORDER BY cnt DESC
LIMIT 10;

得到的结果也许看起来没什么意义,这是因为主键是从1自增的,因此行号和主键值是一样的。但是,这种方式可以用于做排序。例如需要查询饰演电影数量最多的前10名演员,通常的做法是像下面这样写:

SELECT actor_id, COUNT(*) as cnt
FROM sakila.film_actor
GROUP BY actor_id
ORDER BY cnt DESC
LIMIT 10;

如果我们要获得相应的排名值的话,则可以引入变量来完成:

SET @curr_cnt := 0, @prev_cnt := 0, @rank := 0;
SELECT actor_id,
	@curr_cnt := cnt AS cnt,
  @rank 		:= IF(@prev_cnt <> @curr_cnt, @rank+1, @rank) as rank,
  @prev_cnt	:= @curr_cnt AS dummy
FROM (
  SELECT actor_id, COUNT(*) AS cnt
  FROM sakila.film_actor
	GROUP BY actor_id
	ORDER BY cnt DESC
	LIMIT 10
) as der;

这里是将饰演电影的数量赋值给了 curr_cnt 变量,使用了prev_cnt 存储前一个演员的参演数量。排名从第一名开始的,如果后面的演员的数量和前一个演员的数量不同,则排名要往下(+1),如果相同则和前一个演员的排名相同。通过这种方式可以直接从查询结果中得到演员的排名,而不需要再从数据库查询做二次处理(当然也可以通过程序代码实现)。

避免重复获取刚刚修改的数据行

如果想在更新数据行的时候再重新获取数据行的信息,往往需要再读取一次数据库。这是因为 MySQL 不像 PostgreSQL 的 UPDATE RETURNING 功能可以同时返回更新后的数据行,而只是返回更新影响的行数。但是,我们可以通过自定义变量完成这样的操作。例如,获取刚刚被修改过更新时间的行,不使用自定义变量的话需要做一次额外的查询:

UPDATE tb1 SET lastUpdated = NOW() WHERE id = 1;
SELECT lastUpdated FROM tb1 WHERE id = 1;

而使用自定义变量的时候可以避免这种情况:

UPDATE tb1 SET lastUpdated = NOW() WHERE id = 1 AND @now  := NOW();
SELECT @now;

虽然还是有一个查询操作,但是后面的查询操作不再需要访问数据库了。

懒加载的联合查询

假设我们需要写一个联合查询完成如下任务:在联合的分支上查找匹配的数据行,如果找到了就跳过其他分支。y这种情况发生在需要从热区数据或低频访问数据中查找(比如近期订单和历史订单)。这是下面针对用户查询的一个普通的 SQL:

SELECT id FROM users WHERE  id = 123
UNION ALL
SELECT id FROM users_archived WHERE id = 123;

这个查询会先从当前正在使用的用户表查询 id 为123的用户,然后 在从已归档的用户表找同样 id 的用户。但是,这种写法比较低效,即便是在 users 表找到了想要找的用户,还是需要从users_archived 这个表再找一次,而实际用户 id 为123的只会存在其中的一张表中或两张表的数据是一样的。通过懒加载的联合查询,可以避免这种情况——只有在第一个分支没有找到数据时才进行第二个分支的查询。因此可以使用 MySQL 的 GREATEST 方法来作为查询结果的容器以避免多返回数据列。

SELECT GREATEST(@found := -1, id) AS id, users.name, 'users' as which_tb1
FROM users WHERE id = 123
UNION ALL
	SELECT id, users_archived.name, 'users_archived'
  FROM users_archived WHERE id = 123 AND @found IS NULL
UNION ALL
	SELECT 1, '', 'reset' FROM DUAL WHERE ( @found := NULL) IS NOT NULL;

上述的查询如果第一行有结果,则@found 不会被赋值,因而是 NULL,从而执行第二次查询。而第三次的 UNION 实际没什么效果,只是为了将@found恢复到 NULL 值,以便这段 SQL 可以重复执行。另一个验证的方法是对同一张表进行这样的操作,可以发现实际只会返回一行数据或不返回数据(查询不到数据时)。

SELECT GREATEST(@found := -1, `id`) AS `id`, `infocenter_city`.`name`, 'city' as which_tb1 
FROM `infocenter_city` WHERE `id` = 460100 
UNION ALL 
	SELECT `id`, `infocenter_city`.`name`, 'infocenter_city' 
	FROM `infocenter_city` WHERE id = 460100 AND @found IS NULL 
UNION ALL 
	SELECT 1, '', 'reset' FROM DUAL WHERE ( @found := NULL) IS NOT NULL

以上就是MySQL 使用自定义变量进行查询优化的详细内容,更多关于MySQL 用自定义变量进行查询优化的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
一看就懂的MySQL的聚簇索引及聚簇索引是如何长高的
May 25 MySQL
修改MySQL的默认密码的四种小方法
May 26 MySQL
MySQL系列之一 MariaDB-server安装
Jul 02 MySQL
mysql 索引合并的使用
Aug 30 MySQL
MySQL中datetime时间字段的四舍五入操作
Oct 05 MySQL
全面盘点MySQL中的那些重要日志文件
Nov 27 MySQL
MySQL如何快速创建800w条测试数据表
Mar 17 MySQL
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
Mar 23 MySQL
mysql查询结果实现多列拼接查询
Apr 03 MySQL
MySQL事务操作的四大特性以及并发事务问题
Apr 12 MySQL
MySQL自定义函数及触发器
Aug 05 MySQL
MySQL常用慢查询分析工具详解
Aug 14 MySQL
MySQL 逻辑备份与恢复测试的相关总结
May 14 #MySQL
MySQL 可扩展设计的基本原则
May 14 #MySQL
MySQL主从搭建(多主一从)的实现思路与步骤
May 13 #MySQL
MySQL如何构建数据表索引
May 13 #MySQL
MySQL 自定义变量的概念及特点
May 13 #MySQL
为什么mysql字段要使用NOT NULL
MySQL表字段时间设置默认值
May 13 #MySQL
You might like
php简单封装了一些常用JS操作
2007/02/25 PHP
php读取纯真ip数据库使用示例
2014/01/26 PHP
php生成百度sitemap站点地图类函数实例
2014/10/17 PHP
PHP获取数组中重复最多的元素的实现方法
2014/11/11 PHP
php函数实现判断是否移动端访问
2015/03/03 PHP
PHP7匿名类用法分析
2016/09/26 PHP
php版微信数据统计接口用法示例
2016/10/12 PHP
来自chinaz的ajax获取评论代码
2008/05/03 Javascript
location.href语句与火狐不兼容的问题
2010/07/04 Javascript
获取select元素被选中的文本内容的js代码
2014/01/29 Javascript
jQuery实现从身份证号中获取出生日期和性别的方法分析
2016/02/25 Javascript
javascript用正则表达式过滤空格的实现代码
2016/06/14 Javascript
js实现加载更多功能实例
2016/10/27 Javascript
Vue.js系列之项目结构说明(2)
2017/01/03 Javascript
如何获取TypeScript的声明文件.d.ts
2018/05/01 Javascript
一行JavaScript代码如何实现瀑布流布局
2020/12/11 Javascript
[52:00]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 LGD vs Optic
2018/04/02 DOTA
kNN算法python实现和简单数字识别的方法
2014/11/18 Python
python2爬取百度贴吧指定关键字和图片代码实例
2019/08/14 Python
python文件读取失败怎么处理
2020/06/23 Python
python使用matplotlib绘制折线图的示例代码
2020/09/22 Python
浅谈Selenium 控制浏览器的常用方法
2020/12/04 Python
浅谈HTML5新增和废弃的标签
2019/04/28 HTML / CSS
Linux的文件类型
2016/07/05 面试题
在校生钳工实习自我鉴定
2013/09/19 职场文书
药学专业毕业生求职信
2013/10/20 职场文书
中医药大学毕业生自荐信
2013/11/08 职场文书
给儿子的表扬信
2014/01/15 职场文书
求职简历中自我评价
2014/01/28 职场文书
2014年计生标语
2014/06/23 职场文书
股权转让协议范本
2014/12/07 职场文书
个人党性锻炼总结
2015/03/05 职场文书
员工福利申请报告
2015/05/15 职场文书
国家助学金受助感言
2015/08/01 职场文书
ORACLE查看当前账号的相关信息
2021/06/18 Oracle
Python机器学习之决策树和随机森林
2021/07/15 Javascript