MySQLSQL语句EXISTS
MySQL中EXITS语句⽤于查明表中是否存在特定的⾏。普遍情况下EXITS与⼦查询⼀起使⽤,并返回与⼦查询返回的结果相等或匹配的⾏。如果⾏在表中存在,则返回true,否则返回false。在MySQL中使⽤EXISTS是低效的,因为EXISTS对查理表中的每⼀⾏都要重新运⾏。
1. 常⽤⽅式
通过例⼦,了解EXISTS返回的两种情况:TRUE(1), FLASE(0)
mysql> CREATE TABLE students(
id int PRIMARY KEY,
firstName varchar(255) DEFAULT NULL,
lastName varchar(255) DEFAULT NULL
);
INSERT INTO students(id,firstName,lastName)
VALUES(1,"Preet","Sanghavi"), (2,"Rich","John"), (3,"Veron","Brow"), (4,"Geo","Jos"), (5,"Hash","Shah"), (6,"Sachin","Parker"), (7,"David","Miller");
mysql> SELECT *FROM STUDENTS;
+----+-----------+----------+
| id | firstName | lastName |
+----+-----------+----------+
| 1 | Preet | Sanghavi |
| 2 | Rich | John |
| 3 | Veron | Brow |
| 4 | Geo | Jos |
| 5 | Hash | Shah |
| 6 | Sachin | Parker |
| 7 | David | Miller |
+----+-----------+----------+
7 rows in set (0.00 sec)
#查询id
mysql> SELECT EXISTS(SELECT * from students WHERE id=4) as RESULT;
+--------+
| RESULT |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
#查询不存在数据
mysql> SELECT EXISTS(SELECT * from students WHERE id=11) as RESULT;
+--------+
| RESULT |
+--------+
| 0 |
+--------+
1 row in set (0.00 sec)
#执⾏计划
mysql> EXPLAIN SELECT EXISTS(SELECT * from students WHERE id=4) as RESULT;
+----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+
| 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 2 | SUBQUERY | students | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index |
+----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+
2.往往容易误写⽤法
没有条件限制,扫描所有⾏,最终结果只返回⼀条TRUE(1),不管是不是NULL
mysql > SELECT EXISTS(SELECT * from students ) as RESULT;
+--------+
| RESULT |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
CREATE TABLE `course` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`stu_id` int NOT NULL,
`course_name` varchar(20) NOT NULL,
`st_couse` int NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_stu` (`stu_id`)
);
INSERT INTO course(stu_id,course_name,st_couse) VALUES(1,'语⽂',98),(2,'数学',89),(3,'英语',92);
mysql> SELECT st.* FROM students st
WHERE EXISTS (SELECT cs.stu_id FROM course cs );
+----+-----------+----------+------+
| id | firstName | lastName | age |
+----+-----------+----------+------+
| 1 | Preet | Sanghavi | NULL |
| 2 | Rich | John | NULL |
| 3 | Veron | Brow | NULL |
| 4 | Geo | Jos | NULL |
| 5 | Hash | Shah | NULL |
| 6 | Sachin | Parker | NULL |
| 7 | David | Miller | NULL |
+----+-----------+----------+------+
7 rows in set (0.00 sec)
mysql> SELECT st.* FROM students st
WHERE EXISTS (SELECT cs.stu_id FROM course cs WHERE cs.stu_id = st.id );
+----+-----------+----------+------+
| id | firstName | lastName | age |
+----+-----------+----------+------+
| 1 | Preet | Sanghavi | NULL |
| 2 | Rich | John | NULL |
| 3 | Veron | Brow | NULL |
+----+-----------+----------+------+
3 rows in set (0.00 sec)
注意:两次查询结果不⼀样,仔细对⽐上⾯两条 sql 语句,where 语句后⾯直接跟了exists ,并没有指定关联条件。这⾥EXISTS 只在乎WHERE⾥的数据能不能查出来,是否存在这样的记录。
其运⾏⽅式是先运⾏主查询⼀次,再去⼦查询⾥查询与其对应的结果 如果存在返回ture则输出,反之返回false则不输出,再根据主查询中的每⼀⾏去⼦查询⾥去查询。适合外查询表⼩,⼦查询表⼤的情况,毕竟要⼀⾏抽取进⾏匹配。
3.优化SQL语句
EXISTS是否可以改写进⾏优化,下⾯是改写成内连接⽅式:
mysql> SELECT st.* FROM students st INNER JOIN course cs ON cs.stu_id = st.id ;
执⾏计划对⽐:
Semi Join-LooseScan: 把数据基于索引进⾏分组,取每组数据进⾏匹配
EXPLAIN ANAYLZE实际执⾏:
从上诉对⽐中可以看出,在少量的数据中也存在明显的差异。
4. DDL中EXISTS
在DDL语句创建或删除中添加EXISTS,还是有很多好处的。
如果没有IF EXISTS,语句将失败,并出现⼀个错误,表明⽆法删除哪些不存在的表,并且不会进⾏任何更改。
exists的用法使⽤IF EXISTS时,对于不存在的表不会发⽣错误。该语句删除所有确实存在的已命名表,并为每个
不存在的表⽣成⼀个NOTE诊断。这些注释可以通过SHOW WARNINGS显⽰
如果在数据字典中有⼀个条⽬,但存储引擎没有管理表的特殊情况下,IF EXISTS也可以⽤于删除表。(例如,在从存储引擎中删除表之后,在删除数据字典条⽬之前,服务器异常退出。有⼀定的效果,但有时未必可⾏)
2021-11-24T11:33:54.885641Z 0 [ERROR] InnoDB: Cannot open datafile for read-only: './db9/t1.ibd' OS error: 71
2021-11-24T11:33:54.885645Z 0 [ERROR] InnoDB: Operating system error number 2 in a file operation.
2021-11-24T11:33:54.885648Z 0 [ERROR] InnoDB: The error means the system cannot find the path specified.
2021-11-24T11:33:54.885651Z 0 [ERROR] InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create the 2021-11-24T11:33:54.885656Z 0 [ERROR] InnoDB: Could not find a valid tablespace file for `db9/t1`. Please refer to sql/doc/refman/5.7/en/inno
EXIST删除操作:
mysql> DROP DATABASE db9;
ERROR 3679 (HY000): Schema directory './db9/' does not exist
mysql> DROP DATABASE IF EXISTS db9;
Query OK, 0 rows affected, 1 warning (0.03 sec)
EXIST 存储过程适⽤:
与EXISTS相对的是NOT EXISTS。使⽤NOT EXISTS后,若对应查询结果为空,则外层的WHERE⼦语句返回值为真值,否则返回假值。
在MySQL 8.0.19及以后版本中,也可以在⼦查询中使⽤NOT EXISTS或NOT EXISTS嵌套
4.总结
MySQL中EXISTS这些没有特殊的要求,主要考虑性能⽅⾯的问题。可以尽量⽤INNER JOIN。必须⽤到EXISTS时外查询表⼩,⼦查询表
⼤原则,可以有效减少总的循环次数来提升速度。
有时DDL中系统突然宕机,可以⽤IF EXISTS进⾏处理也能启动妙⽤。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论