继续这一系列,上篇的简单查询优化并没讲完,第二点还有查询注意点以及多表查询优化呢!!
/*
补充说明(往后有博友反馈的话,会继续补充。)
*/
一、2017-7-19:
关于“超大型数据尽可能尽力不要写子查询,使用连接(JOIN)去替换它”。
关于这一类的总结,我们要认真去考量,这里并不是说一定。
1)因为在大型的数据处理中,子查询是非常常见的,特别是在查询出来的数据需要进一步处理的情况,
无论是可读性还是效率上,这时候的子查都是更优。
2)然而在一些特定的场景,可以直接从数据库读取就可以的,
比如一个表(A表 a,b,c字段,需要内部数据交集)join自己的效率必然比放一个子查在where中快得多。
可参见我给的例子中的拉黑表,好友表(双方互相喜欢才是好友的表),在查自己的好友列表的时候,或者拉黑列表中。
基本连接方法(内连接、外连接以及交叉连接)
- 内连接:用比较运算符根据每个表共有的列的值匹配两个表中的行(=或>、<)
- 外连接之左连接
- 外连接之右连接
- 外连接之全外连接
- 交叉连接
超大型数据尽可能尽力不要写子查询,使用连接(JOIN)去替换它(基础讲完,讲优化)
(3)使用联合(UNION)来代替手动创建的临时表
建立索引(下一篇将详讲)
//意思是:检索商品分类表和商品表“分类描述”相同的行
select
d.Good_ID ,
d.Classify_ID,
d.Good_Name
from
Commodity_list d
inner join commodity_classification c
on d.Classify_Description=c.Good_kinds_Name
得到的满足某一条件的是A,B内部的数据;正因为得到的是内部共有数据,所以连接方式称为内连接。
//意思:查得商品分类表的所有数据,以及满足条件的商品详情表的数据
select
*
from
commodity_classification c
left join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
//就是只查分类表数据,但是减去跟商品详情表有联系的数据。
select
*
from
commodity_classification c
left join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
where d.Classify_Description is null
//意思是查得商品详情表的所有数据以及在分类描述相同条件下的商品分类表数据
select
*
from
commodity_classification c
right join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
//意思:查询商品详情表的所有数据,但是要减去和商品分类表有联系的数据
select
*
from
commodity_classification c
right join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
where c.Good_kinds_Name is null
select
*
from
commodity_classification c
left join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
union
select
*
from
commodity_classification c
right join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
select
*
from
commodity_classification c
left join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
where d.Classify_Description is null
union
select
*
from
commodity_classification c
right join commodity_list d
on d.Classify_Description=c.Good_kinds_Name
where c.Good_kinds_Name is null
交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。 FROM 子句中的表或视图可通过内联接或完整外部联接按任意顺序指定;但是,用左或右向外联接指定表或视图时,表或视图的顺序很重要。有关使用左或右向外联接排列表的更多信息,请参见使用外联接。
//可以看到
select
*
from
commodity_classification c
cross join commodity_list d
select
*
from
commodity_classification c
cross join commodity_list d
where c.Good_kinds_Name=d.Classify_Description
select
*
from
commodity_classification c,
commodity_list d
where c.Good_kinds_Name=d.Classify_Description
1)一般cross join后面加上where条件,但是用cross join+on也是被解释为cross join+where;
2)一般内连接都需要加上on限定条件,如上面场景一;如果不加会被解释为交叉连接;
3)如果连接表格使用的是逗号,会被解释为交叉连接;
在一个表表达中可以调用另一个表表达式,这个被调用的表表达式叫做子查询(subquery),也称作子选择(subselect)或内嵌选择(inner select)。子查询的结果传递给调用它的表表达式继续处理。
//很简单的意思:就是根据商品id查商品详情表,然后用查出来的ID去查商品分类表。
select
*
from
commodity_classification c
where Classify_ID IN(select Classify_ID from commodity_list where Good_ID='tb10025584930')
select
*
from
commodity_classification c
left join commodity_list d on d.Classify_ID=c.Classify_ID
where d.Good_ID='tb10025584930'
union查询,它可以把需要使用临时表的两条或更多的select查询合并的一个查询中(即把两次或多次查询结果合并起来。)。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用UNION作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要想同。
两次查询的列数必须一致
列的类型可以不一样,但推荐查询的每一列,想对应的类型以一样
多次sql语句取出的列名可以不一致,此时以第一个sql语句的列名为准。
如果不同的语句中取出的行,有完全相同(这里表示的是每个列的值都相同),那么union会将相同的行合并,最终只保留一行。也可以这样理解,union会去掉重复的行。
如果不想去掉重复的行,可以使用union all。
如果子句中有order by,limit,需用括号()包起来。推荐放到所有子句之后,即对最终合并的结果来排序或筛选。
select
Classify_ID,Good_kinds_Name
from
commodity_classification
union
select
Classify_ID,Classify_Description
from
commodity_list
//加条件
(select
Classify_ID,Good_kinds_Name
from
commodity_classification
order by Classify_ID)
union
(select
Classify_ID,Classify_Description
from
commodity_list
order by Good_ID)
//经常操作的含义:列出所有在中国和美国的不同的雇员名
SELECT E_Name FROM Employees_China
UNION
SELECT E_Name FROM Employees_USA
默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。
select
Classify_ID,Good_kinds_Name
from
commodity_classification
union ALL
select
Classify_ID,Classify_Description
from
commodity_list
首先应考虑在 where 及 order by 涉及的列上建立索引。(索引的注意点在下篇将详讲)
否则将导致引擎放弃使用索引而进行全表扫描,如:
//最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.
select id from t where num is null
备注、描述、评论之类的可以设置为 NULL,其他最好不要使用NULL。
不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。
select id from t where num = 0
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
//用这个去替换
select num from a where exists(select 1 from b where num=a.num)
select id from t where name like ‘%abc%’
若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
如果你的应用程序有很多 JOIN 查询,你应该确认两个表中Join的字段是被建过索引的。这样,MySQL内部会启动为你优化Join的SQL语句的机制。
而且,这些被用来Join的字段,应该是相同的类型的。例如:如果你要把 DECIMAL 字段和一个 INT 字段Join在一起,MySQL就无法使用它们的索引。对于那些STRING类型,还需要有相同的字符集才行。(两个表的字符集有可能不一样)
//在state中查找company
SELECT company_name FROM users
LEFT JOIN companies ON (users.state = companies.state)
WHERE users.id = $user_id"
//两个 state 字段应该是被建过索引的,而且应该是相当的类型,相同的字符集
下一篇就是我们的索引详讲了,很难又很重要关键,性能的关键点,我会继续出这个系列文章,分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!