标签:
mysql优化技术
?
前面我们讲的页面静态化,memcached是通过减少对mysql操作来提示访问速度,提高大并发,但是一个网站总是要操作数据库,这时我们如何提示对mysql操作的速度.
我们的表要满足两个条件: 1。表的属性(列)要具有原子性(不可分割)2: 表不能有重复的列, 只要是关系型数据库,就天然的满足1NF
关系型数据库: mysql , sql server, oracle , informix , db2, postgresql
非关系型数据: 面向对象和集合
nosql数据库: mongodb[面向文档.]
表要满足: 不能存在完全相同的两条记录, 通常是通过设置一个主键来实现. 主键一般是非业务逻辑主键.
表中不能存在冗余数据. 表的列的值,如果可过通过显示推导或者隐式的推导出,则就不应该设置该列.
举例
在实际开发,我们遵守 3NF, 但是有时处于效率的考虑,我们也可能用的反3NF,举例
如何快速把一个项目中有问题的sql语句定位,然后在优化。
create database temp;
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)
returns varchar(255) #该函数会返回一个字符串
begin
#定义了一个变量 chars_str, 类型 varchar(100)
#默认给 chars_str 初始值 ‘abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ‘
declare chars_str varchar(100) default
‘abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ‘;
declare return_str varchar(255) default ‘‘;
declare i int default 0;
while i < n do
# concat 函数 : 连接函数
set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i = i + 1;
end while;
return return_str;
end $$
?
#这里我们又自定了一个函数,返回一个随机的部门号
create function rand_num( )
returns int(5)
begin
declare i int default 0;
set i = floor(10+rand()*500);
return i;
end $$
?
#随即添加雇员 max_num条 ,雇员的编号从 start
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 0;
#set autocommit =0 把autocommit设置成0
#autocommit = 0 含义: 不要自动提交
set autocommit = 0; #默认不提交sql语句
repeat
set i = i + 1;
#通过前面写的函数随机删除字符和数组来添加不同记录到 emp表
insert into emp values ((start+i) ,rand_string(6),‘SALESMAN‘,0001,curdate(),2000,400,rand_num());
until i = max_num
end repeat;
#commit整体提交所有sql语句,提高效率
commit;
end $$
?
#调用刚刚写好的函数, 4000000条记录,从100001号开始
call insert_emp(100001,4000000);
在默认情况下,mysql不会记录慢查询语句. , 在默认情况下,慢查询的时间是10s.
show variables like ‘long_query_time‘;
{%mysql%}>bin/mysqld.exe --safe-mode --slow-query-log
先把mysql关闭后,再重启
#Path to the database root
datadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/"
set long_query_time=1;
这里给大家介绍一款工具 explain 工具,可以帮助我们分析mysql数据库在执行一个sql语句的时候,是安装什么方式执行[获得关于MySQL如何执行SELECT语句的信息].
explain sql\G
explain select * from emp where empno=347677\G
?
在empno 这个字段上创建主键索引
alter table 表名 add primary key(列名,列名...)
alter table emp add primary key (empno);
创建完索引后,我们发现索引文件变大了,这说明索引有开销,要占用磁盘空间.
占用跟多的磁盘空间
对dml(update ,insert , delete )速度有影响
?
主键索引创建有两种情况, 1. 在创建表的时候,直接指定主键索引 2. 创建表后,在增加主键索引.
举例
alter table bbb add primary key(id);
主键索引的特点1. 一个表中最多只有一个主键索引 2. 一个主键索引可以指向多列 3. 主键索引的列,不能有重复的值,也不能有null 4. 主键索引的效率高
唯一索引的创建有两种情况: 1. 在创建表时,直接指定唯一索引, 2. 把表创建完后,在指定唯一索引.
举例:
添加索引方法有两种
create unique index uni_email on eee(email);
alter table eee add unique (email );
唯一索引的特点: 1. 一个表中可以有多个唯一索引 2. 一个唯一索引可以指向多列 3. 如果你在唯一索引上,没有指定not null ,则该列可以为空,同时可以有多个null
一般说,是创建好表后,在指定普通索引,举例:
create table fff(id int primary key auto_increment, name varchar(32) not null default ‘‘,email varchar(64) not null default ‘‘);
添加普通索引方法两个
create index inx_email on fff(email);
mysql自带的全文索引mysql5.5不支持中文, 支持英文,同时要求表的存储引擎是myisam。如果希望支持中文,有两个方案 1. 使用sphinx中文版 coreseek 2. 插件mysqlcft.
创建一张表
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 ‘% database %‘; [这样没有使用到索引]
SELECT * FROM articles WHERE MATCH (title,body) AGAINST (‘database‘)[ok]
全文索引有两个概念[匹配度,停止词]
匹配度: 在使用全文索引去检索数据,匹配到的概率是多大.
????
停止词: 全文索引对非常普通的词,不会创建索引.
删除索引,再创建.
?
drop index索引名 on 表名;
alter table 表名 drop index 索引名 ;
主键删除
alter table 表名 drop primary key;
? 如果你在删除主键索引时,该主键是自增的,则需要先去掉自增属性,然后在干掉.
create table ttt( id int unsigned primary key auto_increment , name varchar(32) not null default ‘‘);
先去掉auto_increment;
alter table 表名 modify 列定义;
(1)alter table ttt modify id int unsigned;
(2) alter table ttt drop primary key;
?
有了索引后,我们要正确的使用索引,需要注意的地方如下,为了说清这个问题,我们在 dpet表中添加数据,做测试.
默认情况,MySQL对所有的group by col1,col2进行排序。这与在查询中指定order by col1, col2类似。如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止排序
?
如何选择mysql的存储引擎
表以读和写为主,有少量的删除和修改 ,同时对事务要求不高(比如帖子,公共聊天)
表对事务要求高,比如(账号, 积分)
如果没有memcached或者redis, 但是数据操作频繁,可以考虑使用memory存储引擎,比如好友在线状态。
mysql> create table userstat (id int primary key auto_increment,state tinyint no
t null default 0)engine=memory charset utf8;
说明: memory表的数据都在内存中,因此操作速度快,但是缺少是当mysql重启后,数据丢失,但表的结构在.
对于myisam存储引擎而言,我们需要定时执行 optimize table 表名;
举例:
我们在mysql中存放日期时,可以存放数 (int...) 而int可以存放的数据最大为4294967295, 当php中要显示一个大于2038年日期,该如何处理?
2k28.php
概述: 当一个表很大时,比如200G, 这是太大,这时我只靠创建索引也不好搞定,这时我们需要分表和分区. 分表有两种形式(水平分表,垂直分表), 分区技术(按时间).
核心思想: 把一个大表,分割N个小表,小表和大表的结构是一样一样的,只是把数据分散到不同表中,举例:
?
示意图:
创建数据库
mysql> create table uuid(id int unsigned primary key auto_increment);
mysql> create table qq_user0(id int unsigned primary key, name varchar(32) not n
ull default ‘‘, pwd char(32) not null default ‘‘,email varchar(64) not null defa
ult ‘‘);
create table qq_user1 like qq_user0;
create table qq_user2 like qq_user0;
代码: register.php
login.php
对代码思考,如果我们需要通过邮件或者用户名登陆,又怎么处理?
思路:
这里推出一个的算法把md5值转成一个10进制数据
当有一个表中,存在这样字段,1数据量大,2. 很少被查询, 我们可以把这样的字段单独分割取出,放入到另外一张表,然后通过id关联
把一个海量表的数据分散到不同的磁盘,从而提速, 举一个案例
上面的情况特别适合使用时间来分区.
CREATE TABLE part_balance
(
id int default NULL,
name varchar(30) default NULL,
savetime date default NULL
) engine=myisam
PARTITION BY RANGE (year(savetime)) (PARTITION p0 VALUES LESS THAN (1995),
PARTITION p1 VALUES LESS THAN (1996) ,
PARTITION p2 VALUES LESS THAN (1997) ,
PARTITION p3 VALUES LESS THAN (1998) ,
PARTITION p4 VALUES LESS THAN (1999) ,
PARTITION p5 VALUES LESS THAN (2000) ,
PARTITION p6 VALUES LESS THAN (2001) ,
PARTITION p7 VALUES LESS THAN (2002) ,
PARTITION p8 VALUES LESS THAN (2003) ,
PARTITION p9 VALUES LESS THAN (2004) ,
PARTITION p10 VALUES LESS THAN (2010),
PARTITION p11 VALUES LESS THAN MAXVALUE );
?
#普通表
create table no_part_balance
(
id int default NULL,
name varchar(30) default NULL,
savetime date default NULL
) engine=myisam;
?
create function rand_string(n INT)
returns varchar(255) #该函数会返回一个字符串
begin
#定义了一个变量 chars_str, 类型 varchar(100)
#默认给 chars_str 初始值 ‘abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ‘
declare chars_str varchar(100) default
‘abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ‘;
declare return_str varchar(255) default ‘‘;
declare i int default 0;
while i < n do
# concat 函数 : 连接函数
set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i = i + 1;
end while;
return return_str;
end $$
?
CREATE PROCEDURE add_tab()
begin
declare v int default 0;
while v < 2000
do
insert into part_balance values (v,rand_string(10),adddate(‘1995-01-01‘,(rand(v)*36520) mod 3652));
set v = v + 1;
end while;
end$$
?
?
--执行
delimiter ;
call add_tab();
insert into no_part_balance select * from part_balance;
--执行看看时间如何,结论分区表的时间要短很多.
select count(*) from no_part_balance where savetime > ‘1995-01-01‘ and savetime < ‘1995-12-31‘;
select count(*) from part_balance where savetime > ‘1995-01-01‘ and savetime < ‘1995-12-31‘;
--使用explain 看看mysql是如何执行的
explain partitions select count(*) from no_part_balance where savetime > ‘1995-01-01‘ and savetime < ‘1995-12-31‘\G
explain partitions select count(*) from part_balance where savetime > ‘1995-01-01‘ and savetime < ‘1995-12-31‘\G
--增加未索引字段查询
select count(*) from part_balance where savetime > ‘1995-01-01‘ and savetime < ‘1996-12-31‘ and name=‘hello‘;
select count(*) from no_part_balance where savetime > ‘1995-01-01‘ and savetime < ‘1996-12-31‘ and name=‘hello‘;
--查询数据本身,得出结论也是分区表快
select * from part_balance where savetime = ‘1995-01-03‘;
select * from no_part_balance where savetime = ‘1995-01-03‘
在PHP网站运行中,我们经常会有对网站的维护操作,需要定时反复执行,比如定时备份数据库, 定时碎片整理, 等等 。
举一个具体案例,需要在每天凌晨2:00备份temp数据库中的dept表.
cmd>mysqldump.exe –u root –p密码 temp dept > d:/dept.bak;
C:\myenv\mysql\bin\mysqldump.exe -uroot -proot temp dept > d:/dept.bak
具体配置看一下视频.
?
mytask.php
mytask.bat
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文件
?
?
?
?
标签:
原文地址:http://www.cnblogs.com/yizhinageyuanfang/p/5519389.html