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 函数调用优化
Apr 07 MySQL
如何使用Maxwell实时同步mysql数据
Apr 08 MySQL
MySQL Router的安装部署
Apr 24 MySQL
MySQL Shell import_table数据导入的实现
Aug 07 MySQL
mysql分表之后如何平滑上线详解
Nov 01 MySQL
mysql 索引的数据结构为什么要采用B+树
Apr 26 MySQL
mysql 获取相邻数据项
May 11 MySQL
深入理解MySQL中MVCC与BufferPool缓存机制
May 25 MySQL
Mysql中@和@@符号的详细使用指南
Jun 05 MySQL
MySQL安装失败的原因及解决步骤
Jun 14 MySQL
mysql数据库隔离级别详解
Jun 16 MySQL
mysql sql常用语句大全
Jun 21 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 radio 单选框获取与保持值的实现代码
2010/05/15 PHP
hessian 在PHP中的使用介绍
2010/12/13 PHP
PHP文件上传操作实例详解
2016/09/27 PHP
PHP使Laravel为JSON REST API返回自定义错误的问题
2018/10/16 PHP
javascript基于jQuery的表格悬停变色/恢复,表格点击变色/恢复,点击行选Checkbox
2008/08/05 Javascript
jQuery Selector选择器小结
2010/05/06 Javascript
Jquery 模拟用户点击超链接或者按钮的方法
2013/10/25 Javascript
了不起的node.js读书笔记之mongodb数据库交互
2014/12/22 Javascript
多种js图片预加载实现方式分享
2016/02/19 Javascript
javascript时间戳和日期字符串相互转换代码(超简单)
2016/06/22 Javascript
EditPlus中的正则表达式 实战(2)
2016/12/15 Javascript
JS正则子匹配实例分析
2016/12/22 Javascript
node实现登录图片验证码的示例代码
2018/04/20 Javascript
如何在vue里面优雅的解决跨域(路由冲突问题)
2019/01/20 Javascript
javascript随机变色实例代码
2019/10/15 Javascript
基于axios 的responseType类型的设置方法
2019/10/29 Javascript
python创建只读属性对象的方法(ReadOnlyObject)
2013/02/10 Python
Python操作Mysql实例代码教程在线版(查询手册)
2013/02/18 Python
python实现巡检系统(solaris)示例
2014/04/02 Python
python单例模式实例分析
2015/04/08 Python
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
python 动态调用函数实例解析
2019/10/21 Python
python机器学习实现决策树
2019/11/11 Python
python list数据等间隔抽取并新建list存储的例子
2019/11/27 Python
CSS3属性box-shadow使用详细教程
2012/01/21 HTML / CSS
阿联酋航空假期:Emirates Holidays
2018/03/20 全球购物
The Hut美国/加拿大:英国领先的豪华在线百货商店
2019/03/26 全球购物
SAZAC的动物连体衣和动物睡衣:Kigurumi Shop
2020/03/14 全球购物
关于礼仪的演讲稿
2014/01/04 职场文书
泰山导游词
2015/02/02 职场文书
2015年艾滋病宣传活动总结
2015/03/27 职场文书
辩论赛开场白大全(主持人+辩手)
2015/05/29 职场文书
2016年习总书记讲话学习心得体会
2016/01/20 职场文书
Canvas三种动态画圆实现方法说明(小结)
2021/04/16 Javascript
Python标准库pathlib操作目录和文件
2021/11/20 Python
Flink 侧流输出源码示例解析
2022/09/23 Servers