MySQL学习记录

MySQL - 访问方法

2019-12-15  本文已影响0人  sunyelw

前言

最近在学MySQL,决定记录一下,能写多少写多少,不定时更新,加油。

正文

分几个部分来吧,大致如下:

本文为第四部分 访问方法与连接


访问方法

访问方法大致可以分六种,那么我们怎么查看我们的SQL语句到底以上面方式执行的呢?

MySQL提供了一个explain语句,这里我们只需关注下输出列中的 type字段值就好。

建一张表来测试,下面出现的SQL都是基于此表

CREATE TABLE `single_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key1` varchar(100) DEFAULT NULL,
  `key2` int(11) DEFAULT NULL,
  `key3` varchar(100) DEFAULT NULL,
  `key_part1` varchar(100) DEFAULT NULL,
  `key_part2` varchar(100) DEFAULT NULL,
  `key_part3` varchar(100) DEFAULT NULL,
  `common_field` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_key2` (`key2`),
  KEY `idx_key1` (`key1`),
  KEY `idx_key3` (`key3`),
  KEY `idx_key_part` (`key_part1`,`key_part2`,`key_part3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

下面一种一种来看下。

一、conf

主键列或唯一二级索引的不为NULL的等值查询

只有精确匹配到一条记录, 才是 conf 访问方式

下面看两个例子

mysql>
mysql> explain select * from single_table where id = 100;
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table        | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | single_table | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql>
mysql> explain select * from single_table where key2 = 100;
+----+-------------+--------------+------------+-------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table        | partitions | type  | possible_keys | key      | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------+------------+-------+---------------+----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | single_table | NULL       | const | idx_key2      | idx_key2 | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+-------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

二、ref

二级索引列与常数等值比较

有一种特殊情况:如果二级索引列有多列,那么不一定非要每列都等值匹配,只需要靠左开始匹配就有可能是ref方式访问

// 靠左
mysql>
mysql> explain select * from single_table where key_part1 = 'one_part1';
+----+-------------+--------------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
| id | select_type | table        | partitions | type | possible_keys | key          | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | single_table | NULL       | ref  | idx_key_part  | idx_key_part | 303     | const |    1 |   100.00 | NULL  |
+----+-------------+--------------+------------+------+---------------+--------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

// 不靠左
mysql>
mysql> explain select * from single_table where key_part2 = 'one_part1';
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | single_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1000 |    10.00 | Using where |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

三、ref_or_null

这个很好理解,就是在ref的基础上加一个关于 IS NULL 的条件

mysql>
mysql> explain select * from single_table where key_part1 = 'one_part1' or key_part1 is null;
+----+-------------+--------------+------------+-------------+---------------+--------------+---------+-------+------+----------+-----------------------+
| id | select_type | table        | partitions | type        | possible_keys | key          | key_len | ref   | rows | filtered | Extra
  |
+----+-------------+--------------+------------+-------------+---------------+--------------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | single_table | NULL       | ref_or_null | idx_key_part  | idx_key_part | 303     | const |    2 |   100.00 | Using index condition |
+----+-------------+--------------+------------+-------------+---------------+--------------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (1.55 sec)

形成了 两个连续的记录区间

四、range

聚簇索引或二级索引的 区间查询
mysql>
mysql> explain select * from single_table where id > 10;
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table        | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | single_table | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL | 1000 |   100.00 | Using where |
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql>
mysql> explain select * from single_table where key2 < 10;
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table        | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | single_table | NULL       | range | idx_key2      | idx_key2 | 5       | NULL |   10 |   100.00 | Using index condition |
+----+-------------+--------------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

再看一个例子

mysql>
mysql> explain select * from single_table where key2 > 10;
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | single_table | NULL       | ALL  | idx_key2      | NULL | NULL    | NULL | 1000 |    98.90 | Using where |
+----+-------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

这里是 ALL,虽然还没讲到,但猜都猜到是全表扫描了,为什么这里会全表扫描而不是range方式呢?

五、index

查询列与条件列在索引列中

简单粗暴:

mysql>
mysql> explain select key_part1, key_part3 from single_table where key_part2 = 'one_part1';
+----+-------------+--------------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+ 
| id | select_type | table        | partitions | type  | possible_keys | key          | key_len | ref  | rows | filtered | Extra                    | 
+----+-------------+--------------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+ 
|  1 | SIMPLE      | single_table | NULL       | index | NULL          | idx_key_part | 909     | NULL | 1000 |    10.00 | Using where; Using index | 
+----+-------------+--------------+------------+-------+---------------+--------------+---------+------+------+----------+--------------------------+ 
1 row in set, 1 warning (0.00 sec)

为什么一定是二级索引?

六、all

最后一个就是 全表扫描 了,直接扫描聚簇索引,是最耗时的那种访问方式。

这里就简单介绍下这几种访问方法,下面看看MySQL中的连接。

连接

平时查询涉及多张表的情况不要太多,这些多张表之间的查询就被称为连接查询

连接的本质就是把各个连接表中的记录都取出来依次匹配的组合加入结果集

一、笛卡尔积

连接还没有问世的时候,我们查询多张表怎么玩?

mysql>
mysql> select * from t1, t2;
+------+------+------+------+
| m1   | n1   | m2   | n2   |
+------+------+------+------+
|    1 | a    |    2 | b    |
|    2 | b    |    2 | b    |
|    1 | a    |    3 | c    |
|    2 | b    |    3 | c    |
|    1 | a    |    4 | d    |
|    2 | b    |    4 | d    |
+------+------+------+------+
6 rows in set (0.20 sec)

就是简单的把两张表的数据拼起来,在数学上有个名字叫做笛卡尔积

二、内外连接

为了满足各种使用情况,MySQL提供了连接.

他们把涉及查询的多张表进行了划分 - 驱动表(外表)与被驱动表(内表)

玩法就是,先查驱动表,拿到的记录再去被驱动表进行二次筛选

两张表以上,可以把一张表当做外表,其他表均为内表,再递归处理

内连接
SELECT * FROM t1 JOIN t2;

SELECT * FROM t1 INNER JOIN t2;

SELECT * FROM t1 CROSS JOIN t2;

SELECT * FROM t1, t2;
外连接
SELECT * FROM t1 LEFT [OUTER] JOIN t2 ON 连接条件 [WHERE 普通过滤条件];
SELECT * FROM t1 RIGHT [OUTER] JOIN t2 ON 连接条件 [WHERE 普通过滤条件];

外连接后必须接 on 子句
外连接后必须接 on 子句
外连接后必须接 on 子句

查询条件

一般情况下

对于外连接来说,由于驱动表中的记录即使在被驱动表中找不到符合ON子句条件的记录时也要将其加入到结果集

关于具体查询遵循如下规则:

涉及匹配是两个非常值得多读几遍的词~

下面是一些测试的例子

mysql> select * from t1 left join t2 on t2.m2 = 1;
+------+------+------+------+
| m1   | n1   | m2   | n2   |
+------+------+------+------+
|    1 | a    | NULL | NULL |
|    2 | b    | NULL | NULL |
+------+------+------+------+
2 rows in set (0.00 sec)
mysql> select * from t1 left join t2 on t2.m2 = 2;
+------+------+------+------+
| m1   | n1   | m2   | n2   |
+------+------+------+------+
|    1 | a    |    2 | b    |
|    2 | b    |    2 | b    |
+------+------+------+------+
2 rows in set (0.00 sec)
mysql> select * from t1 left join t2 on t1.m1 = 3;
+------+------+------+------+
| m1   | n1   | m2   | n2   |
+------+------+------+------+
|    1 | a    | NULL | NULL |
|    2 | b    | NULL | NULL |
+------+------+------+------+
2 rows in set (0.00 sec)
mysql> select * from t1 left join t2 on t1.m1 = 1;
+------+------+------+------+
| m1   | n1   | m2   | n2   |
+------+------+------+------+
|    1 | a    |    2 | b    |
|    1 | a    |    3 | c    |
|    1 | a    |    4 | d    |
|    2 | b    | NULL | NULL |
+------+------+------+------+
4 rows in set (0.00 sec)

连接查询

驱动表只访问一次,被驱动表访问次数取决于驱动表查询得到的记录条数

索引永远都是一种值得考虑的优化方案

上一篇下一篇

猜你喜欢

热点阅读