mysql优化

u Mysql数据库的优化技术

mysql优化时一个综合性的技术,主要包括

a: 表的设计合理化(符合3NF)

i:sql语句本身优化

b: 添加适当索引(index) [四种: 普通索引、主键索引、唯一索引unique、全文索引]

c: 分表技术(水平分割、垂直分割)

d: 读写[: update/delete/add]分离

e: 存储过程 [模块化编程,可以提高速度]

f: mysql配置优化 [配置最大并发数my.ini, 调整缓存大小 ]

g: mysql服务器硬件升级,如果你的机器内存超过4G,那么毋庸置疑应当采用64位操作系统和64mysql 5.5.19

h: 定时的去清除不需要的数据,定时进行碎片整理(MyISAM)

--f:my.ini:   max_connections=100 //默认最大并发数

           一般网站调整到1000左右,每个并发都会开一个进程耗内存,不宜再大

什么样的表才是符合3NF (范式)

表的范式,是首先符合1NF, 才能满足2NF , 进一步满足3NF

1NF: 即表的列的具有原子性,不可再分解,即列的信息,不能分解, 只有数据库是关系型数据库(mysql/oracle/db2/informix/sysbase/sql server),就自动的满足1NF

☞ 数据库的分类

关系型数据库: mysql/oracle/db2/informix/sysbase/sql server

非关系型数据库: (特点: 面向对象或者集合)

NoSql数据库: MongoDB(特点是面向文档)

2NF: 表中的记录是唯一的, 就满足2NF, 通常我们设计一个主键来实现

     主键:不含业务逻辑,一般是自增的,因为主键不含业务逻辑,不修改所以比较稳定

3NF: 即表中不要有冗余数据, 就是说,表的信息,如果能够被推导出来,就不应该单独的设计一个字段来存放. 比如下面的设计就是不满足3NF:

3NF : 但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是: 在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,允许冗余 

案例

u Sql语句本身的优化

问题是: 如何从一个大项目中,迅速的定位执行速度慢的语句. (定位慢查询)

① 首先我们了解mysql数据库的一些运行状态如何查询(比如想知道当前mysql运行的时间/一共执行了多少次select/update/delete.. / 当前连接)

知道有什么用呢?因为存储引擎由执行的什么语句来决定

show status//

常用的:

show []status like ‘uptime’ ;

 // 启用了多长时间秒数

Show[] stauts like ‘com_select’  show[] stauts like ‘com_insert’ ...类推 update  delete

//当前执行了多少次查询,添加,删除

☞ show [session|global] status like .... 如果你不写  [session|global] 默认是session 会话,指取出当前窗口的执行,如果你想看所有(mysql 启动到现在,则应该 global)

show status like ‘connections’;

//连接到mysql的连接数,加不加global都一样,包括打开的mysql窗口和php

如何知道那个IP连接到mysql指令:netstat -an

C:Documents and SettingsAdministrator>netstat -an

如何显示进程号C:Documents and SettingsAdministrator>netstat -anb

杀死进程就可以删除远程连接

Active Connections

         

  Proto  Local Address          Foreign Address        State

            Mysql服务器地址      连接到mysql的地址

  TCP    127.0.0.1:3306         127.0.0.1:2200         ESTABLISHED

  TCP    127.0.0.1:3306         127.0.0.1:4759         ESTABLISHED

//显示慢查询次数

show status like ‘slow_queries’;

① 如何去定位慢查询

构建一个大表(400 )-> 储过程构建

默认情况下,mysql认为10秒才是一个慢查询.

修改mysql的慢查询变量.

show variables like ‘long_query_time’ ; //可以显示当前慢查询时间

set long_query_time=1 ;//可以修改慢查询时间

只要从新启动mysql就会恢复默认时间

构建大表->大表中记录有要求, 记录是不同才有用,否则测试效果和真实的相差大.

创建:

CREATE TABLE dept( /*部门表*/

deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0,  /*编号*/

dname VARCHAR(20)  NOT NULL  DEFAULT "", /*名称*/

loc VARCHAR(13) NOT NULL DEFAULT "" /*地点*/

) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

CREATE TABLE emp

(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/

ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/

job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/

mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/

hiredate DATE NOT NULL,/*入职时间*/

sal DECIMAL(7,2)  NOT NULL,/*薪水*/

comm DECIMAL(7,2) NOT NULL,/*红利*/

deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/

)ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

CREATE TABLE salgrade

(

grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,

losal DECIMAL(17,2)  NOT NULL,

hisal DECIMAL(17,2)  NOT NULL

)ENGINE=MyISAM DEFAULT CHARSET=utf8;

测试数据

INSERT INTO salgrade VALUES (1,700,1200);

INSERT INTO salgrade VALUES (2,1201,1400);

INSERT INTO salgrade VALUES (3,1401,2000);

INSERT INTO salgrade VALUES (4,2001,3000);

INSERT INTO salgrade VALUES (5,3001,9999);

为了存储过程能够正常执行,我们需要把命令执行结束符修改

delimiter $$

create function rand_string(n INT)#生成一个n位的随机数 

returns varchar(255) #该函数会返回一个字符串

begin

#chars_str定义一个变量 chars_str,类型是 varchar(100),默认值'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';

 declare chars_str varchar(100) default

   'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';

 declare return_str varchar(255) default '';

 declare i int default 0;

 while i < n do

   set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));

   set i = i + 1;

   end while;

  return return_str;

  end $$

如果希望在程序中使用,是Ok!

Dual: 亚元表 就是空表

//输出随机数

mysql_connect('localhost','root','root');

mysql_select_db('bigtable');

$sql="select rand_string(6) my from dual";

$re=mysql_query($sql);

if($row=mysql_fetch_assoc($re)){

 echo $row['my'];

}

创建一个存储过程

create procedure insert_emp(in start int(10),in max_num int(10))

begin

declare i int default 0;

#set autocommit =0 autocommit设置成0

 set autocommit = 0;  

 repeat

 set i = i + 1;

 insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());

  until i = max_num

 end repeat;

   commit;

 end $$

#调用刚刚写好的函数, 1800000条记录,100001号开始

call insert_emp(100001,4000000);

select * from emp where empno=789643;

① 这时我们如果出现一条语句执行时间超过1秒中,就会统计到.存储过程也算一执行时间

 究竟知道慢查询sql语句?:

② 如果把慢查询的sql记录到我们的一个日志中

在默认情况下,我们的mysql不会记录慢查询,需要在启动mysql时候,指定记录慢查询才可以(在cmd命令行里边)

Binmysql所在的目录,不要进到bin里边

1.  d: D:phpStudyMySQL

2.  binmysqld.exe - -safe-mode  - -slow-query-log [mysql5.5 可以在my.ini指定]

binmysqld.exe log-slow-queries=d:/abc.log [低版本mysql5.0可以在my.ini指定]

安全模式就是会记录日志,有恢复的能力

先关闭mysql,再启动, 如果启用了慢查询日志,默认把这个文件放在

my.ini 文件中记录的位置

#Path to the database root

datadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/"

③ 测试,可以看到在日志中就记录下我们的mysqlsql语句.

我的 D:phpStudyMySQLdata

知道慢查询的语句了怎么优化?

优化问题.

通过 explain 语句可以分析,mysql如何执行你的select 语句, 这个工具的使用放一下,一会说.可以查看是否有索引

Mysql:执行时第一次先缓存,如果是执行过的直接就在缓存中找到

添加索引 【小建议:

老板要求提升速度!,怎么办呢?先分析explain,立马加索引,非常管用

四种索引(主键索引/唯一索引/全文索引/普通索引)

  1. 添加

1.1主键索引添加

当一张表,把某个列设为主键的时候,则该列就是主键索引

create table aaa

(id int unsigned primary key auto_increment ,

name varchar(32) not null defaul ‘’);

这是id 列就是主键索引.

如果你创建表时,没有指定主键索引,也可以在创建表后,在添加, 指令:

alter table 表名 add primary key (列名);

举例:

create table bbb (id int , name varchar(32) not null default ‘’);

alter table bbb add primary key (id);

1.2普通索引

一般来说,普通索引的创建,是先创建表,然后在创建普通索引

比如:

create table ccc(

id int unsigned,

name varchar(32)

)

create index 索引名 on (1,列名2);

1.3创建全文索引

全文索引,主要是针对对文件,文本的检索, 比如文章, 全文索引针对MyISAM有用.

创建

CREATE TABLE articles (

       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,

       title VARCHAR(200),

       body TEXT,

       FULLTEXT (title,body)

     )engine=myisam charset utf8;

INSERT INTO articles (title,body) VALUES

     ('MySQL Tutorial','DBMS stands for DataBase ...'),

     ('How To Use MySQL Well','After you went through a ...'),

     ('Optimizing MySQL','In this tutorial we will show ...'),

     ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),

     ('MySQL vs. YourSQL','In the following database comparison ...'),

     ('MySQL Security','When configured properly, MySQL ...');

如何使用全文索引:

错误用法:

select * from articles where body like ‘%mysql%’; 【不会使用到全文索引】

证明:

explain  select * from articles where body like ‘%mysql%’

正确的全文索引的用法是:

                       匹配(字段名) against(字段中的值;关键字’)  

select * from articles where match(title,body) against(‘database’); 【可以】

在文章表的title,body字段中找值为database

☞ 说明:

  1. mysqlfulltext 索引只针对 myisam生效
  2. mysql自己提供的fulltext针对英文生效->sphinx 私费克斯烤sei(coreseek) 技术处理中文
  3. 使用方法是 match(字段名..) against(‘关键字’)
  4. 全文索引一个 停止词,  因为在一个文本中,创建索引是一个无穷大的数,因此,对一些常用词和字符,就不会创建,这些词,称为停止词.

停止词,是由英文单词:stopword翻译过来的,原来在英语里面会遇到很多atheor等使用频率很多的字或词,常为冠词、介词副词连词等。如果搜索引擎要将这些词都索引的话,那么几乎每个网站都会被索引,也就是说工作量巨大。可以毫不夸张的说句,只要是个英文网站都会用到a或者是the。那么这些英文的词跟我们中文有什么关系呢? 在中文网站里面其实也存在大量的stopword,我们称它为停止词。比如,我们前面这句话,里面这些词都是停止词。这些词因为使用频率过高,几乎每个网页上都存在,所以搜索引擎开发人员都将这一类词语全部忽略掉。如果我们的网站上存在大量这样的词语,那么相当于浪费了很多资源。原本可以添加一个关键词,排名就可以上升一名的,为什么不留着添加为关键词呢?停止词对SEO的意义不是越多越好,而是尽量的减少为宜。

mysql> select * from user;

+----+------------+-----+

| id | name       | age |

+----+------------+-----+

|  1 | 王盼       |  32 |

|  2 | 郭娟       |  30 |

|  3 | 王浩然     |   3 |

|  4 | shywangpan |  40 |

|  5 | guojuan    |  30 |

|  6 | wanghaoran |   3 |

+----+------------+-----+

Select match(name)agaist(‘wanhaoran’) from user//返回匹配度,它是可能性 

+----------------------------------+

| match(name)against('wanghaoran') |

+----------------------------------+

|                                0 |

|                                0 |

|                                0 |

|                                0 |

|                                0 |

|                1.591139793395996 |

+----------------------------------+

1.4唯一索引

①当表的某列被指定为unique约束时,这列就是一个唯一索引

create table ddd(id int primary key auto_increment , name varchar(32) unique);

这时, name 列就是一个唯一索引.

unique字段可以为NULL,并可以有多NULL, 但是如果是具体内容,则不能重复.

主键字段,不能为NULL,也不能重复.

②在创建表后,再去创建唯一索引

create table eee(id int primary key auto_increment, name varchar(32));

create unique index 索引名  on 表名 (列表..);

  1. 查询索引

desc 表名 【该方法的缺点是: 不能够显示索引名.

show index(es) from 表名

show keys from 表名

 删除

alter table 表名 drop index 索引名;

如果删除主键索引。

alter table 表名 drop primary key       [这里有一个小问题]

  1. 修改

先删除,再重新创建.

为什么创建索引后,速度就会变快?

u 索引使用的注意事项

索引的代价:

  1. 占用磁盘空间
  2. dml操作有影响,变慢

在哪些列上适合添加索引?

总结: 满足以下条件的字段,才应该创建索引.

a: 肯定在where条经常使用 b: 该字段的内容不是唯一的几个值(sex) c: 字段内容不是频繁变化.

为什么频繁变化的不适合加索引,因为频繁变化,索引也得跟着变

为两个列加索引:

 alter table user add index my_index(name,english);

u 使用索引的注意事项

dept表中,我增加几个部门:

alter table dept add index my_ind (左列,右列); //  dname 左边的列,loc就是右边的列

说明,如果我们的表中有复合索引(索引作用在多列上), 此时我们注意:

1, 对于创建的多列索引,只要查询条件使用了最左边的列,索引一般就会被使用,而使用右边的列不会用到索引。

explain select * from dept where loc='aaa'G 

就不会使用到索引

2对于使用like的查询,查询如果是  ‘%aaa’ 不会使用到索引

aaa%’ 会使用到索引。

比如: explain select * from dept where dname like '%aaa'G

不能使用索引,即,在like查询时,关键的 ‘关键字’ , 最前面,不能使用 % 或者 _这样的字符., 如果一定要前面有变化的值,则考虑使用 全文索引->sphinx.

这就是为什么用全文索引(fulltext)替代模糊查询(like)

  1. 如果条件中有or,就要求使用的所有字段,都必须建立索引,只一边有索引那么不会用到索引 我们建议大家尽量避免使用or 关键字

select * from dept where ame=’xxx’ or englishname=’xx’ or dname=’xxxx’                                                                                                                       如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须’’), 也就是,如果列是字符串类型,就一定要用 ‘’ 把他包括起来.

  1. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引。

explain 可以帮助我们在不真正执行某个sql语句时,就知道mysql怎样执行,这样利用我们去分析sql指令.

mysql> explain select * from user ;

+----+-------------+-------+------+---------------+------+---------+------+------+-------+

| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |

+----+-------------+-------+------+---------------+------+---------+------+------+-------+

|  1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL |    3 |       |

+----+-------------+-------+------+---------------+------+---------+------+------+-------+

如何查看索引使用的情况:

show status like ‘Handler_read%’;

大家可以注意:
handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。

handler_read_rnd_next:这个值越高,说明查询低效。

u sql语句的小技巧

  1. 在使用group by 分组查询是,默认分组后,还会排序,可能会降低速度.

比如

group by 后面增加 order by null 就可以防止排序.

  1. 有些情况下,可以使用连接来替代子查询。因为使用joinMySQL不需要在内存中创建临时表。

select * from dept, emp where dept.deptno=emp.deptno; [简单处理方式]

select * from dept left join emp on dept.deptno=emp.deptno;  [左外连接,更ok!]

如何选择mysql的存储引擎

在开发中,我们经常使用的存储引擎 myisam / innodb/ memory

myisam 存储: 如果表对事务要求不高,同时是以查询和添加为主的,我们考虑使用myisam存储引擎. ,比如 bbs 中的 发帖表,回复表.

INNODB 存储: 对事务要求高,保存的数据都是重要数据,我们建议使用INNODB,比如订单表,账号表.

MyISAM INNODB的区别

1. 事务安全 -myisan不支持事务就是不支持回滚,安全的要innodb

2. 查询和添加速度 -myisam不用排序直接在后边添加,innodb要排序后才添加

3. 支持全文索引 myisan支持全文索引 innodb不支持全文索引

4. 锁机制 myisan是表锁,innodb是锁在行上的它的精度更高它的机制更严格,事务是针对一条记录而言

5. 外键 MyISAM 不支持外键, INNODB支持外键. (PHP开发中,通常不设置外键,通常是在程序中保证数据的一致)

外键:两个表中的两个字段之间的关联对应关系,班级没有学生插入不进去,那么班级和学生

字段是外键的关系

Memory 存储,比如我们数据变化频繁,不需要入库,同时又频繁的查询和修改,我们考虑使用memory, 速度极快.

如它们名字所指明的,Memory表被存储在内存中,且默认使用哈希索引。这使得它们非常快,并且对创建临时表非常有用。可是,当服务器关闭之时,所有存储在Memory表里的数据被丢失。因为表的定义被存在磁盘上的.frm文件中,所以表自身继续存在,在服务器重启动时它们是空的。

什么是表锁:

表锁例子:

mysql锁机制是在并发操作的时候,避免多人同时操作而发生错误。

先说一下表级锁吧
表级锁 一般引擎都支持,资源消耗小。申请锁的时候 整表锁定(分读写锁),其它线程或操作不能进行操作

行级锁 INNODB引擎支持。资源消耗大 锁定的时候 被锁的行只能进行一个操作 其它均不能操作些行。

比如说数据库有个人员表,有几个人同时更新人员表中的一条记录
比如a想要将 小王 得年龄更新为 24
b想要将 小王 得婚姻状态改为 已婚
c想要将 小王 得工作单位改为 XXX
d想要将小王 这个人的记录删除
e想要查询 小王 得个人信息
这时候就存在一个问题了,如果几个东西一起在操作,数据库应该怎么操作呢?
显示怎样的信息呢?
锁的作用就是做这个的。

如果你的数据库的存储引擎是myisam,请一定记住要定时进行碎片整理

碎片整理:myisan表的缺点,在删除了一些后,它在磁盘的存放的文件的大小不会变小,这就叫碎片整理,这个非常重要

举例说明:

create table test100(id int unsigned ,name varchar(32))engine=myisam;

insert into test100 values(1,’aaaaa’);

insert into test100 values(2,’bbbb’);

insert into test100 values(3,’ccccc’);

主从复制:就是一变224,48

Insert into test100 select id,name from test100;

Delete from test100 from user where id=3  

我们应该定义对myisam进行整理

optimize table test100;

mysql_query(“optimize tables $表名”);

Optimize[熬坡teiz]优化

技术就是窗户纸.->经常和技术好人。

u PHP定时完成数据库的备份  

① 手动备份数据库(表的)方法

环境变量

cmd控制台:

     备份                                    输出符

mysqldump –u root –proot 数据库 [表名1 表名2..]  > 文件路径

比如: temp数据库备份到 d: emp.bak

文件名和后缀随意写

mysqldump –u root –proot wangpan pan> d: emp.bak

如果你希望备份是,数据库的某几张表

mysqldump –u root –prot temp dept > d: emp.dept.bak

mysqldump –u r –proot wangpan pan> d: emp.bak

本人测试

mysqldump -h localhost -u root -proot wangpan wang>d:x.x

如何使用备份文件恢复我们的数据.

mysql控制台

source d: emp.dept.bak

② 使用定时器来自定完成

把备份数据库的指令,写入到 批处理文件bat文件, 然后通过任务管理器去定时调用 bat文件.

mytask.bat 内容是:直接单击就是备份

C:mymysql5inmysqldump -u root -proot temp dept > d: emp.dept.bak

☞ 如果你的mysqldump.exe文件路径有空格,则一定要使用 “” 包括.

mytask.bat 做成一个任务,并定时调用在 2:00 调用一次

自己本机的密码为admin

控制面板-性能和维护-任务计划-添加任务计划-浏览bat文件

步骤 任务计划->增加一个任务,选中你的mytask.bat文件 ,最后配置:

测试ok

现在问题是,每次都是覆盖原来的备份文件,不利用我们分时间段进行备份, 我们可以这样处理; 示意图:

代码是:

mytask2.bat 内容:

C:myenvphp-5.3.5php.exe C:myenvapachehtdocsmytask.php

mytask.php代码:

<?php

//定时备份我们的数据库文件

date_default_timezone_set('PRC');

$bakfilename=date("YmdHis",time());

$command="C:myenvmysql5.5.27inmysqldump -u root -proot temp dept > d:\{$bakfilename}";

exec($command);

最后测试浏览器调用ok!

php文件里有个php.exe这个文件本身就可以解析php文件

控制台进去: cd  c:myphp5

           php.exe d:webmytask.php

就会执行php文件,就是让php.exe解析mytask.php并执行这个文件,和浏览器是一个效果

1.新建mytask2.bat:

c:myphp5php.exe d:webmytask.php

2.让它调用php文件,php文件是备份的命令

如何调用?

C:Documents and SettingsAdministrator桌面>c:myphp5php.exe d:webmytask.php

Exec执行系统命令

作用是,写一个数据库, 数据库中有三张表,然后每天 2:00 备份一次,文件名以时间来命名. 测试.

使用PHP完成定时发送邮件的功能

① 看一个实际的需求

① 设计一张邮件表

create table maillist

(id int unsigned primary key auto_increment,

getter varchar(64) not null default '',

sender varchar(64) not null default '',

title varchar(32) not null default '',

content varchar(2048) not null default '',

sendtime int unsigned not null default 0,

flag tinyint unsigned not null default 0)engine=myisam  charset utf8;

insert into maillist values(null,'hsp@itcast.cn','hanshunping@tsinghua.org.cn','hello100','abc hello',unix_timestamp()+10*3600,0);

insert into maillist values(null,'hsp@itcast.cn','hanshunping@tsinghua.org.cn','hello200','abc hello200',unix_timestamp()+10*3600,0);

② 写代码

  1. 怎样可以定时的去检索哪些邮件该发送., 只能每隔一定时间(1min)就看看哪些邮件该发送, mailtask.php

  1. 上面的代码是模拟发送邮件,看看如何真正发送邮件.

PHP中,有一个函数 mail , 是用于发送邮件,我们实际上可以使用 PHPMailer 类,我们使用他完成.

要正确的使用PHPMailer 发送邮件,需要满足如下条件

  1. 本身机器是可以联网的
  2. 需要搭建自己的smtp邮件服务器->示意图
    1. 搭建自己的邮件服务器.

    卸载.

    安装时傻瓜式的,一步一步的走ok

    配置

    3.1选择access数据库

    3.2

    3.3配置邮件服务器

    点击设置->邮箱域名设置 

  3. 点击设置->服务器设置

  4. 代码:

    <?php

    // 练习用PHPmailer发送邮件

    require('./PHPMailer/class.phpmailer.php');

    $mailer = new PHPMailer();

    /*

    from 来自于谁

    to :寄给谁

    cc : 抄送

    subject: 邮件主题

    Body: 邮件正文

    // 发送怎么发 ?

    */

    $cont = <<<EMAIL

        hello,world yyy!;

    EMAIL;

    // echo $cont;exit;

    $mailer->CharSet = 'utf-8';

    $mailer->ContentType = 'text/html'; // 设置内容类型为html,这样charset才能发挥作用

    $mailer->Encoding = 'base64';       // 防止服务器中继时,服务器能接收的编码不一致,带来问题.

    $mailer->From = 'shunping@192.168.1.152';

    $mailer->FromName = '顺平';

    $mailer->Subject = '一份问候,你好,韩顺平';

    $mailer->Body = $cont;

    // 设置一下语言包

    $mailer->SetLanguage('zh_cn');

    // 增加收件人地址

    // $mailer->AddAddress('328268186@qq.com','saozi');

    $mailer->AddAddress('hanshunping@tsinghua.org.cn','shunping');

    if($mailer->Send()) {

        echo '发送okok';

    } else{

        echo 'fail ';

    }

    配置 php.ini 启用账号 shunping@192.168.1.152

    [mail function]

    ; For Win32 only.

    ; http://php.net/smtp

    SMTP = localhost

    ; http://php.net/smtp-port

    smtp_port = 25

    ; For Win32 only.

    ; http://php.net/sendmail-from

    sendmail_from = shunping@192.168.1.152

    测试一把 成功!

    如何在linux下完成定时任务:

    linux如何备份.

    1. 直接执行PHP脚本, 需要在同一个服务器上执行.

    # crontab -e

    00 * * * * /usr/local/bin/php /home/htdocs/phptimer.php

    2.通过HTTP请求来触发脚本, PHP文件允许不在同一服务器上

    # crontab -e

    00 * * * * /usr/bin/wget -q -O temp.txt http://www.phptimer.com/phptimer.php

    上面是通过wget来请求PHP文件, PHP输出会保存在临时文件temp.txt中

    # crontab -e

    00 * * * * /usr/bin/curl -o temp.txt http://www.phptimer.com/phptimer.php

    上面是通过curl -o来请求PHP文件, PHP输出会保存在临时文件temp.txt中

    # crontab -e

    00 * * * * lynx -dump http://www.phptimer.com/phptimer.php

    上面是通过Lynx文本浏览器来请求PHP文件

    n 分表技术

    如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了。如果我拆成100个表,那么每个表只有10万条记录。当然这 需要数据在逻辑上可以划分。一个好的划分依据,有利于程序的简单实现,也可以充分利用水平分表的优势。比如系统界面上只提供按月查询的功能,那么把表按月 拆分成12个,每个查询只查询一个表就够了。如果非要按照地域来分,即使把表拆的再小,查询还是要联合所有表来查,还不如不拆了。所以一个好的拆分依据是 最重要的。UNION

    每个学生做过的题都记录在这个表里,包括对题和错题。每个题会对应一个或多个知识点,我们需要根据错题来分析学生在哪个知识点上掌握的不足。这个表很容 易达到千万级,迫切需要拆分,那么根据什么来拆呢?从需求上看,无论是老师还是学生,最终会把焦点落在一个学生的身上。学生会关心自己,老师会关心自己班 的学生。而且每个学科的知识点是不同的。所以我们很容易想到,联合学科和知识点两个字段来拆分这个表。这样拆下来,每个表大概2万条数据,检索效率非常 高。(使用hash方法来处理

     

    分表的核心:按什么分

    分表技术有(水平分割和垂直分割)

    分表的原则:

    查询思路:根据用户id%3=值,根据值来取出用户在那个表$table=’qqlogin’.$id%3

              $sql=’ select * from $table where id=$id;

    放的时候:也要放到对应的表里

    1qqlogin0 (id name pwd)

                3号用户

    2qqlogin1 (id name pwd)

                1号用户

    3qqlogin2 (id name pwd)

                2号用户

    %模,求余:求余是指:一个数除以另一个数,不够除的部分就是余数,就是求余的结果

    1/2:   因为1小于212是不够除的,有余数,且余数是1

    3/2:   另外,数学中,整除是指:一个数除以另一个数,刚刚好的倍数;不够一倍的都将舍去,并不四舍五入。

    1%1:  0

    1%31

    2%32

    开发adduser.php添加用户的时候,各个用户的id应该确认下来,通常情况下我们可以使用一个辅助的表,它可以帮我们生成一个编号

    当一张越来越大时候,即使添加索引还慢的话,我们可以使用分表

    qq用户表来具体的说明一下分表的操作.

    思路如图

    首先我创建三张表 user0 / user1 /user2 , 然后我再创建 uuid表,该表的作用就是提供自增的id,

    走代码:

    create table user0(

    id int unsigned primary key ,

    name varchar(32) not null default '',

    pwd  varchar(32) not null default '')

    engine=myisam charset utf8;

    create table user1(

    id int unsigned primary key ,

    name varchar(32) not null default '',

    pwd  varchar(32) not null default '')

    engine=myisam charset utf8;

    create table user2(

    id int unsigned primary key ,

    name varchar(32) not null default '',

    pwd  varchar(32) not null default '')

    engine=myisam charset utf8;

    create table uuid(

    id int unsigned primary key auto_increment)engine=myisam charset utf8;

    编写addUser.php

    <?php

    //注册一个用户

    $con=mysql_connect("localhost","root","root");

    if(!$con){

    die("连接失败!");

    }

    mysql_select_db("temp",$con);

    $name=$_GET['name'];

    $pwd=$_GET['pwd'];

    //这时我们先获取用户id,id是从uuid表获取

    $sql="insert into uuid values(null)";

    if(mysql_query($sql,$con)){

    $id=mysql_insert_id();

    }

    //计算表名,就是,你应该把这个用户放入到哪个表

    $talname='user'.$id%3;

    $sql="insert into {$talname} values ($id,'$name','$pwd')";

    if(mysql_query($sql,$con)){

    echo '添加用户到 '.$talname.'ok';

    }

    mysql_close($con);

    //

    <?php

    //注册一个用户

    $con=mysql_connect("localhost","root","root");

    if(!$con){

    die("连接失败!");

    }

    mysql_select_db("temp",$con);

    $id=intval($_GET['id']);

    //计算表名

    $tabname='user'.$id%3;

    $sql="select pwd from {$tabname} where id=$id";

    $res=mysql_query($sql,$con);

    if($row=mysql_fetch_assoc($res)){

    echo "{$tabname}. 中发现 id号为 {$id}";

    }

    //.....

  5.  

    思考: 如果我们做的是一个平安保险公司的一个订单(8999999999000000)查询功能更.

    ,如何处理海量表?->按时间.

    我们在提供检索时,应该根据业务的需求,找到分表的标准,并在检索的页面,约束用户检索的方式(分页),如果有大表的需求也是少数

    1. 分表的标准是依赖业务逻辑(时间/地区/....)
      1. 安装字符不同. a-z
      2. 我们给用户提供的查询界面一定是有条件,不能让用户进行大范围.(世界),如果需要的可以根据不同的规则,对应多套分表.
      3. 检索时候,带分页条件,减少返回的数据.
      4. 项目中,灵活的根据需求来考虑
    2. .

      n 垂直分割

      有些表记录数并不多,可能也就23万条,但是字段却很长,表占用空间很大,检索表时需要执行大量I/O,严重降低了性能。这个时候需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系。 (JOIN)

      【试题内容】、【答案信息】两个表,最初是作为几个字段添加到【试题信息】里的,可以看到试题内容和答案这两个字段很长,在表里有3万记录时,表已经占 了1G的空间,在列试题列表时非常慢。经过分析,发现系统很多时候是根据【册】、【单元】、类型、类别、难易程度等查询条件,分页显示试题详细内容。而每 次检索都是这几个表做join,每次要扫描一遍1G的表。我们完全可以把内容和答案拆分成另一个表,只有显示详细内容的时候才读这个大表,由此 就产生了【试题内容】、【答案信息】两个表。

      示意图

    3. 一句话: 如果一张表某个字段,信息量大,但是我们很少查询,则可以考虑把这些字段,单独的放入到一张表中,这种方式称为垂直分割.

  6. 数据库的三层结构

    数据库的三层结构

    1.php程序

    2.dbms(数据库管理系统)

    3.数据库(说白来就是文件)

    php(客户端)通过数据库管理系统(dbms)操作数据库(文件)

    1php程序'select * from table'-2dbms(编译->执行->缓存)-

    存储过程:

    编译很费时间,事先把一些经常用的代码直接在数据库dbms里边编码形成一个二进制,我们直接调用,这个就是存储过程

    存储过程是已经编译好了的对象,可以调用存储过程,它不用编译,直接操作数据库文件

    常见的存储过程:分页存储过程,触发器

    存储过程的致命缺点:移植性不好

    存储过程和函数

    存储过程定义: 存储过程是用户定义的一系列sql语句的集合,涉及特定表或其它对象的任务,用户可以调用存储过程,

    函数定义:     而函数通常是数据库已定义的方法,它接收参数并返回某种类型的值并且不涉及特定用户表。

    一、总述 优缺点:存储函数和存储过程统称为存储例程(stored routine)。两者的定义语法很相似,但却是不同的内容。

    1.功能上

    x.存储函数限制比较多,比如不能用临时表,只能用表变量。还有一些函数都不可用等等。

    y.而存储过程的限制相对就比较少。存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。存储过程,功能强大,可以执行包括修改表等一系列数据库操作;用户定义函数不能用于执行一组修改全局数据库状态的操作。

    2、返回值上的不同

    存储函数将向调用者返回一个且仅返回一个结果值。

    存储过程将返回一个或多个结果集(函数做不到这一点),或者只是来实现某种效果或动作而无需返回值。

    3、调用方式上的不同

    存储函数嵌入在sql中使用的,可以在select中调用,就像内建函数一样,比如cos()hex()

    存储过程只能通过call语句进行调用

    4、参数的不同

    存储函数的参数类型类似于IN参数

    存储过程的参数类型有三种、IN参数、OUT参数、INOUT参数

    读写分离

    【核心思想】如果数据库压力很大,一台机器支撑不了,那么可以用mysql复制实现多台机器同步,将数据库的压力分散。

    负载均衡就是团队运作。为了一个共同的团队目标,位于不同位置上“队员”们在领队的统一调度下,协同工作,将大的任务相对平均地分担起来,把任务完成的更快、更好!

 

原理过程:

Php sql语句到Apache有专门处理的模块(php处理,模块),如果没有做读写分离,它该怎么处理就怎么处理,处理完反回给php;分表解决的是数据量很大的问题,快速的把数据完成,但是如果并发很大,来不及处理那么就读写分离

Dml操作:insert ,delete update

负载均衡:专门判断执行怎么样的操作,dml还是select,dml操作直奔主服务器,查询走另外的从数据库(slavel),究竟发给那个从服务器?它会不停的轮训,它有张轮训表,会记录mysql的状态和ip地址,比如从1负载30%,从2负载90%,从3百分60%,负载往往通过内存和cpu综合考虑它的值,每隔一段时间就轮训,看那个相对空闲,就让1来完成,这里边最难得是主服务器的增删改如何通知给从服务器,这里边有很多同步机制,不停的复制

原理就是在增删改后把日志记录下来,然后隔一段时间复制(insert)到从表

复制的技术有

1.mysql-proxy就是mysql代理/

2.新浪的俺爸

Master主服务器

  Slave1从服务器

  Slave2

  Slave3

主库master用来写入,slave1slave3都用来做select,每个数据库

分担的压力小了很多。

  要实现这种方式,需要程序特别设计,写都操作master,读都操作

slave,给程序开发带来了额外负担。当然目前已经有中间件来实现这个

代理,对程 序来读写哪些数据库是透明的。官方有个mysql-proxy,但是

还是alpha版本的。新浪有个amobe for mysql,也可达到这个目的,结构

如下 

mysql数据库参数配置优化,配置完重启

当然调整参数还是要看状态,用show status语句可以看到mysql当前配置状态,以决定改调整哪些参数

1.mysql端口

   port=3306/3307

   mysql_connect('localhost:3307','root','root')

2.最大连接数    一般并发数到2000就极限了,支撑10万没问题

  max_connections=100/1000

3.查询缓存大小

  query_cache_size=15M

4修改默认存储引擎

1mysql存储引擎命令,在mysql>提示符下搞入show engines;

1default为默认存储引擎

2设置默认存储引擎default-storage-engine=INNODB

5.最重要的参数就是内存,我们主要用的innodb引擎,所以下面两个参数调的很大

 innodb_additional_mem_pool_size = 64M

  

  innodb_buffer_pool_size =1G

6 对于myisam,需要调整,可以调大,一半增加10

  key_buffer_size

  指定索引缓冲区的大小,它决定索引处理的速度,尤其是索引读的速度

3查询缓存:

MYSQL的查询缓存用于缓存select查询结果,并在下次接收到同样的查询请求时,不再执行实际查询处理而直接返 回结果,有这样的查询缓存能提高查询的速度,使查询性能得到优化,前提条件是你有大量的相同或相似的查询,而很少改变表里的数据,否则没有必要使用此功 能。可以通过Qcache_lowmem_prunes变量的值来检查是否当前的值满足你目前系统的负载。注意:如果你查询的表更新比较频繁,而且很少有 相同的查询,最好不要使用查询缓存。

具体配置方法:

1. query_cache_size设置为具体的大小,具体大小是多少取决于查询的实际情况,但最好设置为1024的倍数,参考值32M

2. 增加一行:query_cache_type=1

query_cache_type参数用于控制缓存的类型,注意这个值不能随便设置,必须设置为数字,

可选项目以及说明如下:

如果设置为0,那么可以说,你的缓存根本就没有用,相当于禁用了。但是这种情况下query_cache_size设置的大小系统是否要为其分配呢,这个问题有待于测试?

如果设置为1,将会缓存所有的结果,除非你的select语句使用SQL_NO_CACHE禁用了查询缓存。如果设置为2,则只缓存在select语句中通过SQL_CACHE指定需要缓存的查询。

OK,配置完后的部分文件如下:

query_cache_size=128M

query_cache_type=1

保存文件,重新启动MYSQL服务,然后通过如下查询来验证是否真正开启了:

mysql> show variables like ‘%query_cache%’;

实际的查询中是否能够缓存查询,还需要手动测试下,我们可以通过show status like ‘%Qcache%’;语句来测试,

Innodb表:

innodb_additional_mem_pool_size = 64M

这个参数用来设置 InnoDB 存储的数据目录信息和其它内部数据结构的内存池大小。应用程序里的表越多,你需要在这里分配越多的内存。对于一个相对稳定的应用,这个参数的大小也是相对稳定的,也没有必要预留非常大的值。如果 InnoDB 用光了这个池内的内存, InnoDB 开始从操作系统分配内存,并且往 MySQL 错误日志写警告信息。默认值是 1MB ,当发现错误日志中已经有相关的警告信息时,就应该适当的增加该参数的大小

innodb_buffer_pool_size=128M

作用:

这个参数主要作用是缓存innodb表的索引,数据,插入数据时的缓冲

专用mysql服务器设置的大小: 操作系统内存的70%-80%最佳。

设置方法:my.cnf文件

innodb_buffer_pool_size = 6G

此外,这个参数是非动态的,要修改这个值,需要重启mysqld服务。所以设置的时候要非常谨慎。并不是设置的越大越好。设置的过大,会导致systemswap空间被占用,导致操作系统变慢,从而减低sql查询的效率。

myisam

 key_buffer_size

mysql数据库中,mysql key_buffer_size是对MyISAM表性能影响最大的一个参数,下面就将对mysql Key_buffer_size参数的设置进行详细介绍,供您参考。下面一台以MyISAM为主要存储引擎服务器的配置:
mysql> show variables like 'key_buffer_size';
+-----------------+------------+
| Variable_name | Value |
+-----------------+------------+
| key_buffer_size | 536870912 |
+-----------------+------------+
分配了512MB内存给mysql key_buffer_size,我们再看一下key_buffer_size的使用情况:
mysql> show global status like 'key_read%';
+------------------------+-------------+
| Variable_name | Value |
+------------------------+-------------+
| Key_read_requests | 27813678764 |
| Key_reads | 6798830 |
+------------------------+-------------+
一共有27813678764个索引读取请求,有6798830个请求在内存中没有找到直接从硬盘读取索引,计算索引未命中缓存的概率:

key_cache_miss_rate = Key_reads / Key_read_requests * 100%

比如上面的数据,key_cache_miss_rate为0.0244%,4000个索引读取请求才有一个直接读硬盘,已经很BT了,key_cache_miss_rate在0.1%以下都很好(每1000个请求有一个直接读硬盘),如果key_cache_miss_rate在0.01%以下的话,key_buffer_size分配的过多,可以适当减少。
MySQL服务器还提供了key_blocks_*参数:
mysql> show global status like 'key_blocks_u%';
+------------------------+-------------+
| Variable_name | Value |
+------------------------+-------------+
| Key_blocks_unused | 0 |
| Key_blocks_used | 413543 |
+------------------------+-------------+
Key_blocks_unused表示未使用的缓存簇(blocks)数,Key_blocks_used表示曾经用到的最大的blocks数,比如这台服务器,所有的缓存都用到了,要么增加key_buffer_size,要么就是过渡索引了,把缓存占满了。比较理想的设置:
Key_blocks_used / (Key_blocks_unused + Key_blocks_used) * 100% ≈ 80%

Mysql的增量备份

Mysql增量备份:

1.增量备份会记录的语句dml,创建表的语句,但是不会记录select语句,

2.记录的是 A.操作本身;    B.操作的时间;    C position;

注意事项:

增量备份只会记录当天对数据库的操作,

实际案例 如何备份,如何恢复步骤:

1』    配置mysql.ini或者mysql.cof中启用二进制备份,在my.ini中加下

log-bin=d:/binlog/mylog 

自定义目录, 自定义文件名xxx   

//到时候它自己会不停地以xxx+00001      

2』    重新启动记录下如下文件(二进制文件)备份并查看

d:/binlog/mylog/mylog.index索引文件,有哪些增量备份分文件

d:/binlog/mylog/mylog.000001存放用户对数据操作的文件

 

可以使用mysqlbinlog程序查看备份文件的内容:

 

C:Documents and SettingsAdministrator>Cd C:imysql5in

也可以把这个加到环境变量里

 

C:imysql5in>mysqlbinlog d:iwwwinlogmylog.000001

End_log_pos:位置

SET TIMESTAMP=1435642438/*!*/;   执行的时间

SET INSERT_ID=2/*!*/;

insert into red(background)values( 'red')做了什么事情

commit结束

依据位置和时间恢复,所以一定要看懂位置和时间,到commit结束

每一个操作都有位置和时间

3』  数据恢复

增量备份实际操作过程:

cd C:imysql5in

mysqlbinlog --stop-position=”211  d:/binlog/mylog.000001  |  mysql -uroot -p

备份 --从备份文件开始到此   备份的文件路径         竖mysql 用户密码    

时间点恢复

①  mylog.000001文件开始的地方到2015-06-30 14:22:29时间结束

mysqlbinlog --stop-datetime="2015-06-30 14:22:29" d:/binlog/mylog.000001 | mysql -uroot –p

 

②  2013-01-14 00:55:55这个时间开始

mysqlbinlog --start-datetime="2013-01-14 00:55:55" d:/binlog/mylog.000001 | mysql -uroot -p

  mylog.000001文件中从211位置-311位置之间

mysqlbinlog --start-datetime="" --stop-position="" d:/binlog/mylog.000001 | mysql -uroot -p

 

位置恢复

① mylog.000001文件开始的地方到21114位置结束

mysqlbinlog --stop-position="21114" d:/binlog/mylog.000001 | mysql -uroot -p

 

② 211开始

mysqlbinlog --start-position="211" d:/binlog/mylog.000001 | mysql -uroot -p

 

③   mylog.000001文件中从211位置-311位置之间

mysqlbinlog --start-position="211" --stop-position="311" d:/binlog/mylog.000001 | mysql -uroot –p

 

 

 

 

./etc/my.cnf 下面设置开启bin-log

mysql> reset master;清空日志

         编辑

         vim /etc/my.cnf 或者my.ini

         [mysqld]

         binlog_format       = MIXED                 //binlog日志格式

         log_bin             =目录/mysql-bin.log     //binlog日志名

log-bin=d:/binlog/mylog 

         expire_logs_days    = 7                     //binlog过期清理时间

         max_binlog_size    100m                    //binlog每个日志文件大小 最大值和默认是1个G

 

binlog-do-db=game     #需要备份的数据库名,如果备份多个数据库,重复设置这个选项即可

 

         binlog-do-db=platform #

.创建远程登陆数据库帐号

         grant all privileges on game.* to 'jack'@'192.168.10.56' identified by 'admin'

         grant all privileges on platform.* to 'jack'@'192.168.10.56' identified by 'admin'

3.将服务器上的数据,导入一份进远程服务器中

         mysqldump -ujack -padmin -h192.168.10.38 > 备份数据库地址(/home/mysql/db/mysql.sql);

4.写Linux 计划任务:

         vim /etc/crontab

在底部加入

         0 3 * * * root sh /home/wwwroot/sh/mysqlbackup.sh #每天3点以root帐号的权限执行目录下的sh

重启服务

         /etc/init.d/crond restart

---------------------------------------------------

如果遇到了问题,请查看一下

select super_priv,user from user where host='192.168.10.39';

update user set super_priv='Y' where user='game1';

 

如何在工作中将全备份和增量备份全部使用

方案:

每周1做一个全备份mysqldump,启用增量备份,把过期时间至少设置为大于等于7-,增量备份不用定时器,你只要操作它就会记录下过程,如果出现数据库崩溃,如果数据库没了用全备份,在增量备份,如果某几张表数据没了,就增量备份(增量须看增量日志)

 

 

         #binlog-ignore-db=不需要备份的数据库,如果备份多个数据库,重复设置这个选项即可

 

原文地址:https://www.cnblogs.com/finddata/p/11080577.html