MySQL8 新特性和常用查询优化

1:默认数据引擎改变为InnoDB

Mysql8之前的版本,默认引擎为MyISAM(主要的非事务处理存储引擎),从Mysql8开始,数据库默认引擎为InnoDB(支持事务、分布式、事务部分回滚、行级锁、外键)

2:默认字符集改变为utf8mb4

Mysql8之前的版本,默认字符集为lation1,从Mysql8开始,数据库默认编码改为utf8mb4

3:新增设置系统变量参数(Persist),全局变量的持久化,如下:

show [global|session] variables like '%time_zone%'; 
 set [global|session|persist] time_zone='+8:00';  
 flush privileges; # 立即生效

4:自增变量的持久化

 Create table test1(
 id int auto_increment primary key,
 Val int
 );
 Insert into test1(val) values (1);
 Delete from table where id=1;
 -- 重启数据库
 Insert into test1(val) values (1);
 Select * from test1
 -- 发现id变成了2,但如果是MySQL5的版本,则id会是1
 

5:新增窗口函数

窗口函数类似sum(),count()那样的聚合函数,但是它不会将多行合并,而是将结果多行返回,也就是说,窗口函数是不需要Group By的,以下是几个简单的例子

 select *,sum(count) over() as totalcount from Orders;
 
 select *,count/(sum(count) over()) as totalcount from Orders;

6:新增通用表达式

通用表达试简称CTE,CTE是命名的临时结果集,作用范围是当前语句,CTE可以理解成一个可以复用的子查询,CTE可以引用其他CTE,但是子查询不能引用其他子查询 例如我们在8.0之前的sql,只能使用子查询获取类别名称

 Select g.*,(select name from category where id=g.cat_id)  cat_name from goods g;

但是在8.0之后,我们可以用CTE的方式

 With cte as ( select * from category)    
 Select g.*,(select cte.name from cte where cte.id=g.cat_id)  cat_name from goods g;

相比子查询,cte的效率会更高,因为非递归的cte只会查询一次并可以重复使用。
我们也可以使用cte引用其它cte,达到查询目的,查询例子如下

 With cte1 as ( select * from category),
 cte2 as (select g.*,cte1. name  cat_name  from goods g left join cte1 on g.cat_id=cte1.id) 
 select * from cte2

7:通用表达式CET递归神器

递归cte是特殊的cte,必须以WITH RECURSIVE开头,递归子查询包括两部分,SEED查询和RECURSIVE查询,中间由union[all]分隔, SEED查询只会执行1次,以创建初始数据集, RECURSIVE查询会重复执行,直到无法满足语句条件为止。

With RECURSIVE cte as (
 select 1 n     -- SEED查询
 union all 
 Select n+1 n from cte where n<8)  -- RECURSIVE查询
 Select * from cte;

以下是2个常用场景

场景1:递归查询指定节点的所有后代

 set @customer_id=2; -- 当前节点
 WITH RECURSIVE cte AS
 (
 SELECT 
 a.customer_id, a.inviter_id,
 cast(a.inviter_id as char(255)) path
 FROM t_customer_relation a WHERE a.customer_id=@customer_id
 UNION ALL
 SELECT
 k.customer_id,k.inviter_id,
 concat(cte.path,',', k.inviter_id) path
 FROM t_customer_relation k 
 INNER JOIN cte ON cte.customer_id = k.inviter_id
 )
 SELECT cte.customer_id,cte.inviter_id,cte.path  FROM cte 
 -- left join t_customer d  on cte.customer_id=d.id
 

场景2:根据当前节点,查询自己的祖宗

set @customer_id =29 ; -- 当前节点
 WITH RECURSIVE cte AS(
     SELECT
     customer_id, 
     inviter_id, 
     convert(inviter_id , char(255)) path 
     FROM t_customer_relation WHERE customer_id = @customer_id 
     UNION ALL
     SELECT 
     c.customer_id, 
     c.inviter_id, 
     concat(cte.path,',', c.inviter_id) path 
     FROM t_customer_relation c, cte WHERE c.customer_id= cte.inviter_id
 )SELECT * FROM cte;

8:支持json类型

Mysql是关系数据库,我们如果再Mysql8前如果有此类需求,一般用Blob类型存取。但是存在以下 缺点:

1.无法保证json正确性

2.json的二操作加工需要代码处理

3.读取json的某个字段,必须从数据库读出字段所有内容

4.无法在json上的某个字段建索引

现在,可以试试在表里使用json类型字段。如下:

Create table tb(
 jsdata  json
 );
 Insert into table(’{”key”:”123”}’);

值得注意的是,key的长度不能超过2个字节(65535)。Mysql8.0提供了很多操作json的函数,包括条件查询,具体可以参考官方文档说明

9:其他新特性

a:加密函数(md5(str),sha (str),sha2 (str,hash_length))

b:GROUP BY 不再隐式排序

c:DLL的原子化(drop table table1,table2;如果table2不存在,那table1将不会删除)

d:支持降序索引

e:统计直方图

f:支持表空间加密

g:支持不可见索引(相对于enable,哪怕隐藏时依然和正常索引一样实时更新,查询不再走)

h:跳过锁等待,sql如下:

select * from table where id=1 for update nowait; --有锁就报错)
select * from table where id=1 for update skip locked; --有锁就不理)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注