mysql常见的优化需要注意的点

Posted 梦想远航

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql常见的优化需要注意的点相关的知识,希望对你有一定的参考价值。

1.explain分析
explian引用
索引基数
show indexes from table_name;
主键索引具有最好的基数

测试时

不走缓存
SELECT SQL_NO_CACHE id from test_null;

2.更好的索引类型
索引列尽可能的为not null ,避免在可空的列索引上进行二次扫描
要尽量避免 NULL ,关于索引列为Null的是否走索引,见测试 索引列的值为null查询时走索引的情况
3.使用unique index
与常规索引比不需要进行索引范围扫描
4.使用primary key
主键是uniquekey的一种特殊形式 。在innodb中,一个uniquekey是一个聚集索引(即对磁盘上数据排列的索引),当数据按照主键的次序进行检索时会极大改进性能
5.索引太多是有害的
例如,如果possible_keys 列表中有超过3个的索引,mysql优化器有太多信息而无法确定最好使用哪个索引,也就意味着有些是低效或者无用的索引
6.索引列使用最小可能的数据类型
比如在一个varchar(100)甚至更大的列上建立索引,一种改进方法是建立一个额外的列,并在包含较大的varchar(100)列的md5值的额外varchar(32)列上创建索引。
更好的方法是使用bigint来存储md5值的数字表示,数字索引更加高效
CONV(N,from_base,to_base)

mysql> select conv(\'a\',16,10);
+-----------------+
| conv(\'a\',16,10) |
+-----------------+
| 10              |
+-----------------+
mysql> select conv(substr(md5(\'abc\'),1,16),16,10);
+-------------------------------------+
| conv(substr(md5(\'abc\'),1,16),16,10) |
+-------------------------------------+
| 10376663631224000432                |
+-------------------------------------+

7.建立索引时
如果使用到多个列,定义多列索引
哪列的唯一性更高(基数大 show indexes from table_name),哪列优先放在多列索引的前面
覆盖索引是理性的索引 (explain 里extra的信息时using index)

覆盖索引包括所有需要的列,但是不需要读取单独的数据页,实际意味着不需要读取数据存储,只利用索引数据就可以检索到实际想要的查询的数据
在myisam表里,意味着只要读入索引就可以得到问题的记录,在innodb中 索引和数据是位于同一个文件中的,但仍然会高效些,因为只需要读入索引
优化部分索引的性能

select type from tb where sid=1

建立(sid,type)的索引 就是覆盖索引,比单独在sid,type上建索引要快


与其在长字符的列上定义索引,还不如只在左边的一小部分上建立索引

8.一些常见的不使用索引的情况
开始字符是通配符是,或者 在索引列上使用标量函数
like "%123",upper()

字符串类型的查询不加引号
9.覆盖索引的左前缀原则

10.更详细的分析
set profiling=1;
select * from table;
show profile;
show profile source ;

mysql> select * from test_null where mark like \'aaa9999%\';
+------+---------+
| id   | mark    |
+------+---------+
| 9999 | aaa9999 |
+------+---------+
1 row in set

mysql> show profile;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 5.5E-5   |
| checking permissions | 1.1E-5   |
| Opening tables       | 2E-5     |
| init                 | 2.4E-5   |
| System lock          | 7E-6     |
| optimizing           | 8E-6     |
| statistics           | 1.4E-5   |
| preparing            | 7E-6     |
| executing            | 2E-6     |
| Sending data         | 0.006271 |
| end                  | 5.7E-5   |
| query end            | 3.6E-5   |
| closing tables       | 5.1E-5   |
| freeing items        | 0.000348 |
| cleaning up          | 0.00011  |
+----------------------+----------+
mysql> show profile source;
+----------------------+----------+-----------------------+----------------------+-------------+
| Status               | Duration | Source_function       | Source_file          | Source_line |
+----------------------+----------+-----------------------+----------------------+-------------+
| starting             | 5.5E-5   | NULL                  | NULL                 | NULL        |
| checking permissions | 1.1E-5   | check_access          | sql_authorization.cc |         835 |
| Opening tables       | 2E-5     | open_tables           | sql_base.cc          |        5648 |
| init                 | 2.4E-5   | handle_query          | sql_select.cc        |         121 |
| System lock          | 7E-6     | mysql_lock_tables     | lock.cc              |         321 |
| optimizing           | 8E-6     | JOIN::optimize        | sql_optimizer.cc     |         151 |
| statistics           | 1.4E-5   | JOIN::optimize        | sql_optimizer.cc     |         367 |
| preparing            | 7E-6     | JOIN::optimize        | sql_optimizer.cc     |         475 |
| executing            | 2E-6     | JOIN::exec            | sql_executor.cc      |         119 |
| Sending data         | 0.006271 | JOIN::exec            | sql_executor.cc      |         195 |
| end                  | 5.7E-5   | handle_query          | sql_select.cc        |         199 |
| query end            | 3.6E-5   | mysql_execute_command | sql_parse.cc         |        4952 |
| closing tables       | 5.1E-5   | mysql_execute_command | sql_parse.cc         |        5004 |
| freeing items        | 0.000348 | mysql_parse           | sql_parse.cc         |        5578 |
| cleaning up          | 0.00011  | dispatch_command      | sql_parse.cc         |        1864 |
+----------------------+----------+-----------------------+----------------------+-------------+
mysql> set profiling=1;
Query OK, 0 rows affected

mysql> select * from a;
+----+-----+-------+
| id | uid | phone |
+----+-----+-------+
|  1 |   1 | 22    |
|  2 |   2 | 33    |
|  3 |   3 | 33    |
|  4 |   4 | 22    |
|  5 |   5 | 22    |
+----+-----+-------+
5 rows in set

mysql> select * from b;
+-------+
| phone |
+-------+
| 1111  |
| 2222  |
| 3333  |
| 4444  |
+-------+
4 rows in set

mysql> show profiles;
+----------+------------+-----------------+
| Query_ID | Duration   | Query           |
+----------+------------+-----------------+
|        1 | 0.00025225 | select * from a |
|        2 |  0.0009805 | select * from b |
+----------+------------+-----------------+
2 rows in set

mysql> show profile for query 2;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000106 |
| checking permissions | 1.4E-5   |
| Opening tables       | 3.3E-5   |
| init                 | 3E-5     |
| System lock          | 2E-5     |
| optimizing           | 0.000259 |
| statistics           | 4.5E-5   |
| preparing            | 2.5E-5   |
| executing            | 4E-6     |
| Sending data         | 0.000358 |
| end                  | 7E-6     |
| query end            | 6E-6     |
| closing tables       | 8E-6     |
| freeing items        | 5.4E-5   |
| cleaning up          | 1.4E-5   |
+----------------------+----------+
15 rows in set
View Code

 

优化update
换成select使用explain

优化delete

mysql> select * from parent;
+----+------+
| id | name |
+----+------+
|  1 | pa   |
|  2 | pb   |
|  3 | pc   |
|  4 | pd   |
+----+------+
4 rows in set

mysql> select * from child;
+-----------+----------+
| parent_id | child_id |
+-----------+----------+
|         1 |        1 |
|         2 |        2 |
|         3 |        3 |
|         1 |        4 |
|         1 |        5 |
|         2 |        6 |
|         0 |        7 |
|         5 |        8 |
|         6 |        9 |
|         5 |       10 |
+-----------+----------+

删除child中parent_id不在parent表的记录
一般的写法是
delete from child where parent_id not in(select id from parent);
更加高效的是使用连接查询
通过以下来验证

set profiling=1;
select * from child where parent_id not in(select id from parent);

select child.* from child left join parent on child.parent_id=parent.id where parent.id is null;

select query_id,count(*) as \'#ops\' ,sum(duration) from information_schema.profiling group by query_id;
select * from information_schema.profiling ;

演示结果
mysql> set profiling=1;
Query OK, 0 rows affected

mysql> select * from child where parent_id not in(select id from parent);
+-----------+----------+
| parent_id | child_id |
+-----------+----------+
|         0 |        7 |
|         5 |        8 |
|         6 |        9 |
|         5 |       10 |
+-----------+----------+
4 rows in set

mysql> select child.* from child left join parent on child.parent_id=parent.id where parent.id is null;
+-----------+----------+
| parent_id | child_id |
+-----------+----------+
|         0 |        7 |
|         5 |        8 |
|         6 |        9 |
|         5 |       10 |
+-----------+----------+
4 rows in set

mysql> select query_id,count(*) as \'#ops\' ,sum(duration) from information_schema.profiling group by query_id;
+----------+------+---------------+
| query_id | #ops | sum(duration) |
+----------+------+---------------+
|        1 |   23 | 0.000749      |
|        2 |   16 | 0.000388      |
+----------+------+---------------+

优化器显示第二个用了更少的操作
优化Insert,同一表的多条类似的多个insert改写成1条减少数据库的网络往返
例外一个好处是mysql只需为insert语句产生一次执行计划,可以在多个值上利用同一个执行计划
当批量插入时,如果单个插入失败,多个value子句说明的记录都无法插入成功

优化insert ...on duplicate key update
replace在内部是使用delete和insert来实现的,因而其效率并不高
使用insert ...on duplicate key update
如果存在同样主键值的记录,而其它列与现在存指定的记录有所不同,就更新该记录,如果记录不存在就插入该记录,如果记录存在而且没有任何值发生改变
就不做任何操作,优于replace

mysql> desc a;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| id    | int(11)  | NO   | PRI | NULL    | auto_increment |
| sid   | int(11)  | YES  |     | NULL    |                |
| type  | char(10) | NO   |     | NULL    |                |
+-------+----------+------+-----+---------+----------------+
mysql> select * from a;
+----+-----+------+
| id | sid | type |
+----+-----+------+
|  1 |  11 | aa   |
|  2 |   1 | b    |
|  3 |   2 | c    |
|  4 |   3 | d    |
+----+-----+------+
mysql> insert into a(`id`,`type`) values(1,\'a1\');
1062 - Duplicate entry \'1\' for key \'PRIMARY\'
mysql> insert into a(`id`,`type`) values(1,\'a1\') on duplicate key update type=\'a1\';
Query OK, 2 rows affected
注意改变的是2行
mysql> insert into a(`id`,`type`) values(以上是关于mysql常见的优化需要注意的点的主要内容,如果未能解决你的问题,请参考以下文章

Centos7下安装mysql5.6需要注意的点

mysql有几种索引类型?使用索引时都有那些地方要注意?sql优化原则

linux学习:Nginx--常见功能配置片段与优化-06

使用 C++ 反转句子中的每个单词需要对我的代码片段进行代码优化

ClickHouse学习-建表和索引的优化点

ClickHouse学习-建表和索引的优化点