Chinaunix首页 | 论坛 | 博客
  • 博客访问: 210509
  • 博文数量: 45
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 444
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-11 12:23
文章分类

全部博文(45)

文章存档

2017年(1)

2016年(14)

2014年(30)

我的朋友

分类: Mysql/postgreSQL

2014-03-11 12:43:28

u       Mysql数据库的优化技术

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

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

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

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

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

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

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

g: mysql服务器硬件升级

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

 

 

u       什么样的表才是符合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:

3.       使用方法是 match(字段名..) against(‘关键字’)

4.       全文索引一个 叫 停止词因为在一个文本中,创建索引是一个无穷大的数,因此,对一些常用词和字符,就不会创建,这些词,称为停止词.

 

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 表名 (列表..);

 

 

 

2.       查询索引

 

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

show index(es) from 表名

show keys from 表名

 

3.       删除

 

alter table 表名 drop index 索引名;

 

如果删除主键索引。

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

 

 

 

4.       修改

 

先删除,再重新创建.

 

 

 

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

 

原理示意图:

 

.

 

u       索引使用的注意事项

 

索引的代价:

1.       占用磁盘空间

2.       dml操作有影响,变慢

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

 

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

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

 

 

u       使用索引的注意事项

 

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

 

alter table dept add index my_ind (dname,loc); //  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.

 

3.       如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引, 我们建议大家尽量避免使用or 关键字

 

select * from dept where dname=’xxx’ or loc=’xx’ or deptno=45

 

4.       如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须’’), 也就是,如果列是字符串类型,就一定要用 ‘’ 把他包括起来.

 

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

 

 

 

 

 

 

 

 

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

 

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

show status like ‘Handler_read%’;

 

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

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

 

 

u       sql语句的小技巧

 

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

 

比如:

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

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

 

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

 

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

 

u       如何选择mysql的存储引擎

 

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

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

 

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

 

 

MyISAM INNODB的区别

1. 事务安全

2. 查询和添加速度

3. 支持全文索引

4. 锁机制

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

 

 

 

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

 

 

 

 

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

 

举例说明:

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’);

 

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

optimize table test100;

 

mysql_query(“optimize tables $表名”);

 

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

 

 

 

 

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

 

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

 

cmd控制台:

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

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

mysqldump –u root –proot temp > d:\temp.bak

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

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

 

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

mysql控制台

source d:\temp.dept.bak

 

②     使用定时器来自定完成

 

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

 

mytask.bat 内容是:

C:\myenv\mysql5.5.27\bin\mysqldump -u root -proot temp dept > d:\temp.dept.bak

 

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

 

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

 

 

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

 

 

测试ok

 

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

 

 

代码是:

mytask2.bat 内容:

C:\myenv\php-5.3.5\php.exe C:\myenv\apache\htdocs\mytask.php

mytask.php代码:

 

 

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

      

       date_default_timezone_set('PRC');

 

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

 

      

       $command="C:\myenv\mysql5.5.27\bin\mysqldump -u root -proot temp dept > d:\\{$bakfilename}";

 

       exec($command);

 

最后测试ok!

 

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

 

 

u       使用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

 

 

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

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

 

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

1.       本身机器是可以联网的

2.       需要搭建自己的smtp邮件服务器->示意图

 

3.       搭建自己的邮件服务器.

 

卸载.

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

配置 :

3.1选择access数据库

3.2

3.3配置邮件服务器

 

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

 

点击设置->服务器设置

设置一个账号(试用版本只能设置5个账号)

 

代码:

 

// 练习用PHPmailer发送邮件

 

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

 

$mailer = new PHPMailer();

 

/*

from 来自于谁

to :寄给谁

cc : 抄送

 

subject: 邮件主题

Body: 邮件正文

 

// 发送怎么发 ?

 

*/

 

 

$cont = <<

    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 启用账号

 

[mail function]

; For Win32 only.

;

SMTP = localhost

; -port

smtp_port = 25

 

; For Win32 only.

;

sendmail_from =lsk

 

测试一把 成功!

 

 

如何在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

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

# crontab -e

00 * * * * /usr/bin/curl -o temp.txt

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

# crontab -e

00 * * * * lynx -dump

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

 

 

n         分表技术

 

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

 

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

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

 

       //注册一个用户

       $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);

      

//

 

       //注册一个用户

       $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}";

       }

 

       //.....

 

 

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

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

1.       分表的标准是依赖业务逻辑(时间/地区/....)

2.       安装字符不同. a-z

3.       我们给用户提供的查询界面一定是有条件,不能让用户进行大范围.(世界),如果需要的可以根据不同的规则,对应多套分表.

4.       检索时候,带分页条件,减少返回的数据.

5.       项目中,灵活的根据需求来考虑.

 

 

n         垂直分割

 

示意图:

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

 

 

 

 

 

 

 

 

 

阅读(1202) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Thinkphp常用配置

给主人留下些什么吧!~~