高性能MySQL学习笔记:用户自定义变量的使用

MySQL学习笔记:用户定义变量的使用

  • 一.用户自定义变量。
    • 1.用户自定义变量的介绍。
    • 2.用户自定义变量的属性和限制。
  • 二.使用用户变量的示例。
    • 1.统计更新和查询语句。
    • 2.确定取值顺序。
  • 三. 总结。

笔者在学习<<高性能mysql>>的时候,了解到了用户自定义变量的一些便捷作用,以前虽然用过mysql,但仅限于小规模数据库的增删查改,对于用户自定义变量这种隐晦的特性了解不多。遂借这次机会,做一些记录。也正好开始笔者的博客写作初体验。

一.用户自定义变量。

1.用户自定义变量的介绍。

我们在进行查询语句编写的时候往往是利用结构化的关系查询,但是单纯的结构化查询将所有数据当作一个无序的数据集合一次性操作他们。如果我们在查询中混合地使用关系话和过程化的时候,用户自定义变量就会变得非常有作用。

用户自定义变量是一个来存储内容的临时容器,它的生命周期是当前数据库连接。这一点在维护一个数据库连接池来复用连接的时候可能会带来一些困扰,需要多加注意。我们可以使用 set关键字来定义一个变量,mysql为了将变量和关键字区分开来,变量的定义需要@开头。从下面的老例子还可以看到,mysql在赋值时使用:=与等于号 = 区分开。

set @one := 1set @last_weeek := CURRENT_DATE - interval 1 week;

接下来就可以在任何可以使用表达式的地方使用变量了

select * from test where col <= @last_week

2.用户自定义变量的属性和限制。

1. 使用了用户变量的查询语句,无法使用查询缓存。

2. 不能在使用常量或标识符的地方使用变量,例如表名。

3. 用户变量的生命周期是当前连接,无法跨连接使用,而且在使用连接 池管理多连接的时候,应该小心用户变量的使用。

4.5.0版本之前大小写敏感。

5.不能显式自定义变量类型。

6.使用未定义变量不会出现任何语法错误,在变量使用时应该特别注意。

7.变量的赋值时机并不总是固定的,可能会被优化器优化,甚至被优化器忽略。

8.赋值操作符:=的优先级非常低,所以在使用赋值语句时,应尽量使用().

二.使用用户变量的示例。

使用用户自定义变量的一个重要优势就是你可以在给一个变量赋值 的同时使用这个变量。也就是说用户变量具有“左值特性”,下面用一个例子做演示。

set @rownum := 0;
select *, @rownum := @rownum + 1
from variable_test;

1.统计更新和查询语句。

当使用了INSERT ON UPDATE DUPLICATE KEY 时,如果想要知道到底插入了多少数据,多少数据是因为数据重复更改为更新操作的? <<高性能mysql>>中引用了一种利用用户变量的巧妙做法。

set @x := 0;
insert t1 (c1,c2) values(1,2), (3,4), (1,3)
on duplicate key update
c1 = values(c1) + (0 * (@x := @x + 1));

当每次冲突导致数据被更新时,变量@x做自增,但是同时由于前面的0系数,又不会对数据更新造成影响。另外,mysql会返回由query语句造成影响的行数,所以不需要单独计算。

2.确定取值顺序。

使用用户自定义变量的一个问题是忽略了用户变量的取值发生在查询语句的哪一阶段。例如,在select子句中进行赋值,在where子句中使用变量,结果可能会有点让人疑惑。

set @rownum := 0;
select *, @rownum := @rownum + 1 as rownum
from variable_test
where @rownum <= 1;

按照我们的设想,这个语句应该只会返回一条数据,但是事实并非如此,因为select 和where是在查询语句的不同阶段执行的,而where的执行顺序在select之前,所以在where进行过滤时,@rownum还未进行赋值,0<1成为了一个恒等式。

那么要想正确地完成我们的目的,上面的sql语句可以改写为下面版本。

set @rownum := 0;
select *, @rownum as rownum
from variable_test
where (@rownum := rownum + 1) <= 1;

这样我们就能顺利地输出行号为1的数据了。接下来我们对第一条语句再做一些小更改。

set @rownum := 0;
select *,@rownum := @rownum + as rownum
from variable_test
where rownum <= 1
order by name

执行这条语句之后不仅返回了全部的数据,而且连rownum的排序都变得一团糟!返回全部数据的原因我们已经知道了,那为什么连顺序都变了呢,问题依然出现在子语句的执行顺序上,order by子语句的执行时机发生在select 和where 之后,这个时候rownum已经按照select顺序完成了赋值,再重新排序当然会打乱rownum的顺序,解决这个问题的方法也很简单,那就是把赋值放入order by子语句中。

set @ronum := 0;
select *,@rownum as rownum
from variable_test
where @rownum <= 1
order by name, LEAST(0, @rownum := @rownum + 1)

order by的第二个条件返回恒定值0,不会对排序造成影响,这样我们的目的就达到了。

三. 总结。

通过用户变量的使用,可以便捷的实现一些关系型查询语句不方便做到的事情,通过本篇章的学习,我也更加深入的了解到了select语句各个子语句的执行顺序对于查询的影响。记第一次博客。

引用<<高性能mysql>> 第三版。

你可能感兴趣的:(高性能MySQL学习笔记:用户自定义变量的使用)