mysql优化

1、优化概述

设计角度:存储引擎的选择(myisam/innodb),字段类型的选择(数字型/日期型/字符型)、范式

自身特性索引、查询缓存、分区分表、存储过程、sql语句优化配置

部署大负载架构体系:主从赋值、读写分离

硬件升级

2、分析需要优化的语句

  查找出执行速度比较慢的sql语句,来具体分析sql语句

1、 慢查询

是mysql提供的日志,记录所有超过了某个时间界限的sql语句,在mysql中默认是没有开启的,就算开启了,也只能记录执行超过10s的语句

         在my.ini 中进行配置

         Log-slow-queries = ‘man-log’                             // 也可以指定在d:/slow-log

         Long_query_time = 0.5                                         // 指定事件界限

         测试:  select benchmark(10000000,10000*10000)

         查看:

                   Show variables like ‘long_query_time’             // 查看设置的时间界限

                   Set ‘long_query_time’= 1                                     // 把时间界限设置为1

2、 精确查询

使用mysql提供的profile机制完成,记录每次sql语句的执行时间

Set profiling = 1|0 (开启或关闭)                // 设置时间界限

Show profiles                                                  // 查看记录时间

注意:不需要分析时,最好将其关闭,set profiling = 0

对字段的查询,一般情况下一个没有添加索引的语句,执行的速度是比较慢的

3、索引

索引:利用数据的某个特征,快速定位该数据位置的技术

在myisam引擎里面,索引是单独的一个文件 . MYD 在添加索引后文件大小将会增加

1、 索引的类型

主键索引(primary key) àprimary key

唯一索引(unique)      àunique key

普通索引(index)         à key

全文索引(fulltext  index)         àFulltext key

联合索引[ index(name,age)]  àkey

在添加索引时,如果没有指定索引的名称,则是把字段的名称当成索引的名称

查看索引:show create table table_name

增加索引:alter table table_name add index (索引名称);

删除索引:alter table table_name drop index (索引的名称)

索引结构:show keys from 表名

2、 myisam引擎的索引的数据结构

索引的节点中存储的数据是物理地址(磁道和扇区)

在查找数据时,查找到索引后,根据索引的节点的物理地址,再查找到具体的内容

通过在sql语句中的字段查找到索引的物理地址,并查找到具体的数据内容

3、 innodb的索引的数据结构

innodb的主键索引文件上直接存放该行数据,称为聚簇索引

innodb的非主键索引,非主键索引指向对主键的引用

innodb的特点:

1)       主键索引既存储索引值,又在叶子中存储行的数据

2)       如果没有主键,则会把unique key 做主键

3)       如果没有unique则系统生成一个内部的roword做主键

4)       像innodb中,主键的索引结构中,既存储了主键,又存储了行数据,这种结构称为‘聚簇索引

5)       在innodb里面,数据是按照主键的顺序插入数据的,因此在大量的插入数据时,会影响效率,每插入一条数据,会重新排序

4、 创建索引的注意事项

a)         较频繁的作为查询条件应该创建索引

b)         唯一性太差的字段不适合单独创建索引(枚举性的数据)

c)         更新非常频繁的字段不适合创建索引

d)         不会出现在where子句中字段不该创建索引

e)         where 后边加id 获取是group by / order by 后的字段加索引

4、执行计划

         执行计划通常是使用explain/desc sql  \G  来分析sql语句的执行情况,并不是真实的执行sql语句,只是查看sql语句的执行情况,执行sql语句都用到了哪些方法

1Type:查询的方式

all 扫描了全文的所有的数据

index 比all要好一点,是指要扫描所有的索引节点,但是在索引覆盖(一般情况下是innodb引擎下,非索引字段中都存储着主键id索引,故在查询的时候会出现索引覆盖的情况)的查询的情况下,能利用上索引,但是还是必须进行全索引扫描; 利用索引来进行排序,但只能取出索引的列

range: 范围扫描在非主键索引当中使用大小于号 where c_id >10

ref : 通过非主键索引列直接引用到某些数据行 where c_id=?

const/system/null 通常在使用主键查找的情况下,很容易出现此类型

2possible_key: 可能用到的索引

3key 最终用到的索引

4key_len使用索引的最大长度

5rows 扫描的最大行数

6extrausing index           用到了索引覆盖,效率非常高

                    Using where          用索引还无法进行定位,还需使用where进行判断

using temporary  临时表

 

5、索引覆盖

         如果查询的列刚好是索引(主键索引和非主键索引)的一部分,那么查询只需要在索引文件上进行,而不需要在磁盘上查找数据,这样的查询方式非常的快

 

6、索引的使用细节

1、全值匹配

条件字段使用’=’,条件字段必须建立索引才能得到

Desc select * from stu where name=”xiaoming”  // 当name字段为索引的时候才能用到索引

2、范围匹配

         <= | >= | between…and…  当使用主键id时为primay key,非索引字段的时候为key

3、左值匹配

          Select * from stu where name like ‘abc%’  // 此句可以使用索引匹配

          Select * from stu where name like ‘%abc’    // 当%放在字符的前边的时候不会使用索引

          Select * from stu where name=’abc%’;     // 此处为非模糊匹配

         拓展: select * from stu where name like name=’a%’    

                   Select * from stu where name like name=’%a’

                   Select * from stu where name like name=’%a%’

                   Select * from stu like name=’a_’               // a后边接单个的字符

4、独立的列

指的是索引的列,不能是表达式,也不能是函数的参数

Desc select * from stu where id=1+1(1+1 = id)(不可以id+1=2必须独立的)

5、如果存在有or运算,规定or两边的字段都存在索引字段才能用到索引

Desc select * from stu where id=2 or name=’xiaofeng’  (id和name 均为索引才可以)

6、多列索引(联合索引)

         当创建了联合索引,在查询的时候当使用了左边的索引,索引一般就会被使用

且联合索引都是需要按字段的顺序执行的;例C1C2C3想要在C2上使用索引,必须先使用C1索引,想要使用C3索引,必须先使用C2索引

desc select * from t4 where c1=1 and c2=2 and c4>2 and c3=3

7、当取出的数据量超过了20%,优化器将不会使用,而是全表扫描

7、表的分割

1、垂直分割:

1) 单一事物:将不经常查询的字段,单独使用一张表来进行存储(图书的分类和内容分开)

2) 多个事物(主表+附表)

将事物共同的字段(类名,图片)作为一张表,不同的事物再单独的使用一张表存储

2、水平分割:

         如用户注册,使用取模算法,三张用户表,一张用户的注册数列表num,通过对num来进行取模运算,来决定用户分配到哪一张表中

8、翻页优化和延时缓存

Limit offset,N  mysql在查询的时候,并不是将前面offset跳过,而是先将offset+N 条记录查询出来,再返回N条数据,故offset偏移量越大,翻页就会越缓慢

 

需求:限制总的翻页数方案

方案一:

先计算出总的页数,使用min(70,$pages)函数来进行最大限制

方案二:

不使用offset 来进行查询

Select * from stu limit 1000,10                           当记录不连续的时候,id值将会错位

Select * from stu where id>1000 limit 10   

故在数据库中不要轻易地删除数据,可以为其添加is_delete 字段来进行软删除

方案三:

当物理删除,且不能offset,还不能限制分页时,此时可以使用延时索引

延时索引:现将需要查询的记录数的id查询出来,然后根据内连接进行查询

Select * from stu a inner join (select * from stu limit 1000,10) as tmp on a.id = tmp.id

 

9、mysql锁机制

         Myisam: 表级锁,开销小,锁冲突高,并发率小

         读锁lock table table_name read  自己可读,别人可读,均不能写

         写锁 lock table table_name write  自己可读可写,别人不可读不能写

         解锁:unlock tables;

         操作多张表的时候:lock table tab1,tab2,….read/write

 

         Innodb:  行锁,开销大,锁冲突低,并发率大

         Innodb是给索引加上索引项来加锁实现的,只用通过索引条件来进行检索数据才能开启行锁,否则将会开启表锁 

Begin 开启锁机制

         Commit 提交                    // 事物处理

10、数据的碎片与维护

         对于myisam表会产生3个文件名:.frm(表结构)  .myd  .myi

         当我们再删除表中的一些字段后,会产生数据表结构并没有调整也没有将所占的文件大小改变,故一下两种方法来实现,碎片的整理

         1、改变表的引擎来实现      

                   Alter table table_name engine 原来的引擎

         2、使用

optimize  table  表名

11、数据表的分区

         当数据量非常大的时候,通常采用数据的逻辑分区,便于存储数据

         create table  table_name(

         字段信息,

    索引,

)表选项[engine myisam,charset utf8]

partition by 分区算法(分区选项)

 

分区算法listrangehashkey

 

create table emp(

    id int primary key auto_increment,

    name varchar(32) not null,

    store_id  int

)engine myisam charset utf8

partition by list (store_id)(              // store_id 分公司的id来进行关联

    partition bei values in (1,4,5,6,17,18),                                //1,4,5....分公司编号

    partition nan values in (2,7,9,10,11,13),

    partition dong values in (3,12,19,20),

    partition xi values in (8,14,15,16)

);

 

通过以下指令来进行查询

explain partitions select * from p_list where store_id=20 and id=3 \G

 

分区表的限制

只能对数据表的整型列进行分区,或者数据列可以通过分区函数转化成整型列

对id,store_id 来进行分区(关联)

如果含有唯一索引或者主键,则分区列必须包含在所有的唯一索引或者主键在内

不支持外键

不支持全文索引(fulltext)

按日期进行分区很非常适合,因为很多日期函数可以用。但是对于字符串来说合适的分区函数不太多

 

12、主从复制,读写分离

主从复制的条件

至少使用两台mysql服务器,一台作为主服务器,一台作为从服务器,将主服务器上的写(增删改)操作,同步到从服务器上,主服务器只进行写操作,从服务器只进行查询操作

 

主从复制的原理

在mysql中存在有一个log-bin日志专门用来记录mysql下所有修改过数据库的sql语句,

主从复制的原理是多台服务器都开启bin日志(在my.ini中修改),然后主服务器会把执行过的sql语句记录到bin日志中,之后把这个bin日志发送给从服务器,从服务器将bin日志文件中的语句执行一次,就可以和主服务器上的数据一致了

 

主从复制的使用

1、在主从表中创建一个用户并为其分配权限

master主服务器:grant all on *.* to 'xiaoming'@'%' identified by '123456';

slave  从服务器: grant all on *.* to 'xiaomei'@'192.168.28.28' identified by '123456';

另: 删除用户 drop user ‘用户名’@’授权登录的主机ip地址’

 

2、在my.ini中开启log-bin文件[linux下是my.cnf]

log-bin = mysql-bin (或者自己指定log-bin = d:/nginx/log.txt),当在重启mysql的时候将会在data下产生一个log-bin:000001的文件,该文件就记录着执行的sql语句

 

log-bin日志的相关函数

reset master                  // 清空所有的log-bin日志,产生一个新的log-bin文件

flush logs                     // 产生一个新的log-bin日志文件

show master status    // 查看一个最新的log-bin日志文件,并包含pos位置

 

查看log-bin日志

mysqlbinlog --no-defaults 日志文件的名称(全路径)

mysqlbinlog --no-defaults  d:/wamp/mysql/data/mysql-bin.000003

 

使用log-bin日志完成数据的恢复

1、  创建一张表

2、  执行flush logs,产生一个新的日志文件

3、  使用insert语句完成数据的插入

4、  执行flush logs(产生一个新的日志)

5、  将刚才添加的数据删除

6、  使用log-bin 来进行日志的数据恢复

msyqlbinlog - -no-defaults 日志文件的名称(全路径) | mysql –uroot –proot 数据库的名称

 

恢复某一时间段内的数据[一般是在某个离的近的时间段,但是时间如果太长将不能很好的恢复]  可以使用 --start-post=’开始位置’ --stop-position = ‘结束的位置’

mysqlbinlog --no-defaults --start-position=’?’ --stop-postion=’?’ d:/wamp/mysql/mysql-bin.0001

 

主从复制的配置

1、  对主从服务器进行编号

主:server-id =1

从:server-id = 2

 

2、  在主服务器上面授权一个用户,从服务器就是通过该账号来读取log-bin中的日志信息的

master主服务器:grant replication slave on *.* to ‘xiaomei’@’%’ identified by ‘123456’

 

3、查看主服务器的最新的log-bin日志,此时禁止任何人对主武器的任何修改

show master

 

3、  从服务器的配置

关闭从服务器stop slave;

开始配置:

change master to master_host =’主服务器的ip地址’,master_user = ‘主服务器上的username’,master_password=’密码’,master_log_file=’bin日志文件名’,master_log_pos = bin日志中的position值

 

配置完成:start slave

查看服务器的状态:show slave status \G

Slave_IO_Running:yes 此进程负责从服务器从主服务器上读取日志,并写入从服务器上

Slave_SQL_Running:yes 此进程负责读取并且执行中继日志中的binlog日志

 

测试完成:在主服务器上面创建一个新的数据库,并创建一张新表,并添加记录,查看从服务器是否同步来完成测试

 

配置完成后,要禁止对服务器执行增删改的操作

 

撤销从服务器

停止从服务器:stop slave

删除从服务器的配置:reset slave all;

 

读写分离

 

class  mysql{

         $dbm=主服务器

         $dbs1=从服务器

         $dbs2=从服务器

         public function query(){

            在query里面进行语句判断,分析连接不同的mysql服务器。

如果是增删改的操作,就连接主服务器,如果是查询操作,则随机连接从服务器。

         }

}

 

TP支持读写分离

 

修改TP框架项目的配置文件:

    'DB_DEPLOY_TYPE'=>1,//分布式数据库支持

    'DB_TYPE'               => 'mysql',     // 数据库类型

    'DB_HOST'               => 'localhost,192.168.3.250', // 服务器地址,多个用逗号隔开,默认第一个是主服务器,其余是从服务器。

    'DB_NAME'               => 'php,php',          // 数据库名

    'DB_USER'               => 'root,xiaogang',      // 用户名

    'DB_PWD'                => 'root,1234',          // 密码

    'DB_PORT'               => '3306',        // 端口

    'DB_PREFIX'              => '',

    'DB_RW_SEPARATE'=>true,//支持读写分离

    'DB_MASTER_NUM'       =>  1, // 读写分离后 主服务器数量

'DB_SLAVE_NO'       =>  '', // 指定从服务器序号,如果为空,则随机连接从服务器。

 

posted @ 2015-10-26 09:24  罗雪纷纷  阅读(201)  评论(0)    收藏  举报