优化SQL语句的一般步骤详情

1.通过show status 命令了解各种SQL的执行频率。

格式:show [session|global]status;

其中:session(默认)表示当前连接,

     global表示自数据库启动至今

show status;
show global status;
show status like 'com_%';
show global status like 'com_%';

参数说明:

com_xxx表示每个xxx语句执行的次数如:

com_select执行select操作的次数,一次查询只累计加1

com_update执行update操作的次数

com_insert执行insert操作的次数,对批量插入只算一次。

com_delete执行delete操作的次数

只针对InnoDB存储引擎的。

InnoDB_rows_read执行select操作的次数

InnoDB_rows_updated执行update操作的次数

InnoDB_rows_inserted执行insert操作的次数

InnoDB_rows_deleted执行delete操作的次数

其他:

connections连接mysql的数量

Uptime服务器已经工作的秒数

Slow_queries慢查询的次数

2.定位执行效率较低的SQL语句

1)explain select * from table where id=1000;

2)desc select * from table where id=1000;

每一列的简单解释

id:1

select_type:SIMPLE表示select的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个SELECT)等。

table:stu 输出结果集的表

type:range 表示表的连接类型,性能由好到差:system(表仅一行)、const(只一行匹配)、eq_ref(对于前面的每一行使用主键和唯一)、ref(同eq_ref,但没有使用主键和唯一)、ref_or_null(同前面对null查询)、index_merge(索引合并优化)、unique_subquery(主键子查询)、index_subquery(非主键子查询)、range(表单中的范围查询)、index(都通过查询索引来得到数据)、all(通过全表扫描得到的数据)

possible_keys:name,ind_stu_name 表示查询可能使用的索引。

key:name 表示实际使用的索引。

key_len:50 索引字段的长度

ref:NULL

rows:8 扫描行的数量

Extra:Using where;Using index执行情况的说明和描述

索引问题

索引是数据库优化中最常见也是最重要的手段之一,通过索引通常可以帮助用户解决大多数的SQL性能问题。

1.索引的存储分类

  MyISAM存储引擎的表的数据和索引是自动分开存储的,各自是独一的一个文件;InnoDB存储引擎的表的数据和索引是存储在同一个表空间里面,但可以有多个文件组成。

  MySQL目前不支持函数索引,但是能对列的前面某一部分进行索引,例如name字段,可以只取name的前4个字符进行索引,这个特性可以大大缩小索引文件的大小,用户在设计表结构的时候也可以对文本列根据此特性进行灵活设计。

--其中company表名 ind_company_name索引名
create index ind_company_name on company(name(4));

2.MySQL如何使用索引

索引用于快速找出在某个列中有一特定值的行。对相关列使用索引是提高SELECT 操作性能的最佳途径。

1)、使用索引

a)对于创建的多列索引,只要查询的条件中用到最左边的列,索引一般就会被使用。如下创建一个复合索引。

create index ind_sales2_com_mon on sales2(company_id,moneys);

然后按company_id进行查询,发现使用到了复合索引

explain select * from sales2 where company_id = 2006\G

使用下面的查询就没有使用到复合索引。

explain select * from sales2 where moneys = 1\G

b)使用like的查询,后面如果是常量并且只有%号不在第一个字符,索引才可能会被使用,如下:

复制代码

mysql> explain select * from t1 where name like "%z"\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4
        Extra: Using where
1 row in set (0.01 sec)
mysql> explain select * from t1 where name like "z%"\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t1
         type: range
possible_keys: idx_name
          key: idx_name
      key_len: 63
          ref: NULL
         rows: 3
        Extra: Using where
1 row in set (0.00 sec)

c)如果对大的文本进行搜索,使用全文索引而不使用like" %...%".

d)如果列名是索引,使用column_name is null将使用索引。

2)、存在索引但不使用索引

a)如果MySQL估计使用索引比全表扫描更慢,则不使用索引。例如如果列key_part1均匀分布在1到100之间,查询时使用索引就不是很好

select * from table_name where key_part1 >1 and key_part <90;

b)如果使用MEMORY/HEAP表并且where条件中不使用"="进行索引列,那么不会用到索引。Heap表只有在"="的条件下会使用索引。

c)用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。

d)如果不是索引列的第一部分,如虽然在money上面建有复合索引,但是由于money不是索引的第一列,那么在查询中这个索引也不会被MySQL采用。

e)如果like是以%开始,可见虽然在name上面建有索引,但是由于条件中like的值为"%"在第一位了,那么MySQL也不会采用这个索引。

f)如果列类型是字符串,但在查询时把一个数值型常量赋值给了一个字符型的列名name,那么虽然在name列上有索引,但是也没有用到。

3.查看索引使用情况

  如果索引正在工作,Handler_read_key的值将很高,这个值代表了一个行被索引值读的次数。

  Handler_read_rnd_next的值高则意味着查询运行低效,并且应该建立索引补救。

mysql> show status like 'handler_read%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 13    |
| Handler_read_key      | 35    |
| Handler_read_next     | 4     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 96    |
+-----------------------+-------+

两个简单实用的优化方法

对于大多数开发人员来说,可能只希望掌握一些简单实用的优化方法,对于更多更复杂的优化,更倾向于交给专业DBA来做。

1.定期分析表和检查表

ANALYZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE tal_name[,tbl_name]...

本语句用于分析和存储表的关键字分布,分析的结果将可以使得系统得到准确的统计信息,使得SQL能够生成正确的执行计划。

mysql> analyze table t1;
+---------+---------+----------+----------+
| Table   | Op      | Msg_type | Msg_text |
+---------+---------+----------+----------+
| test.t1 | analyze | status   | OK       |
+---------+---------+----------+----------+

分析表的语法如下:(检查一个或多个表是否有错误)

CHECK TABLE tbl_name[,tbl_name]...[option]... option =
{QUICK|FAST|MEDIUM|EXTENDED|CHANGED}

mysql> check table t1;
+---------+-------+----------+----------+
| Table   | Op    | Msg_type | Msg_text |
+---------+-------+----------+----------+
| test.t1 | check | status   | OK       |
+---------+-------+----------+----------+

2.定期优化表

OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE tbl_name[,tbl_name]

  如果已经删除了表的一大部分,或者如果已经对含有可变长度行的表进行了很多的改动,则需要做定期优化。这个命令可以将表中的空间碎片进行合并,但是此命令只对MyISAM、BDB和InnoDB表起作用。

mysql> optimize table t1;
+---------+----------+----------+----------+
| Table   | Op       | Msg_type | Msg_text |
+---------+----------+----------+----------+
| test.t1 | optimize | status   | OK       |
+---------+----------+----------+----------+

常用SQL的优化

1.大批量导入数据

当用load命令导入数据的时候,适当设置可以提高导入的速度。对于MyISAM存储引擎的表,可以通过以下方式快速的导入大量的数据。

ALTER TALBE tbl_name DISABLE KEYS
loading the data
ALTER TABLE tbl_name ENABLE KEYS

DISABLE KEYS 和 ENABLE KEYS用来打开或关闭MyISAM表非唯一索引的更新,可以提高速度,注意:对InnoDB表无效。

1)针对于InnoDB类型表数据导入的优化

  因为InnoDB表是按照主键顺序保存的,所以将导入的数据主键的顺序排列,可以有效地提高导入数据的效率。

load data infile '/home/mysql/film_test3.txt' into table film_test4;

2)关闭唯一性校验可以提高导入效率

  在导入数据前先执行set unique_checks=0,关闭唯一性校验,在导入结束后执行set unique_checks=1,恢复唯一性校验,可以提高导入效率。

3)关闭自动提交可以提高导入效率

  在导入数据前先执行set autocommit=0,关闭自动提交事务,在导入结束后执行set autocommit=1,恢复自动提交,可以提高导入效率。

2.优化insert语句

尽量使用多个值表的insert语句,这样可以大大缩短客户与数据库的连接、关闭等损耗。

可以使用insert delayed(马上执行)语句得到更高的效率。

将索引文件和数据文件分别存放不同的磁盘上。

可以增加bulk_insert_buffer_size变量值的方法来提高速度但是只对MyISAM表使用

当从一个文件中装载一个表时,使用LOAD DATA INFILE,这个通常比使用很多insert语句要快20倍。

3.优化group by 语句

  如果查询包含group by但用户想要避免排序结果的损耗,则可以使用order by null来禁止排序。

4.优化嵌套查询

嵌套查询(里面的子句可以用到索引,外面的用不到索引)可以使用更有效的链接查询(Join替代)

数据库优化

1.优化表的类型

2.通过拆分提高表的访问效率

3.使用中间表或视图提高统计查询速度

MySQL服务器优化

四种字符集问题

Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8

# vi /etc/my.cnf
[client]
default-charset-set=utf8  --客户端字符集
[mysqld]
character-set-server = utf8  --服务器字符集
collation-server=utf8_general_ci  --校验字符集

binary log日志问题

# vi /etc/my.conf
log-bin=mysql-bin  --开启binlog日志

slow log慢查询日志问题

mysql> show variables like '%slow%';
+---------------------+-----------------------------------------+
| Variable_name       | Value                                   |
+---------------------+-----------------------------------------+
| log_slow_queries    | OFF                                     |
| slow_launch_time    | 2                                       |
| slow_query_log      | OFF                                     |
| slow_query_log_file | /usr/local/mysql/var/localhost-slow.log |
+---------------------+-----------------------------------------+
mysql> show variables like '%long%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
--开启慢查询日志
# vi /etc/my.cnf 
log_slow_queries = slow.log
long_query_time = 5
--重启mysql服务器
mysql> show variables like '%slow%';
+---------------------+----------+
| Variable_name       | Value    |
+---------------------+----------+
| log_slow_queries    | ON       |
| slow_launch_time    | 2        |
| slow_query_log      | ON       |
| slow_query_log_file | slow.log |
+---------------------+----------+
mysql> show variables like '%long%';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 5.000000 |
+-----------------+----------+

socket问题

1.有时候登录mysql时提示不能用socket登录,此时可以换成tcp方式去登录,但是可以测试时可以这样用,但是必须要在php去用之前把这个事情解决了

# /usr/local/mysql/bin/mysql -uroot -proot --protocol tcp -hlocalhost
--这样就可以登录,可以不用mysql.sock来登录,而mysql.sock是启动mysqld
--服务时产生的,所以重启mysqld进程又会产生mysql.sock

root密码丢失

1.service mysqld stop
2.mysqld_safe --skip-grant-tables --user=mysql &
--跳过授权表mysql.user和mysql.db这些表
3.mysql -uroot
4.set password = password("root");
--用这一条语句结果报错,就是因为加了 --skip-grant-tables
5.update user set password=password("root") where user='root' and host='localhost';
6.set password for root@localhost = password("root");
7.set password = password("root");
--和第五步一样,都可以成功修改密码。

猜你喜欢

转载自blog.csdn.net/dreamhua927/article/details/86009858