64-MySQL其它查询优化策略

一、 EXISTS 和 IN

不太理解哪种情况下应该使用 EXISTS,哪种情况应该用 IN。选择的标准是看能否使用表的索引吗?
索引是个前提,其实选择与否还是要看表的大小。可以将选择的标准理解为小表驱动大表。这种方式下效率是最高的

1.1、EXISTS

  • SQL
SELECT *
FROM A
WHERE EXISTS(SELECT cc FROM B WHERE A.cc = B.cc);
  • 当 A 小于 B 时,用 EXISTS 。因为 EXISTS 的实现,相当于外表循环,实现的逻辑类似于
for i in A
    for j in B
        if i.cc == j.cc
          then . . .

1.2、IN

  • SQL
SELECT *
FROM A
WHERE cc IN (SELECT cc FROM B);
  • 当 B 小于 A 时用 IN,因为实现的逻辑类似于
for i in B
    for j in A
        if i.cc == j.cc
          then . . .

二、 COUNT(*)与COUNT(具体字段)效率

在 MySQL 中统计数据表的行数,可以使用三种方式: SELECT COUNT(*)SELECT COUNT(1)SELECT COUNT(具体字段) ,使用这三者之间的查询效率是怎样的?如果你要统计的是某个字段的非空数据行数

2.1、SELECT COUNT(*)与SELECT COUNT(1)比较

SELECT COUNT(*)SELECT COUNT(1) 都是对所有结果进行COUNTCOUNT(*)COUNT(1) 本质上并没有区别。如果有 WHERE 子句,则是对所有符合筛选条件的数据行进行统计;如果没有 WHERE 子句,则是对数据表的数据行数进行统计

2.2、不同存储引擎

  • MyISAM存储引擎

MyISAM存储引擎统计数据表的行数只需要O(1)的复杂度,这是因为每张 MyISAM 的数据表都有一个 meta 信息存储了 row_count值,而一致性则由表级锁来保证

  • InnoDB存储引擎

InnoDB存储引擎因为 InnoDB 支持事务,采用行级锁MVCC机制,所以无法想MyISAM一样,维护一个row_count变量,因此需要采用全表扫描,是O(n)的复杂度,进行循环 + 计数的方式来完成统计

2.3、COUNT(具体字段)

InnoDB引擎中,如果采用COUNT(具体字段)来统计数据行数,要尽量采用二级索引。因为主键采用的索引是聚簇索引聚簇索引包含的信息多,明显会大于二级索引。对于COUNT(*)COUNT(1) 来说,它们不需要查找具体的行,只是统计行数,系统会自动采用占用空间更小的二级索引来进行统计。如果有多个二级索引,会使用key_len小的二级索引进行扫描。当没有二级索引的时候,才会采用主键索引来进行统计

三、于SELECT(*)

在表查询中,建议明确字段,不要使用*作为查询的字段列表,推荐使用SELECT <字段列表> 查询

  • 原因1: MySQL 在解析的过程中,会通过 查询数据字典 将"*"按序转换成所有列名,这会大大的耗费资源和时间。
  • 原因2:无法使用 覆盖索引

四、 LIMIT 1 对优化的影响

针对的是会扫描全表的 SQL 语句,如果你可以确定结果集只有一条,那么加上 LIMIT 1 的时候,当找到一条结果的时候就不会继续扫描了,这样会加快查询速度。
如果数据表已经对字段建立了唯一索引,那么可以通过索引进行查询,不会全表扫描的话,就不需要加
LIMIT 1 了。

五、多使用COMMIT

只要有可能,在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放
的资源而减少

  • COMMIT 所释放的资源:
    • 回滚段上用于恢复数据的信息
    • 被程序语句获得的锁
    • redo / undo log buffer 中的空间
    • 管理上述 3 种资源中的内部花费

你可能感兴趣的:(64-MySQL其它查询优化策略)