Mysql子查询及优化

子查询:当一个查询是另一个查询的子部分时,称之为子查询。

create table t1(k1 int PRIMARY key,c1 int);
create table t2(k2 int PRIMARY key,c2 int);
insert into t2 values(1,10),(2,2),(3,30);
mysql> SELECT t1.c1, (SELECT t2.c2 FROM t2) FROM t1, t2;

Empty set (0.00 sec)


mysql> insert into t1 values (1,1), (2,2), (3,3);

Query OK, 3 rows affected (0.01 sec)

Records: 3  Duplicates: 0  Warnings: 0


mysql> SELECT t1.c1, (SELECT t2.c2 FROM t2) FROM t1, t2;

ERROR 1242 (21000): Subquery returns more than 1 row


mysql> DELETE FROM T2;

Query OK, 3 rows affected (0.01 sec)


mysql> SELECT t1.c1, (SELECT t2.c2 FROM t2) FROM t1, t2;

Empty set (0.00 sec)
mysql> insert into t2 values (1,10), (2,2), (3,30);

Query OK, 3 rows affected (0.01 sec)

Records: 3  Duplicates: 0  Warnings: 0

SELECT t1.c1, (SELECT t2.c2 FROM t2 WHERE K2=1) FROM t1, t2;

SELECT t1.c1, (SELECT t2.c2 FROM t2 WHERE c2=1) FROM t1, t2;

mysql> SELECT t1.c1, (SELECT t2.c2 FROM t2 WHERE c2>1) FROM t1, t2;

ERROR 1242 (21000): Subquery returns more than 1 row
SELECT t1.c1, (SELECT t2.c2 FROM t2 WHERE c2=10) FROM t1, t2;
mysql> INSERT INTO t2 VALUES (4,10);

Query OK, 1 row affected (0.00 sec)
mysql> SELECT t1.c1, (SELECT t2.c2 FROM t2 WHERE c2=10) FROM t1, t2;

ERROR 1242 (21000): Subquery returns more than 1 row

from子句的位置:
SELECT * FROM t1, (SELECT * FROM t2) as A_t2;

where子句位置:
SELECT * FROM t1 WHERE k1 IN (SELECT k2 FROM t2);
SELECT * FROM t1 WHERE k1 >=ANY (SELECT k2 FROM t2);

SELECT * FROM t1 WHERE k1 <=SOME (SELECT k2 FROM t2);

SELECT * FROM t1 WHERE k1 <=ANY (SELECT k2 FROM t2);

SELECT * FROM t1 WHERE NOT EXISTS (SELECT k2 FROM t2 WHERE k2=100);

子查询分类:
1.从对象间的关系看:相关子查询,非相关子查询
2.从特定谓词看:(1)[NOT]IN/ALL/ANY/SOME子查询(2)[NOT]exists子查询(3)其他子查询
3.从语句的构成复杂程度看:SPJ子查询,GROUPBY子查询,其他子查询
4.从结果的角度看:(1)标量子查询(2)单行单列子查询(3)多行单列子查询(4)表子查询
如何实现子查询优化:
1.子查询合并
在某些条件下,多个子查询能够合并成一个子查询,这样可以把多次表扫描、多次连接减少为单次表扫描和单次连接。

select * from t1 where k1<10 and(
EXISTS (select k2 from t2 where t2.k2<5 and t2.c2=1) OR
EXISTS (select k2 from t2 where t2.k2<5 and t2.c2=2));

可优化为:

select * from t1 where k1<10 and(
EXISTS (select k2 from t2 where t2.k2<5 and (t2.c2=1 or t2.c2=2)));

2.子查询展开
把一些子查询置于外层的父查询中,作为连接关系与外层父查询并列,实质是把某些子查询重写为等价的多表连接操作。
展开的条件:
1.如果子查询中出现了聚集、GROUPBY、DISTINCT子句,则子查询只能单独求解,不可以拉到外层。
2.如果子查询只是一个简单格式的(SPJ格式)查询语句,则可以上拉子查询到外层,提高查询效率。

select * from t1,(select * from t2 where t2.k2>2) v_t2
where t1.k1<10 and v_t2.k2<20

可优化为:

select * from t1,t2
where t1.k1<10 and t2.k2<20 and t2.k2>2

3.聚集子查询消除
select * from t1 where t1.k1>(select avg(t2.k2) from t2)

 

### 如何优化 MySQL 子查询性能 #### 将子查询转换为 JOIN MySQL 执行子查询时,通常先执行子查询部分再将结果传递给外部查询。对于大表而言,这可能导致大量临时表操作并影响性能。通过重写子查询为 `JOIN` 可以使 MySQL 更好地利用索引,并减少不必要的临时表创建,从而提升查询速度[^1]。 例如,考虑如下两个表格: - 表A (id, name) - 表B (aid, info) 原始带有子查询的 SQL 语句可能像这样: ```sql SELECT * FROM A WHERE id IN (SELECT aid FROM B); ``` 将其改为使用 `JOIN` 的形式后变为: ```sql SELECT DISTINCT a.* FROM A AS a INNER JOIN B AS b ON a.id = b.aid; ``` 这种变化不仅提高了可读性还增强了性能表现。 #### 避免不必要的临时表创建 当遇到提示 "Using temporary" 说明 MySQL 正在创建一个临时表来完成当前查询请求。这类情况往往意味着存在潜在的低效之处,应该优先尝试用合适的索引来改进查询逻辑而不是依赖于临时存储结构[^3]。 #### 利用查询缓存机制 许多 MySQL 实例默认启用了查询缓存功能,它能够显著加快重复查询的速度。然而需要注意的是并非所有的查询都会触发此特性;特别是那些含有不确定因素(如时间戳函数)或涉及多行更新的操作可能会绕过缓存。因此,在编写应用程序代码期间应当留意这一点,尽可能设计出有利于充分利用这一特性的查询方式[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值