mysql官网介绍新特性地址
https://blog.csdn.net/horses/article/details/85038949
等值查询博客介绍
等值查询官网介绍
其实博客中介绍的很详细,但是我这里也会说明几点:
我们为了介绍等值查询先创建3张表,而且往每张表里面插入100万条记录
CREATE TABLE t1 (c1 INT, c2 INT);
CREATE TABLE t2 (c1 INT, c2 INT);
CREATE TABLE t3 (c1 INT, c2 INT);
MySQL怎么快速插入100条记录呢?很简单,如下:
--往T1里面插入100万条,同理可以插入t2,t3
INSERT INTO t1
-- INSERT INTO t2
-- INSERT INTO t3
WITH RECURSIVE t AS (
SELECT 1 AS c1, 1 AS c2
UNION ALL
SELECT t.c1 + 1, t.c1 * 2
FROM t
WHERE t.c1 < 1000000
)
SELECT *
FROM t;
A:连接条件
SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1;
SELECT * FROM t1 JOIN t2 ON t1.c1=t2.c1;
## 1. 可以
EXPLAIN ANALYZE SELECT * FROM t1, t2 ,t3 WHERE t1.c1 = t2.c1 and t3.c1 =t2.c1;
## 2.可以
SELECT * FROM t1 JOIN t2 ON (t1.c1 = t2.c1 AND t1.c2 < t2.c2)
JOIN t3 ON (t2.c1 = t3.c1);
EXPLAIN FORMAT=TREE SELECT * FROM t1, t2,t3 WHERE t1.c1 = t2.c1 and t3.c1 > t2.c1;
##或者这样写都是不能用的
SELECT * FROM t1 JOIN t2 ON (t1.c1 = t2.c1)
JOIN t3 ON (t2.c1 < t3.c1)
B:笛卡尔积查询
因为连接如: select * from a,b where a.id =b.id
其实就是一种笛卡尔积的方式,而且即使没有where条件其实还是笛卡尔积的方式,如:select * from a,b
那么其实上面的等值连接也可以用到笛卡尔积方式的连接上,如:select * from a, b where a.id>10
,实际上诉应用就是:
如下:两种都可以用到hash join
EXPLAIN ANALYZE SELECT * from t1 ,t2 where t1.c1<50
EXPLAIN ANALYZE SELECT * from t1 JOIN t2 where t1.c1<50
C:查看是否用了等值连接
EXPLAIN FORMAT=TREE
命令可以看到执行计划中的 hash join,例如:EXPLAIN FORMAT=TREE
SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1;
--如下所示
mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (t2.c1 = t1.c1) (cost=199274951320.59 rows=199274851191)
-> Table scan on t2 (cost=0.02 rows=1995918)
-> Hash
-> Table scan on t1 (cost=100539.40 rows=998412)
|
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.03 sec)
EXPLAIN ANALYZE
SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1;
--如下:
mysql> EXPLAIN ANALYZE
-> SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (t2.c1 = t1.c1) (cost=199274951320.59 rows=199274851191) (actual time=1866.313..3850.063 rows=2000000 loops=1)
-> Table scan on t2 (cost=0.02 rows=1995918) (actual time=18.531..1259.661 rows=2000000 loops=1)
-> Hash
-> Table scan on t1 (cost=100539.40 rows=998412) (actual time=0.124..1331.061 rows=1000000 loops=1)
|
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (3.99 sec)
博客介绍
MySQL 8.0 支持隐藏索引(invisible index),也称为不可见索引。隐藏索引不会被优化器使用。主键不能设置为隐藏(包括显式设置或隐式设置)。
索引默认是可见的(visible)。使用CREATE TABLE、CREATE INDEX 或ALTER TABLE语句的VISIBLE或者INVISIBLE选项设置一个新建索引的可见性:
ALTER TABLE t1 ALTER INDEX i_idx INVISIBLE;
ALTER TABLE t1 ALTER INDEX i_idx VISIBLE;
SELECT INDEX_NAME, IS_VISIBLE
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'xxx' AND TABLE_NAME = 'tableXXX';
show index from tableXXX
不可见索引特性可以用于测试删除某个索引对于查询性能的影响,同时又不需要真正删除索引,也就避免了错误删除之后的索引重建。对于一个大表上的索引进行删除重建将会非常耗时,而将其设置为不可见或可见将会非常简单快捷。
5. 主键索引不能设置为不可见,如果没有显式的设置主键,但是 NOT NULL 字段 j 上存在一个唯一索引,它实现了和主键相同的数据约束,不能设置为不可见:
当创建表时没有显示定义主键时.
1 首先判断表中是否有非空的整形唯一索引,如果有,则该列为主键
(这时候可以使用 select _rowid from table ).查询到主键列
2 如果没有符合条件的则会自动创建一个6字节的主键(该主键是查不到的).
比如创建如下表
CREATE TABLE `t` (
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
`id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx1` (`c1`,`c2`),
KEY `idx2` (`c1`,`c2` DESC),
KEY `idx3` (`c1` DESC,`c2`),
KEY `idx4` (`c1` DESC,`c2` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of t
-- ----------------------------
INSERT INTO `t` VALUES ('1', '1', '1');
INSERT INTO `t` VALUES ('2', '2', '2');
INSERT INTO `t` VALUES ('3', '3', '3');
INSERT INTO `t` VALUES ('4', '4', '4');
explain select * from tORDER BY c1 ASC, c2 ASC -- optimizer can use idx1
explain select * from tORDER BY c1 DESC, c2 DESC -- optimizer can use idx4
explain select * from tORDER BY c1 ASC, c2 DESC -- optimizer can use idx2
explain select * from tORDER BY c1 DESC, c2 ASC -- optimizer can use idx3
CREATE TABLE `t_2` (
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
`id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx1` (`c1` ASC ,`c2` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
下面还是能支持索引的
explain select * from t_2 ORDER BY c1 ASC, c2 ASC
MySQL 8.0.13 以及更高版本支持函数索引(functional key parts),也就是将表达式的值作为索引的内容,而不是列值或列值前缀。 将函数作为索引键可以用于索引那些没有在表中直接存储的内容。
下面创建一个包含函数索引的表
CREATE TABLE `t1` (
`id` int(11) NOT NULL,
`col1` int(11) DEFAULT NULL,
`col2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `func_index` ((abs(`col1`))),
KEY `idx1` (((`col1` + `col2`))),
KEY `idx2` (((`col1` + `col2`)),((`col1` - `col2`)),`col1`),
KEY `functional_index` (((`col1` * 40)) DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of t1
-- ----------------------------
INSERT INTO `t1` VALUES ('1', '1', '1');
INSERT INTO `t1` VALUES ('2', '2', '2');
INSERT INTO `t1` VALUES ('3', '3', '3');
## 能用索引functional_index
EXPLAIN SELECT * from t1 where col1*40 =1
## 不能用索引
EXPLAIN SELECT * from t1 where col1 =1
CREATE TABLE tbl (
id int(11) PRIMARY key ,
col1 LONGTEXT,
INDEX idx1 ((SUBSTRING(col1, 1, 10)))
);
## 不能用索引
EXPLAIN SELECT * FROM tbl WHERE SUBSTRING(col1, 1, 9) = '123456789';
## 能用索引idx1
EXPLAIN SELECT * FROM tbl WHERE SUBSTRING(col1, 1, 10) = '1234567890';
因为在5.7中自增列是写到了内存中而没有更新binlog,如果出现故障或者重启自增列是扫描当前表的最大值
这样如果是已经删除的id,就会重新出现,但是8.0不会
比如我们删除最大id是100的记录,重启5.7版本服务器,则下次插入的还是100,但是MySQL8.0则是101
在MySQL8.0中值是2,锁是交叉生成的,主从复制是基于行进行复制的
1是连续模式,主从是基于语句复制的,
由1变成2,提高了并发,在MySQL主从复制中,提高了性能
mysql> show variables like '%Innodb_autoinc%';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_autoinc_lock_mode | 2 |
+--------------------------+-------+
1 row in set
MySQL为了死锁检测增加了一个动态的变量 innodb_deadlock_detect
mysql> show variables like 'innodb_deadlock_detect';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_deadlock_detect | ON |
+------------------------+-------+
1 row in set
也可以关闭,但是建议不要关闭
set global innodb_deadlock_detect =off;
##死锁超时时间5秒
set global innodb_lock_wait_timeout=5;
## 行锁,独占锁
select * from tableXX where id =1 for update ;
## 行锁,共享锁
select * from tableXX where id =1 for share ;
## 行锁,如果当前数据被锁定,则直接返回错误
select * from tableXX where id =1 for update NOWAIT ;
## 针对多个数据,如果有数据被锁定,则不返回被锁定的数据,即跳过被锁定的数据
select * from tableXX where SKIP LOCKED ;
从MySQL 8.0.14开始,InnoDB支持并行聚集索引读取,这可以提高 CHECK TABLE性能。此功能不适用于二级索引扫描
##1- limit 限制几个
select * from user limit 55
select * from user limit 55 ,5 从第五个开始,限制55个
SELECT u.id from sys_user u where u.id NOT IN (1,20)
SELECT u.id from sys_user u where u.id NOT BETWEEN 1 AND 5
SELECT u.user_name from sys_user u where u.user_name LIKE '%hcg%'
SELECT u.user_name from sys_user u where u.user_name LIKE 'hcg%'
SELECT u.user_name from sys_user u where u.user_name LIKE '%hcg'
SELECT u.user_name from sys_user u where u.user_name LIKE '_hcg'
但是不能过度使用通配符,如果有需要放在排序的最后面,因为它的查询速度非常慢
// 查询含文本hcg的所有值
SELECT u.user_name from sys_user u where u.user_name REGEXP 'hcg'
//. 能匹配任意一个字符
SELECT u.user_name from sys_user u where u.user_name REGEXP '.hcg'
//mysql 的正则表达式匹配不区分大小写,即无论是什么匹配的既有大写也有小写
//解决方案是 加一个关键字: BINARY 后面跟的是大写匹配大写,如果是小写匹配小写
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY 'U'
SELECT u.user_name from sys_user u where u.user_name REGEXP 'U'
// | 是OR的意思即或 同时如果前面有BINARY 关键字 匹配的是里面的值,比如下面匹配的都是
//小写的u 和大写H
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY 'u|H'
//[123]里面可以放一些字符,表示随便匹配其中的一个,事实上他是[1|2|3]的缩写
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY 'r[123]'
//[X-X]表示一个集合 [1-3]相当于[1|2|3]
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY '[0-9]'
//这里因为.能匹配任意一个字符,所以这里想要匹配带.的要用转译符 //
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY '.'
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY '//.'
//那么问题来了,怎么匹配/ 这里用三个/就好了
SELECT u.user_name from sys_user u where u.user_name REGEXP BINARY '///'
//{n}最靠近它左边的值要求被匹配的次数
//{n,}不少于指定数目的匹配
//{n,m}匹配数目的范围,m不超过255
//{*}0个或者多个匹配
//{+}1个或者多个匹配
//{?}0个或者1个
//如果想要以一个数字开始,而上面的所有都没有这个属性,都是在任意位置都可以,为了解决这个问题,定位符出现了,它可以指定位置
^ 文本的开始
$ 文本的结尾
[[:<:]]词的开始
[[:<:]]词的结尾
// ^有两种用法,一个是限定的开始,一个是否定一个集合
[^a]表示“匹配除了a的任意字符”。
[^a-zA-Z0-9]表示“找到一个非字母也非数字的字符”
//同时正则表达式的书写其实不用数据库,因为REGEXP的查询总是返回0或者1
SELECT 'hello' REGEXP '[0-9]'
// CONCAT 函数是拼接函数,需要被拼接的列用逗号隔开即可
SELECT CONCAT(u.user_name ,u.email ) FROM sys_user u WHERE u.id < 10
//还可以在中间或者任意位置放置你想要的连接符
SELECT CONCAT(u.user_name , '============',u.email ) FROM sys_user u WHERE u.id < 10
//RTrim() LTrim()去掉值右边、左边的空格
SELECT CONCAT( RTRIM (u.user_name) , '============', LTRIM(u.email) ) FROM sys_user u WHERE u.id < 10
// *—+/ 这些算数运算符也是可以直接用的
SELECT (u.`status` * u.role_id) AS HH FROM sys_user u WHERE u.id <10