MySQL其他优化

102 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,[点击查看活动详情]

1.exists和in的区别

我们都知道,exists和in一样都是存在的意思,但是这两个有什么区别你知道吗?

有如下两个SQL,执行语义一样:

explain select * from student s where classId in (select monitor from class) and s.id < 6000000执行计划如下:

image.png

查询时间如下,由于数据量太多,直接卡死,所以我限制了100w条数据(id是500w开始): image.png

explain select * from student s where exists (select monitor from class c where s.classId = c.id) and s.id < 6000000执行计划如下:

image.png

查询时间如下:

image.png

student是大表,class是小表,可以看到驱动表较大的时候使用in的扫描记录数较少,使用exists的扫描将近全部数据,同时我们也可以根据执行时间看出在驱动表大的时候使用in效率较高。相反如果驱动表数据较少使用exists效率较高,因为扫描次数由外层循环决定,而决定哪个表是外层in和exists是相反的,如果外表的数据小于内表且使用的是in,MySQL优化器会将in转变为exists。

2.count(*) 和 count(1) 以及 count(field)的区别

class原本有10w数据,现在查询一下address字段

image.png

现在我新增一条,只有除了逐渐其他都为空的记录:

insert into class values();

再次查询count(address)发现还是10w: image.png

count(id)查询,如下图:

image.png

count(1)查询:

image.png

结论:使用count(field)查询具体字段,如果为空则不统计,如果统计记录数应该使用count(*),或者count(1)

那么count(*),count(1)有区别吗? 看下他们两个的执行计划如下图:

image.png

一模一样,没有区别,但是如果是在存储引擎不同的情况下会有所差异,因为在MyISAM存储引擎下表记录数在meta元数据里有常量存储,所以不需要扫描表时间复杂度o(1),而InnoDB引擎需要扫描表所以速度会慢点,但是会使用到索引,如上面的就使用到主键索引,如果class表有二级索引会优先使用二级索引,有多个则会选择key_len最小的使用,其实也好理解,主键索引包含主键和所有字段数据,数据量较大,而二级索引只保留了主键和索引字段,统计的时候占用的内存较小。

3.select(*)的危害

都知道非必要不要查询全部字段,但是你知道为什么吗?

  1. 查询的字段越多查询时占用的内存资源越多,返回的数据也越多。

  2. 查询全部字段无法触发索引覆盖。

  3. join连接查询时,如果查询全部字段将会严重影响扫描次数,在join连接的文章里讲到过,使用BNLJ算法每次批量获取记录的条数和join buffer以及数据记录的大小有直接关系(每条记录占用内存的大小和字段多少有直接关系)。

  4. 在MySQL解析SQL的时候会将查询的列全部转化为全限定列名,也会消耗资源。