优化MySQL数据库是数据库管理员的必备技能。通过不同的优化方式达到提高MySQL数据库性能的目的。
MySQL 数据库的用户和数据非常少的时候,很难判断一个MySQL数据库的性能的好坏。只有当长时间运行,并且有大量用户进行频繁操作时,MySQL数据库的性能 就会体现出来了。例如,一个每天有几百万用户同时在线的大型网站的数据库性能的优劣就很明显。这么多用户在线的连接MySQL数据库,并且进行查询、插 入、更新的操作。如果MySQL数据库的性能很差,很可能无法承受如此多用户同时操作。试想用户查询一条记录需要花费很长时间,用户很难会喜欢这个网站。
SHOW STATUS LIKE 'value';
show status like 'connections';
show status like 'Com_select';
18.2 优化查询
18.2.1 分析查询语句
通过对查询语句的分析,可以了解查询语句的执行情况。MySQL中,可以使用explain语句和describe语句来分析查询语句。
explain select语句;
通过explain关键字可以分析后面的select语句的执行情况。并且能够分析出所查询的表的一些内容。
explain select * from mysql.user;
describe select * from mysql.user;
id: # select语句的编号
select_type:# select语句类型 simple(不包括连接查询和子查询)
table: student # 表
type: # 连接的类型
possible_keys:
key:
key_len:
ref:
rows:
Extra:
18.2.2 索引对查询速度的影响
索引可以快速的定位表中的某条记录。使用索引可以提高数据库查询的速度,从而提高数据库的性能。
如果查询时不使用索引,查询语句将查询表中的所有字段。这样查询的速度会很慢。如果使用索引进行查询,查询语句只查询索引字段。这样可以减少查询的记录数,达到提高查询速度的目的。
explain select * from student where name="张三" \G
create index idx_name on student(name);
explain select * from student where name="张三" \G
18.2.3 使用索引查询
索引可以提高查询的速度。但是有些时间即使查询时使用的是索引,但索引并没有起作用。
1. 查询语句中使用LIKE关键字
explain select * from student where name like '%四' \G
explain select * from student where name like '李%' \G
使用like关键字的时候索引字段的搜索必须开头必须有值开始
2. 查询语句中使用多列索引
使用第一个索引字段的时候才会起作用
create index idx_birth_depart on student(birth,department);
explain select * from student where birth > 1990;
explain select * from student where department like '中文%';
3. 查询语句中使用OR关键字
两个字段都有索引的时候索引查询,其中一个字段没有索引时不会使用索引查询。
explain select * from student where name="张三" or gender="女" \G
explain select * from student where name="张三" or id=905 \G
18.2.4 优化子查询
很 多查询中需要使用子查询。子查询可以使查询语句很灵活,但子查询的执行效率不高。子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表。然后 外层查询语句再临时表中查询记录。查询完毕后,MySQL需要撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比较大,这种影响就 会随之增大。在MySQL中可以使用连接查询来替代子查询。连接查询不需要建立临时表,其速度比子查询要快。
18.3 优化数据库结构
数据库结构是否合理,需要考虑是否存在冗余、对表的查询和更新的速度、表中字段的数据类型否合理等多方面的内容。
18.3.1 将字段很多的表分解成多个表
有些表在设置时设置了很多的字段。这个表中有些字段的使用频率很低。当这个表的数据量很大时,查询数据的速度就会很慢。
对于这种字段特别多且有些字段的使用频率很低的表,可以将其分解成多个表。
create table student_extra(
id int primary key,
extra varchar(255)
);
select * from student,student_extra where studnet.id=student_extra.id;
18.3.2 增加中间表
有时候需要经常查询某两个表中的几个字段。如果经常进行联表查询,会降低MySQL数据库的查询速度。对于这种情况,可以建立中间表来提高查询速度。
先分析经常需要同时查询哪几个表中的哪些字段。然后将这些字段建立一个中间表,并从原来那几个表将数据插入到中间表中。之后就可以使用中间表来进行查询和统计了。
desc student;
desc score;
create table temp_score(
id int not null,
name varchar(20) not null,
grade float
) default charset=utf8;
insert into temp_score select student.id,student.name,score.grade from student,score where student.id=score.stu_id;
18.3.3 增加冗余字段
设计数据库表的时候尽量让表达到三范式。但是,有时候为了提高查询速度,可以有意识的在表中增加冗余字段。
表 的规范化程序越高,表与表之间的关系就越多。查询时可能经常需要多个表之间进行连接查询。而进行连接操作会降低查询速度。例如,学生的信息存储在 student表中,院系信息存储在department表中,通过student表中的dept_id字段与department表建立关联关系。如果 要查询一个学生所在系的名称,必须从student表中查找学生所在院系的编号(dept_id),然后根据这个编号去department查找系的名 称。如果经常需要进行这个操作时,连接查询会浪费很多的时候。因此可以在student表中增加一个冗余字段dept_name,该字段用来存储学生所在 院系的名称。这样就不用每次都进行连接操作了。
18.3.4 优化插入记录的速度
插入记录时,索引、惟一性校验都会影响到插入记录的速度。而且,一次插入多条记录和多次插入记录所耗费的时间是不一样的。根据这些情况,分别进行不同的优化。
1. 禁用索引
插入记录的时候,MySQL会根据对表的索引插入的数据进行排序。如果插入大量数据的时候,这些排序会会降低插入数据的速度。为这解决这个问题,首先插入数据之前先关闭当前表的索引,等数据插入完毕之后再开启索引。
ALTER TABLE 表名 disable keys;# 禁用当前表的索引
ALTER TABLE 表名 enable keys;# 开启当前表的索引
2. 禁用惟一性检查
插入数据的时候,会检测数据的唯一性校验这会降低大量数据的插入速度。
#禁用惟一性检查
set unique_checks=0;
# 开启惟一性检查
set unique_checks=1;
3. 优化insert语句
1.一次性插入多条语句(减少数据库连接,速度更优)
2.多次插入语句(相对慢)
18.4 分析表、检查表和优化表
分析表主要作用是分析关键字的分布。
检查表主要作用是检查表是否存在错误。
优化表主要作用是消除删除或者更新造成空间浪费。
18.4.1 分析表
使用analyze语句的时候对当前表进行只读锁,在分析表的时候只能读取数的数据,不能更新他插入记录。能够分析InnoDb和MyISAM类型的表。
ANALYZE TABLE 表名1[,表名2...];
analyze table score;
TableOpMsg_typeMsg_text
test.scoreanalyzestatusOK
Op:
analyze
check
optimize
Msg_type:
status(状态)
warnings(警告)
error(错误)
18.4.2 检查表(包括视图表)
CHECK TABLE 表名1[,表名2...][options]
options:只适用于MyISAM类型,且只读锁
CHECK TABLE score;
18.4.3 优化表
适用于引擎类型:InnoDB和MyISAM
适用于数据类型:varchar、blob和text类型的字段
只读锁
OPTIMIZE table 表名1[,表名2...]
optimize table score;
18.5 优化MySQL服务器
优化MySQL服务器可以从两个方面来理解。一个是从硬件方面来进行优化。另一个是从MySQL服务的参数进行优化。通过这些优化方式,可以提供MySQL的运行速度。但是这部分的内容很难理解,一般只有专业的数据库管理员才能进行这一类的优化。
18.5.1 优化服务器硬件
服务器的硬件性能直接决定着MySQL数据库的性能。例如,增加内存和提高硬盘的读写速度,这能够提高MySQL数据库的查询、更新的速度。
随 着硬件技术的成熟、硬件的价格也随之降低。现在普通的个人电话都已配置了2G内存,甚至一些个人电脑配置4G内存。因为内存的读写速度比硬盘的读写速度 快。可以在内存中为MySQL设置更多的缓冲区,这样可以提高MySQL访问的速度。如果将查询频率很高的记录存储在内存中,那查询速度就会很快。
如 果条件允许,可以将内存提高到4G。并且选择my-innodb-heavy-4G.ini作为MySQL数据库的配置文件。但是,这个配置文件主要支持 InnoDB存储引擎的表。如果使用2G内存,可以选择my-huge-ini作为配置文件。而且,MySQL所在的计算机最好是专用数据库服务器。这样 数据库可以完全利用该机器的资源。
18.5.2 优化MySQL的参数
内存中会为MySQL保留部分的缓存区。这些缓存区可以提高MySQL数据库的处理速度。缓存区的大小都是在MySQL的配置文件中进行设置的。
MySQL中比较重要的配置参数都在my.cnf或者my.ini文件[mysqld]组中。
innodb_buffer_pool_size=36M
18.6 本章实例
(1)查看InnoDB表的查询的记录数和更新的记录数。
show status like 'Innodb_rows_read' \G
show status like 'Innodb_rows_updated' \G
(2)分析查询语句的性能,select语句如下:
explain select * from score where stu_id=902 \G
analyze table score;
18.7 上机实践
(1)查看MySQL服务器的连接数、查询次数和慢查询的次数
show status like 'Connections';
show status like 'Com_select';
show status like 'Slow_queries';
(2)检查score表
check table score;
(3)优化score表
optimize table socre;
18.9 常见问题及解答
1. 如何使用查询缓存区?
查 询缓存区提高查询的速度,这种方式只适用于修改操作少且经常执行相同的查询操作的情况。默认情况下,查询缓存区是禁止的,因为 query_cache_size的默认值为0。query_cache_size可以设置有效的使用空间。query_cache_type可以设置查 询缓冲区的开启状态,其取值为0、1或者2。在my.cnf或者my.ini中加入下面的语句:
# my.cnf(Linux)或者my.ini(Windows)
[mysqld]
query_cache_size=20M
query_cache_type=1
query_cache_type取值为1时表示开启查询缓存区。在查询语句中加上SQL_NO_CACHE关键字,该查询语句将不使用查询缓存区。可以使用FLUSH QUERY CACHE语句来清理查询缓存区中的碎片。
2. 为什么查询语句中的索引没有发挥作用?
在 很多情况下,虽然查询语句中使用了索引,但是索引并没有发挥作用。例如,在WHERE条件的LIKE关键字匹配的字符串以"%"开头,这种情况下索引不会 起作用。WHERE条件中使用OR关键字来连接多个查询条件,如果有一个条件没有使用索引,那么其它的索引也不会起作用。如果使用多列索引时,多列索引第 一个字段没有使用,那么这个多列索引也不起作用。根据这些情况,必须对这些语句进行相应的优化。
19.Java访问MySQL数据库
20.PHP访问MySQL数据库
现 在最流行的动态网站开发的软件组合是LAMP。LAMP是Linux、Apache、MySQL和PHP的缩写。PHP具有简单易用、功能强大和开放性等 特点,这使PHP已经成为了网络世界中最流行的编程语言之一。PHP可以通过mysql接口或者mysqli接口来访问MySQL数据库。
20.1 PHP连接MySQL数据库
PHP可能通过mysql接口或者mysqli接口来访问MySQL数据库。如果希望正常的使用PHP,那么需要适当的配置PHP与Apache服务器。同时,PHP中加入了mysql接口和mysqli接口后,才能够顺利访问MySQL数据库。
20.1.1 Windows下操作系统下配置PHP
1.首先安装Apache服务器:
2.安装PHP
(1)如果还没有安装PHP,可以在http://www.php.net/downloads.php 中下载PHP。Windows操作系统下推荐下载PHP 5.2.11 zip package。
在 Windows操作系统中,将PHP的软件包解压到C:\php目录下。需要在Apache服务器的配置文件httpd.conf中添加一些信息。 Apache服务器的默认路径为C:\Program Files\Apache Software Foundation\Apache2.2。http.conf文件在Apache服务器目录下的conf文件夹中。在httpd.conf中加入下面的 信息:
LoadModule php5_module
"C:/php/php5apache2_2.dll"
AddType applicatin/x-httpd-php .php
(2)php.ini-recommended()复制到C:\WINDOWS\目录下
(3)添加参数:
;;;;;;;动态加载mysql和mysqli接口;;;;;;;;;;;;;;;;;;;;;;;
extension_dir="C:/php/ext"
extension=php_mysql.dll
extension=php_mysqli.dll
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(4)C:\php目录下的libmysql.dll复制到C:\WINDOWS目录下
(5)在Apachehtdocs目录下创建一个文件名为test.php。
test.php文件内容:
php_info();
?>
20.1.2 Linux操作系统下配置PHP
Linux 操作系统下推荐下载PHP 5.2.11(tar.gz)。下载网址为:http://www.php.net/downloads.php 。下载完成后将php-5.2.11.tar.gz复制到/usr/local/src目录下,然后在该目录下解压和安装。假设新下载的php软件包存储 在/home/skydao/download目录下。使用下面的语句来安装PHP:
shell> cp /home/skydao/download/php-5.2.11.tar.gz /usr/local/src/
shell> cd /usr/local/src/
shell> tar -xzvf php-5.2.11
shell> cd php-5.2.11
shell> ./configure --prefix=/usr/local/php --with-mysql=/usr/local --with-mysqli=/usr/bin/mysql_config
shell> make
shell> make install
shell> make clean
20.1.6 连接MySQL数据库
php可以通过mysql接口来连接MySQL数据库,也可以通过mysqli接口来连接MySQL数据库。
$connection = mysql_connect('host/IP','username','password');
# 指定登录到哪个数据库
$connection = mysql_connect('localst','root','','test');
mysqli接口有两个比较常用的内部类。分别是mysqli和mysqli_reult。
$connection = new mysqli('localhot','root','password','test');// 创建连接
if (mysqli_connect_errno()) {// 判断是否连接成功
ech '
连接失败'.mysqli_connect_errno().'
';// 输出连接失败的信息exit();// 退出程序
} else {
echo '
连接成功
';// 显示连接成功}
?>
20.2 PHP操作MySQL数据库
连 接MySQL数据库之后,PHP可以通过query()函数对数据进行查询、插入、更新、删除等操作。但是query()函数一次只能执行一条SQL语 句。如果需要一次执行多个SQL语句,需要使用multi_query()函数。PHP通过query()函数和multi_query()函数可以方便 的操作MySQL数据库。
20.2.1 执行SQL语句
PHP可以通过query()函数来执行SQL语句。如果SQL语句是INSERT语句、UPDATE语句、DELETE语句等,语句执行成功query()返回true,否则返回false。并且,可以通过affected_rows()函数获取发生变化的记录数。
# 执行INSERT语句
$result = $connection->query("INSERT INTO score VALUES(NULL,908, '法语',88");
if ($result) {
echo '
INSERT语句执行成功
';// 输出INSERT语句执行成功echo '
插入的记录数:'.$connection->affected_rows.'
';// 返回插入的记录数} else {
echo '
INSERT语句执行失败
';// 输出INSERT语句执行失败}
$result = $connection->query('SELECT * FROM socre');// 执行SELECT语句
if ($result) {
echo '
SELECT语句执行成功
';echo '
查询的记录数:'.$result->num_rows.'
';// 输出查询的记录数echo '
查询的字段数:'.$result->field_count.'
';// 输出查询的字段数} else {
echo '
SELECT语句执行失败
';// 输出SELECT语句执行失败的信息}
20.2.2 处理查询结果
query()函数成功的执行SELECT语句后,会返回一个mysqli_result对象$result。SELECT语句的查询结果都存储在$result中。mysqli接口中提供了四种方法来读取数据。
$rs = $result->fetch_row();$rs[$num]
$rs = $result->fetch_array();$rs[$num]或$rw['columnName']
$rs = $result->fetch_assoc();$rs['columnName']
$rs = $result->fetch_object();$rs->columnName;
$result = $connection->query('SELECT * FROM core');
# 判断是否还有记录,如果有记录,通过fetch_row()方法返回记录的值;如果没有记录,返回FALSE
while ($row=$result->fetch_row()) {
echo '
'.$row[0].','.$row[1].','.$row[2].','.$row[3].'
';}
while ($row=$result->fetch_assoc()) {
echo '
'.$row['id'].','.$row['stu_id'].','.$row['c_name'].','.$row['grade'].'
';}
while ($row=$result->fetch_array()) {
echo '
'.$row[0].','.$row['stu_id'].','.$row[2].','.$row['grade'].'
';}
while ($row=$result->fetch_object()) {
echo '
'.$row->id.','.$row->stu_id].','.$row->c_name.','.$row->grade.'
';}
20.2.3 获取查询结果的字段名
通 过fetch_fields()函数可以获取查询结果的详细信息,这个函数返回对象数组。通过这个对象数组可以获取字段名、表名等信息。例如,$info = $result->fetch_fields()可以产生一个对象数组$fino。然后通过$info[$sn]->name获取字段 名,$info[$n]->table获取表名。
$result = $connection->query('SELECT * FROM score');
$num = $result->field_count;// 计算查询的字段数
$info = $result->fetch_fields();// 获取记录的字段名、表名等信息
echo '
table:' . $info[0]->table.'
';// 输出表的名称for($i=0; $i<$num; $i++){
echo $info[$i]->name . "\t";// 输出字段的名称
}
20.2.4 一次执行多个SQL语句
query() 函数一次只能执行一条SQL语句,而multi_query()函数可以一次执行多个SQL语句。如果第一个SQL语句正确执行,那么 multi_query()函数返回true。否则,返回false。PHP中使用store_result()函数返回获取multi_query() 函数执行查询的记录。一次只能获取一个SQL语句的执行结果。可以使用next_result()函数来判断下一个SQL语句的结果是否存在,如果存 在,next_result()函数返回true,否则返回false。
$sql = 'SELECT * FROM score;SELECT * FROM student';
$rows = $connection->multi_query($sql);
if ($rows) {
$result = $connection->store_result();// 将查询结果赋值给$result
while ($row = $result->fetch_object()){
echo '
'.$row->id."\t".$row->stu_id."\t".$row->c_name."\t".$row->grade.'
';}
# 判断是否还有下一个SELECT语句
if ($connection->next_result()) {
while ($row=$result->fetch_object()) {
echo '
'.$row->id."\t".$row->name."\t".$row->gender."\t".$row->birth.'
';}
}
}
20.2.5 处理带参数的SQL语句
PHP中可以执行带参数的SQL语句。带参数的SQL语句中可以不指定某个字段的值,而使用问号(?)代替。然后在后面的语句中指定值来替换掉问号。通过prepare()函数将带参数的SQL语句进行处理。
通过prepare()函数将带参数的SQL语句进行处理
$stmt = $mysqli->prepare("INSERT INTO table(name1,name2) values(?,?)");
使用bind_param()函数中将数据类型与相应的变量对应
$stmt->bind_param('idsb',$var1,$var2,$var3,$var4);
i:int/tiny7/tinyint/......
d:float/double/...
s:char/varchar/text
b:blob
通过execute()方法执行SQL语句
$stmt->execute();
示例:
$stmt = $mysqli->prepare('INSERT INTO socre(id,stu_id,c_name,grade') VALUES(?,?,?,?)');
$stmt->bind_param('iisi',$id,$stu_id,$c_name,$grade); // 给变量设置数据类型
# 给每个变量赋值
$id=15;
$stu_id=908;
$c_name='数学';
$grade=85;
$stmt->execute();// 执行INSERT语句
$id=16;
$stu_id=909;
$c_name='数学';
$grade=88;
$stmt->execute(;
20.2.6 关闭创建的对象
对MySQL数据库的访问完成后,必须关闭创建的对象。连接MySQL数据库时创建了$connection对象,处理SQL语句的执行结果时创建了$result对象。操作完成后,这些对象必须使用close()方法来关闭。
$result->close();
$connection->close();
$stmt->close();
20.3 PHP备份与还原MySQL数据库
PHP语言中可能执行mysqldump命令来备份MySQL数据库,也可以执行mysql命令来还原MySQL数据库。PHP中使用system()函数或者exec()函数来调用mysqldump命令和mysql命令。
20.3.1 PHP备份MySQL数据库
PHP可以通过system()函数或者exec()函数来调用mysqldump命令。
system("mysqldump -h localhost -u root -pPassword database [table] > dir:\backup.sql");
exec() 函数的使用方法与system()函数是一样的。这里直接将mysqldump命令当作系统命令来调用。这需要将MySQL的应用程序的路径添加到系统变 量的Path变量中。如果不想把MySQL的应用程序的路径添加到Path变量中,可以使用mysqldump命令的完整路径。假设mysqldump在 c:\mysql\bin目录下,system()函数的形式如下:
system("C:/mysql/bin/mysqldump -h localhost -u root -pPassword database [table] > dir:/backup.sql");
20.3.2
20.3.3
20.3.4
20.3.5
20.4
20.5
21.C#访问MySQL数据库