MySQL之查询优化方式(笔记)

时间:2023-12-17 13:27:56

1.COUNT()

  对COUNT的优化可以通过下面的SQL实现

  

mysql> select count(gnp<10000 or null) as  '<<<<',count(gnp>=10000 or null) as '>>>>' from country;
+------+------+
| <<<< | >>>> |
+------+------+
| 152 | 87 |
+------+------+
1 row in set (0.00 sec)

count(*)与count(cloumn)返回的值可能不一样,因为如果存在空的情况,count(*)也会计算在内

2.SUM()

对SUM()的优化需要通过建立索引实现

  

mysql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | MUL | | |
| CountryCode | char(3) | NO | | | |
| District | char(20) | NO | | | |
| Population | int(11) | NO | | 0 | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.03 sec) mysql> create index popu_index on city(population);
Query OK, 4079 rows affected (0.05 sec)
Records: 4079 Duplicates: 0 Warnings: 0 mysql> explain select SUM(population) as sum from city;
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | city | index | NULL | popu_index | 4 | NULL | 4079 | Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
1 row in set (0.00 sec) mysql> select SUM(population) as sum from city;
+------------+
| sum |
+------------+
| 1429559884 |
+------------+
1 row in set (0.00 sec)

 3.子查询的优化

  对于子查询的优化可以通过on实现

 

mysql> desc city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | MUL | | |
| CountryCode | char(3) | NO | | | |
| District | char(20) | NO | | | |
| Population | int(11) | NO | MUL | 0 | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set (0.01 sec) mysql> desc country;;
+----------------+---------------------------------------------------------------------------------------+------+-----+---------+--
| Field | Type | Null | Key | Default | E
+----------------+---------------------------------------------------------------------------------------+------+-----+---------+--
| Code | char(3) | NO | PRI | |
| Name | char(52) | NO | | |
| Continent | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO | | Asia |
| Region | char(26) | NO | | |
| SurfaceArea | float(10,2) | NO | | 0.00 |
| IndepYear | smallint(6) | YES | | NULL |
| Population | int(11) | NO | | 0 |
| LifeExpectancy | float(3,1) | YES | | NULL |
| GNP | float(10,2) | YES | | NULL |
| GNPOld | float(10,2) | YES | | NULL |
| LocalName | char(45) | NO | | |
| GovernmentForm | char(45) | NO | | |
| HeadOfState | char(60) | YES | | NULL |
| Capital | int(11) | YES | | NULL |
| Code2 | char(2) | NO | | |
+----------------+---------------------------------------------------------------------------------------+------+-----+---------+--
15 rows in set (0.01 sec) ERROR:
No query specified mysql> explain select t.* from city t where t.countrycode in( select code from country);
+----+-------------+---------+--------+---------------+---------+---------+---------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+--------+---------------+---------+---------+---------------------+------+-------------+
| 1 | SIMPLE | t | ALL | NULL | NULL | NULL | NULL | 4079 | NULL |
| 1 | SIMPLE | country | eq_ref | PRIMARY | PRIMARY | 3 | world.t.CountryCode | 1 | Using index |
+----+-------------+---------+--------+---------------+---------+---------+---------------------+------+-------------+
2 rows in set (0.04 sec) mysql> explain select t.* from city t join country t1 on t.countrycode = t1.code;
+----+-------------+-------+--------+---------------+---------+---------+---------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+------+-------------+
| 1 | SIMPLE | t | ALL | NULL | NULL | NULL | NULL | 4079 | NULL |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 3 | world.t.CountryCode | 1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+------+-------------+
2 rows in set (0.00 sec)

  这样的优化可能返回重复的行,去重需要使用关键字distinct

4.Group  by优化

正常执行情况下如下

  

mysql> explain select t.* from city t join country t1 on t.countrycode = t1.code group by t.id;
+----+-------------+-------+--------+---------------+---------+---------+---------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+------+---------------------------------+
| 1 | SIMPLE | t | ALL | NULL | NULL | NULL | NULL | 4079 | Using temporary; Using filesort |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 3 | world.t.CountryCode | 1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------------+------+---------------------------------+
2 rows in set (0.02 sec)

  可以看到了使用临时表还有文件排序的方式来实现,那么我们应该怎么减少IO已经对资源的消耗呢,通过下面方式可以看出

mysql> explain select t.* from city t join (select code from country) t1 on t.countrycode = t1.code;
+----+-------------+------------+-------+---------------+-------------+---------+---------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+-------------+---------+---------------------+------+-------------+
| 1 | PRIMARY | t | ALL | NULL | NULL | NULL | NULL | 4079 | NULL |
| 1 | PRIMARY | <derived2> | ref | <auto_key0> | <auto_key0> | 3 | world.t.CountryCode | 10 | Using index |
| 2 | DERIVED | country | index | NULL | PRIMARY | 3 | NULL | 239 | Using index |
+----+-------------+------------+-------+---------------+-------------+---------+---------------------+------+-------------+
3 rows in set (0.00 sec)

  这样就可以避免了文件排序还有使用该临时表的情况。

5.limit操作方式的优化

  使用之前:

mysql> explain select * from city order by name limit  100,10;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4079 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)

  可以看到使用了文件排序,这样会造成性能上的低下。

  优化方式:可以通过主键或者是含有索引的列进行order by  操作;

  

mysql> create index name_index  on city(name);

mysql> explain select name from city order by name limit  100,10;
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | city | index | NULL | name_index | 35 | NULL | 110 | Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
1 row in set (0.00 sec)

  可以发现只扫描了35行而且使用了索引但是效率增加了很多。