上面这个就是不合适的冗余,原因是:
在这里,为了提高学生活动记录的检索效率,把单位名称冗余到学生活动记录表里。单位信息有500条记录,而学生活动记录在
一年内大概有200万数据量。 如果学生活动记录表不冗余这个单位名称字段,只包含三个int字段和一个timestamp字段,只占用了16字节,是一个很小的表。而冗余了一个 varchar(32)的字段后则是原来的3倍,检索起来相应也多了这么多的I/O。而且记录数相差悬殊,500 VS 2000000 ,导致更新一个单位名称还要更新4000条冗余记录。由此可见,这个冗余根本就是适得其反。
订单表里面的Price就是一个冗余字段,因为我们可以从订单明细表中统计出这个订单的价格,但是这个冗余是合理的,也能提升查询性能。
从上面两个例子中可以得出一个结论:
1---n 冗余应当发生在1这一方.
SQL语句优化
SQL优化的一般步骤
1.通过show status命令了解各种SQL的执行频率。
2.定位执行效率较低的SQL语句-(重点select)
3.通过explain分析低效率的SQL
4.确定问题并采取相应的优化措施
-- select语句分类SelectDml数据操作语言(insert update delete)dtl 数据事物语言(commit rollback savepoint)Ddl数据定义语言(create alter drop..)Dcl(数据控制语言) grant revoke-- Show status 常用命令--查询本次会话Show session status like "com_%"; //show session status like "Com_select"--查询全局Show global status like "com_%";-- 给某个用户授权grant all privileges on *.* to "abc"@"%";--为什么这样授权 "abc"表示用户名 "@" 表示host, 查看一下mysql->user表就知道了--回收权限revoke all on *.* from "abc"@"%";--刷新权限[也可以不写]flush privileges;SQL语句优化-show参数
show status like "Connections"show status like "Uptime"show status like "Slow_queries"如何查询mysql的慢查询时间
Show variables like "long_query_time";修改mysql 慢查询时间
set long_query_time=2SQL语句优化-定位慢查询
show variables like "long_query_time" ; //可以显示当前慢查询时间set long_query_time=1 ;//可以修改慢查询时间构建大表->大表中记录有要求, 记录是不同才有用,否则测试效果和真实的相差大.创建:
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);
create function rand_string(n INT) 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创建一个存储过程
create procedure insert_emp(in start int(10),in max_num int(10))begindeclare i int default 0; #set autocommit =0 把autocommit设置成0set autocommit = 0; repeatset i = i + 1;insert into emp values ((start+i) ,rand_string(6),"SALESMAN",0001,curdate(),2000,400,rand());until i = max_numend repeat;commit;end #调用刚刚写好的函数, 1800000条记录,从100001号开始call insert_emp(100001,4000000);这时我们如果出现一条语句执行时间超过1秒中,就会统计到.
[mysqld]# The TCP/IP Port the MySQL Server will listen onport=3306slow-query-log通过慢查询日志定位执行效率较低的SQL语句。慢查询日志记录了所有执行时间超过long_query_time所设置的SQL语句。
show variables like "long_query_time";set long_query_time=2;为dept表添加数据
desc dept;ALTER table dept add id int PRIMARY key auto_increment;CREATE PRIMARY KEY on dept(id);create INDEX idx_dptno_dptname on dept(deptno,dname);INSERT into dept(deptno,dname,loc) values(1,"研发部","康和盛大厦5楼501");INSERT into dept(deptno,dname,loc) values(2,"产品部","康和盛大厦5楼502");INSERT into dept(deptno,dname,loc) values(3,"财务部","康和盛大厦5楼503");UPDATE emp set deptno=1 where empno=100002;****测试语句***[对emp表的记录可以为3600000 ,效果很明显慢]
select * from emp where empno=(select empno from emp where ename="研发部")如果带上order by e.empno 速度就会更慢,有时会到1min多.
select * from emp e,dept d where e.empno=100002 and e.deptno=d.deptno;查看慢查询日志:默认为数据目录data中的host-name-slow.log。低版本的mysql需要通过在开启mysql时使用- -log-slow-queries[=file_name]来配置
Explain select * from emp where ename=“wsrcla”会产生如下信息:
explain select * from emp where ename="JKLOIP"
如果要测试Extra的filesort可以对上面的语句修改
explain select * from emp order by enameGEXPLAIN详解
SELECT * FROM emp WHERE empno = 1 and ename = (SELECT ename FROM emp WHERE empno = 100001) G;select_type
SELECT * FROM emp G
SELECT * FROM (SELECT * FROM emp WHERE empno = 1) a ;system:表仅有一行(=系统表)。这是const联接类型的一个特