mysql> select * from wifi_data where dev_id like "0023-AABBCCCCBBAA" ;
1、显示数据库列表。
show databases;
刚开始时才两个数据库:mysql和test。mysql库很重要它里面有MYSQL的系统信息,我们改密码和新增用户,实际上就是用这个库进行操作。
2、显示库中的数据表:
use mysql; //打开库,学过FOXBASE的一定不会陌生吧
show tables;
3、显示数据表的结构:
describe 表名;
4、建库:
create database 库名;
5、建表:
use 库名;
create table 表名 (字段设定列表);
如下:
CREATE TABLE `wifi_test` (
`dev_id` varchar(30) NOT NULL default '' COMMENT '设备ID',
`timestamp` varchar(50) NOT NULL default '' COMMENT '时间',
`interval` tinyint(1) NOT NULL default '1' COMMENT '上传间隔',
PRIMARY KEY (`dev_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
6、删库和删表:
drop database 库名;
drop table 表名;
7、将表中记录清空:
delete from 表名;
8、显示表中的记录:
select * from 表名;
9、表数据中的增删改查
(全部插入)insert into 表名 valus('','',……,'');
(部分插入)insert into 表名(列x,列y,……,列z) valus('','',……,'');
insert into wifi_test values("1234567890ab","201506161330","300");
insert into wifi_test values("1234567890ad","201506161332",0);
insert into wifi_test(dev_id,timestamp) values("1234567890ag","201506181405");
insert into wifi_test(timestamp) values("201506181505");
select * from wifi_test;
10.向表中删除行数据:
delect from 表名;(清空表)
delect from 表名 where [检索条件表达式]
delete from wifi_test where dev_id=1234567890ab;
delete from table_xx where catch_time LIKE '2016-07-14 20:22:%';
11.修改,更改表中的数据:
update 表名 set 列名='表达式' [from 另一表名] where [检索条件表达式];
update wifi_test set interval='300' where dev_id=1234567890ag;
update wifi_test set interval=replace(interval,127,80);
update wifi_test set timestamp=20150618143333 where dev_id;
update语法
Single-table语法:
UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
SET col_name1=expr1 [, col_name2=expr2 ...]
[WHERE where_definition]
[ORDER BY ...]
[LIMIT row_count]
Multiple-table语法:
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET col_name1=expr1 [, col_name2=expr2 ...]
[WHERE where_definition]
UPDATE语法可以用新值更新原有表行中的各列。SET子句指示要修改哪些列和要给予哪些值。WHERE子句指定应更新哪些行。如果没有WHERE子句,则更新所有的行。如果指定了ORDER BY子句,则按照被指定的顺序对行进行更新。LIMIT子句用于给定一个限值,限制可以被更新的行的数目。
如果您在一个表达式中通过tbl_name访问一列,则UPDATE使用列中的当前值。例如,以下语句把年龄列设置为比当前值多一:
UPDATE persondata SET age=age+1;
UPDATE赋值被从左到右评估。例如,以下语句对年龄列加倍,然后再进行增加:
UPDATE persondata SET age=age*2, age=age+1;
如果您把一列设置为其当前含有的值,则MySQL会注意到这一点,但不会更新。
update表的某些字段为null
update person set number=null,name=null;
如果您把被已定义为NOT NULL的列更新为NULL,则该列被设置到与列类型对应的默认值,并且累加警告数。对于数字类型,默认值为0;对于字符串类型,默认值为空字符串('');对于日期和时间类型,默认值为“zero”值。
多个表的UPDATE操作
UPDATE items,month SET items.price=month.price WHERE items.id=month.id;
以上的例子显示出了使用逗号操作符的内部联合,但是multiple-table UPDATE语句可以使用在SELECT语句中允许的任何类型的联合,比如LEFT JOIN,但是您不能把ORDER BY或LIMIT与multiple-table UPDATE同时使用。
12.查询表中的数据:select */表字段1,表字段2,……表字段n from 表名 【where 查询条件】;
mysql> select * from student;
mysql> select * from student where id=1;
mysql> select id,name from student;
mysql> select id,name from student where id in(1,3,4);//in表示集合。
//看当前使用的是哪个数据库 ,如果你还没选择任何数据库,结果是NULL。
mysql>select database();
+------------+
| DATABASE() |
+------------+
| menagerie |
+------------+
//查看有哪些数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
//选择数据库
mysql>use test; //;号可有可无,必须单行使用.
为了找出当前的数据库包含什么表(例如,当你不能确定一个表的名字),使用这个命令:
//看数据库里有哪些表
mysql>show tables;
+---------------------+
| Tables in menagerie |
+---------------------+
| event |
| pet |
+---------------------+
如果你想要知道一个表的结构,可以使用DESCRIBE命令;它显示表中每个列的信息:
//看表里有哪些列
mysql> describe pet;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name | varchar(20) | YES | | NULL | |
| owner | varchar(20) | YES | | NULL | |
| species | varchar(20) | YES | | NULL | |
| *** | char(1) | YES | | NULL | |
| birth | date | YES | | NULL | |
| death | date | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
Field显示列名字,Type是列的数据类型,Null表示列是否能包含NULL值,Key显示列是否被索引而Default指定列的默认值。
如果表有索引,SHOW INDEX FROM tbl_name生成有关索引的信息。
删除数据库.
mysql>drop database test;
如先输入mysql,成功启动后输入use mysql,出现如下错误:Access denied for user ''@'localhost' to database 'mysql'
还有,输mysql可以,输mysql -u root就出错了:
Access denied for user 'root'@'localhost' (using password: NO).
The reason is:
是昨日更新ROOT密码时出错
update user set password = '123456' where user ="root" //这样写是错的,密码其实不是123456
应该为update user set password = password ('123456') where user = "root"
具体操作步骤:
关闭mysql:
# service mysqld stop
然后:
# mysqld_safe --skip-grant-tables(该命令完成后,可能终端不会提示输入下一命令,下面命令在新开的终端中实现)
启动mysql:
# service mysqld start
mysql -u root
mysql> use mysql
mysql> UPDATE user SET Password=PASSWORD('xxx') WHERE user='root';
mysql> flush privileges;
mysql>\q
ERROR 1044 (42000): Access denied for user ''@'localhost' to database
解决 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) 问题
最近新装好的mysql在进入mysql工具时,总是有错误提示:
# mysql -u root -p
Enter password:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
或者
# mysql -u root -p password 'newpassword'
Enter password:
mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'root'@'localhost' (using password: YES)'
现在终于找到解决方法了。本来准备重装的,现在不必了。
方法操作很简单,如下:
# /etc/init.d/mysql stop
# mysqld_safe --user=mysql --skip-grant-tables --skip-networking &
# mysql -u root mysql
mysql>
UPDATE user SET Password=PASSWORD('newpassword') where USER='root' and
host='root' or host='localhost';//把空的用户密码都修改成非空的密码就行了。
mysql> FLUSH PRIVILEGES;
mysql> quit # /etc/init.d/mysqld restart
# mysql -uroot -p
Enter password: <输入新设的密码newpassword>
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
此问题是没有开启mysqld服务.
root 用户的 create_priv 权限是否被设置为N了?
在创建数据库时报错
mysql> create database haha;
ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'haha' mysql>
解决方案:这是因为在mysql的usr表中,存在用户名为空的账户,虽然登陆时用的是root,但是匿名登陆。删除user.user中值为NULL的,或更新NULL为test 1)delete from user where user is NULL
2)update user set user='test' where user is NULL
ERROR 1044 (42000): Access denied for user 'root'@'%' to database
我这里root有三种解析登录方式分别是:Host: bidevedw\_db、Host: ::1、Host: %
一般情况还有Host:127.0.0.1、Host:localhost我的里面把哪两种删了。
请注意 !
注意上面每条记录的的红色字体部分Grant_priv: Y
这个表示,以这种方式解析登录的root用户,是否有grant权限,Y则表示有授权限给其他用户的权限,N表示没有。
这里恰好,就是我们要找的原因,因为我的/my.cnf文件里面有skip-name-resolve参数,所以root都是解析到@'%'方式登录,于是就没有grant_priv权限。
解决方法:
1、在不重启MySQL服务的情况下,只需要在登录的时候加上-h参数。
例如:(a). /usr/local/mysql/bin/mysql -uroot -p123456 -h::1
(b)./usr/local/mysql/bin/mysql -uroot -p123456 -h127.0.0.1
2、需要重启MySQL。把skip-name-resolve参数去掉 ---- 还没验证。不过我记得,如果去掉了,日志里面会有大量的警告信息。我是因为那些警告信息,才添加的这个参数。
use testdb;
简单描述表结构,字段类型:
desc tb_content;
查看表生成的DDL,这个命令虽然显示起来不是太容易看, 这个不是问题可以用\G来结尾,使得结果容易阅读;该命令把创建表的DDL显示出来,于是表结构、类型,外键,备注全部显示出来了。我比较喜欢这个命令:输入简单,显示结果全面。
show create table tb_content;
查询表中列的注释信息
select * from information_schema.columns where table_schema = 'testdb';
select * from information_schema.columns where table_schema = 'testdb' and table_name = 'tb_content';
只查询列名和注释
select
column_name, column_comment from information_schema.columns where
table_schema ='testdb' and table_name = 'tb_content' ;
查看当前使用的数据库:
mysql>select database();
mysql>status;
修改root密码
mysql> use mysql
Database changed
mysql> update user set password=PASSWORD('123456') where user='root';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
查看所有用户密码:
SELECT User, Password, Host FROM user;
windows添加防火墙端口:
.需要设置防火墙放开mysql 3306端口的访问,控制面板->windows防火墙->高级设置,打开另一个界面,
在该界面中选择入站规则,然后在右边栏选择 新建规则,下一步选择端口,下一步选择TCP/特定本地端口并输入3306,下一步选择允许连接,下一步默认选择,下一步输入你想给的名称比如mysqlport,然后点击完成。
打开防火墙,选择例外选项卡,添加端口
名称:mysqlport
端口号:3306
选中TCP
设置好后,务必重新启动计算机
iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
打开防火墙配置文件可查看当前防火墙情况:vi /etc/sysconfig/iptables
iptables-save
sudo service iptables save
iptables-save, service iptables save 作用一样,只不过iptables-save需要手动指定路径及文件名,而service iptables save的文件为/etc/sysconfig/iptables
注意:增加的开放3306端口的语句一定要在icmp-host-prohibited之前
CREATE TABLE tab2 AS (SELECT * FROM tab1)
这种做法表的存储引擎也会采用服务器默认的存储引擎而不是源表的存储引擎,此种复制方法把表的内容也一起复制过来了。
CREATE TALBE tab2 ENGINE=MYISAM, CHARSET='UTF8' AS (SELECT * FROM tab1)
可以自己指定存储引擎和字符集,弥补方法一的不足
CREATE TABLE tab2 LIKE tab1
使用和tab1表相同的结构来创建一个新表,列名、数据类型、空指和索引也将复制,但是表的内容不会被复制。外键和专用的权限也没有被复制。
MySQL复制表结构及数据到新表
CREATE TABLE tab_new SELECT * FROM tab_old
复制旧表的数据到新表(假设两个表结构一样)
INSERT INTO tab1 SELECT * FROM tab2
复制旧表的数据到新表(假设两个表结构不一样)
INSERT INTO tab1(字段1, 字段2, ...) SELECT 字段1, 字段2, ... FROM tab2
更改表名
ALTER TABLE employee RENAME TO staff
更改列类型
ALTER TABLE employee MODIFY COLUMN truename VARCHAR(10) NOT NULL DEFAULT ''
更改列名
ALTER TABLE employee CHANGE COLUMN truename employeename VARCHAR(10) NOT NULL DEFAULT ''
添加默认值
ALTER TABLE employee ALTER COLUMN truename SET DEFAULT ''
删除默认值
ALTER TABLE employee ALTER COLUMN truename DEOP DEFAULT
mysql修改表
表的结构如下:
mysql> show create table person;
| person | CREATE TABLE `person` (
`number` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
删除列:
ALTER TABLE person DROP COLUMN birthday;
添加列:
ALTER TABLE person ADD COLUMN birthday datetime;
修改列,把number修改为bigint:
ALTER TABLE person MODIFY number BIGINT NOT NULL;
或者是把number修改为id,类型为bigint:
ALTER TABLE person CHANGE number id BIGINT;
添加主键:
ALTER TABLE person ADD PRIMARY KEY (id);
删除主键:
ALTER TABLE person DROP PRIMARY KEY;
添加唯一索引:
ALTER TABLE person ADD UNIQUE name_unique_index (`name`);
为name这一列创建了唯一索引,索引的名字是name_unique_index.
添加普通索引:
ALTER TABLE person ADD INDEX birthday_index (`birthday`);
删除索引:
ALTER TABLE person DROP INDEX birthday_index;
ALTER TABLE person DROP INDEX name_unique_index;
禁用非唯一索引
ALTER TABLE person DISABLE KEYS;
ALTER TABLE...DISABLE KEYS让MySQL停止更新MyISAM表中的非唯一索引。
激活非唯一索引
ALTER TABLE person ENABLE KEYS;
ALTER TABLE ... ENABLE KEYS重新创建丢失的索引。
把表默认的字符集和所有字符列(CHAR, VARCHAR, TEXT)改为新的字符集:
ALTER TABLE person CONVERT TO CHARACTER SET utf8;
修改表某一列的编码
ALTER TABLE person CHANGE name name varchar(255) CHARACTER SET utf8;
仅仅改变一个表的默认字符集
ALTER TABLE person DEFAULT CHARACTER SET utf8;
修改表名
RENAME TABLE person TO person_other;
移动表到其他数据库
RENAME TABLE current_db.tbl_name TO other_db.tbl_name;
在mysql中我们对数据表字段的修改命令只要使用alter就可以了,下面我来给大家详细介绍mysql中修改表字段名/字段长度/字段类型等等一些方法介绍,有需要了解的朋友可参考。
先来看看常用的方法
MySql的简单语法,常用,却不容易记住。当然,这些Sql语法在各数据库中基本通用。下面列出:
1.增加一个字段
alter table user add COLUMN new1 VARCHAR(20) DEFAULT NULL; //增加一个字段,默认为空
alter table user add COLUMN new2 VARCHAR(20) NOT NULL; //增加一个字段,默认不能为空
2.删除一个字段
alter table user DROP COLUMN new2; //删除一个字段
3.修改一个字段
alter table user MODIFY new1 VARCHAR(10); //修改一个字段的类型
alter table user CHANGE COLUMN new1 new4 varchar(512) default ""; //修改一个字段的名称,此时一定要重新指定该字段的类型
//主键
alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列
alter table t2 add d timestamp;
alter table infos add ex tinyint not null default ‘0′;
//删除列
alter table t2 drop column c;
//重命名列
alter table t1 change a b integer;
//改变列的类型
alter table t1 change b b bigint not null;
alter table infos change list list tinyint not null default ‘0′;
//重命名表
alter table t1 rename t2;
加索引
mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引
mysql> alter table tablename add primary key(id);
加唯一限制条件的索引
mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引
mysql>alter table tablename drop index emp_name;
增加字段:
mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:
mysql> ALTER TABLE table_name DROP field_name;
mysql修改字段长度
alter table 表名 modify column 字段名 类型;
例如
数据库中user表 name字段是varchar(30)
可以用
alter table user modify column name varchar(50) ;
mysql更改表结构:添加、删除、修改字段、调整字段顺序
mysqltablenulluserlist
添加字段:
alter table `user_movement_log`
Add column GatewayId int not null default 0 AFTER `Regionid` (在哪个字段后面添加)
删除字段:
alter table `user_movement_log` drop column Gatewayid
调整字段顺序:
ALTER TABLE `user_movement_log` CHANGE `GatewayId` `GatewayId` int not null default 0 AFTER RegionID
//主键
alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列
alter table t2 add d timestamp;
alter table infos add ex tinyint not null default '0';
//删除列
alter table t2 drop column c;
//重命名列
alter table t1 change a b integer;
//改变列的类型
alter table t1 change b b bigint not null;
alter table infos change list list tinyint not null default '0';
//重命名表
alter table t1 rename t2;
加索引
mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引
mysql> alter table tablename add primary key(id);
加唯一限制条件的索引
mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引
mysql>alter table tablename drop index emp_name;
修改表:
增加字段:
mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:
mysql> ALTER TABLE table_name DROP field_name;
MySql表结构修改详解
修改表的语法
=========================
增加列[add 列名]
=========================
①alter table 表名 add 列名 列类型 列参数【加的列在表的最后面】
例:alter table test add username char(20) not null default '';
alter table test add birth date not null default '0000-00-00';
②alter table 表名 add 列名 列类型 列参数 after 某列【把新列加在某列后面】
例:alter table test add gender char(1) not null default '' after username;
③alter table 表名 add 列名 列类型 列参数 first【把新列加在最前面】
例:alter table test add pid int not null default 0 first;
=========================
删除列[drop 列名]
=========================
①alter table 表名 drop 列名
例:alter table test drop pid;
=========================
修改列[modife 列名]
=========================
①alter table 表名 modify 列名 新类型 新参数【修改列类型】
例:alter table test modify gender char(4) not null default '';
②alter table 表名 change 旧列名 新列名 新类型 新参数【修改列名和列类型】
例:alter table test change pid uid int unsigned not null default 0;
=========================
查询列
=========================
①desc 表名【查询所有列】
例: desc test;
mysql> desc department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| dId | int(11) | NO | PRI | | |
| dName | varchar(32) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
②show columns from 表名【效果和desc一样】
mysql> show columns from department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| dId | int(11) | NO | PRI | | |
| dName | varchar(32) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
③show create table 表名【查看表的创建代码】
mysql> show create table department;
CREATE TABLE `department` (
`dId` int(11) NOT NULL,
`dName` varchar(32) DEFAULT NULL,
PRIMARY KEY (`dId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
总结一下对mysql表结构的修改操作,包括对字段及索引的修改操作:
添加字段:
alter table `user_movement_log` Add column GatewayId int not null default 0 AFTER `Regionid` (在哪个字段后面添加)
删除字段:
alter table `user_movement_log` drop column Gatewayid
调整字段顺序:
ALTER TABLE `user_movement_log` CHANGE `GatewayId` `GatewayId` int not null default 0 AFTER RegionID
//主键
alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列
alter table t2 add newfield timestamp; (简单语法,只指定新添字段newfield 类型为timestamp)
alter table infos add newfield tinyint not null default '0'; (同时指定字段null属性、默认值)
//删除列
alter table t2 drop column c; (删除列c)
//重命名列
alter table t1 change a b integer; (把列a改名为b,注意要指定列类型)
//改变列的类型
alter table t1 change b b bigint not null; (把列a改名为b,指定列类型及null属性)
alter table infos change list list tinyint not null default '0';
//重命名表
alter table t1 rename t2;
加索引
mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引
mysql> alter table tablename add primary key(id);
加唯一限制条件的索引
mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引
mysql>alter table tablename drop index emp_name;
修改表:
增加字段:
mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:
mysql> ALTER TABLE table_name DROP field_name;
ORDER BY _column1, _column2; /* _column1升序,_column2升序 */
ORDER BY _column1, _column2 DESC; /* _column1升序,_column2降序 */
ORDER BY _column1 DESC, _column2 ; /* _column1降序,_column2升序 */
ORDER BY _column1 DESC, _column2 DESC; /* _column1降序,_column2降序 */
用 DESC 表示按倒序排序(即:从大到小排序)
用 ACS 表示按正序排序(即:从小到大排序)
order应该是以汉字的 ASCII 码排序,下面是按照汉字拼音排序
select * from corp_data where Chengshi like "图木舒克" order by convert(name using gbk);
#select count(*) as count from corp_data where Chengshi like "图木舒克";
select * from corp_data where Chengshi like "图木舒克" order by convert(name using gbk);
#delete from corp_data where Chengshi like "图木舒克";
#desc corp_data;
#alter table corp_data modify column hangye varchar(100) ;
#alter table corp_data modify column jianjie varchar(10000) ;
mysql如何查询最新的5条数据
select * from tb_content where id=(select msx(id) from tb_content) limit 0,5;
jdbcTemplate.execute("CREATE
建数据库不合适,要手动drop database ,再create database.
查总数:
select count(*) as count from tb_content;
select count(id) as count from tb_content;
navicat->分析表->取得表的总数
select * from corp_data where Chengshi like "上海";
select * from corp_data where Shengzhixiashi like "河南";
select name ,count(distinct(url)) from corp_data group by name;
select Chengshi ,count(distinct(url)) from corp_data group by Chengshi;
select Chengshi ,count(*) from corp_data group by Chengshi;
select count(*) from corp_data where Chengshi like "北京";
select * from corp_data where Chengshi like "北京";
select name ,url from corp_data limit 1;
select * from corp_data limit 1;
select * from corp_data limit 10;
select count(*) as count from corp_data limit 10;
select count(distinct(name)) as count from corp_data;
varchar(N), 这里的N是指字符数,并不是字节数.占用的字节数与编码有关
utf-8, 一个汉字3字节 英文字母1字节
CREATE TABLE IF NOT EXISTS corp_url_all_20150909 (id int(11) NOT NULL AUTO_INCREMENT,url varchar(500),PRIMARY KEY (id))
insert into corp_url_all_20150909 select * from corp_url_all;
备份:
mysql> create table corp_url_all_20150909 select * from corp_url_all;
Query OK, 3186326 rows affected (1 min 14.19 sec)
Records: 3186326 Duplicates: 0 Warnings: 0
mysql> select count(distinct(url)) as count from corp_url_all_20150909;
+--------+
| count |
+--------+
| 357399 |
+--------+
1 row in set (11.21 sec)
去重:
create table corp_url_all_single select distinct(url) from corp_url_all_20150909;
select count(distinct(url)) as count from corp_url_all_single;
基本的SQL语句
二、数据定义语言(DDL)
数据定义语言:Data Definition Language。如CREATE, DROP,ALTER等语句。需要注意的是,数据库中的命令不区分大小写。
创建数据库,命名为mydb:
CREATE DATABASE mydb;
注:如若要删除数据库,将“create”改为“drop”即可。
创建一个名为teacher的表:
CREATE TABLE teacher(
id int primary key auto_increment,
name varchar(20),
gender char(1),
age int(2),
birth date,
description varchar(100)
);
查看表结构:
desc teacher;
需要注意的是:主键是用来唯一代表一条记录的字段(主键值必须是唯一)
修改表结构(ALTER TABLE语句):(假设表名为test)
- alter table test add column job varchar(10); --添加表列
- alter table test rename test1; --修改表名
- alter table test drop column name; --删除表列
- alter table test modify address char(10) --修改表列类型(改类型)
- alter table test change address address1 char(40) --修改表列类型(改名字和类型,和下面的一行效果一样)
- alter table test change column address address1 varchar(30)--修改表列名(改名字和类型)
自动增长
alter table tab_teacher change id id int auto_increment;
增加数据
insert into tab_teacher(name,gender,age,createDate) values('smyh','b',22,now());
now()函数可以调出当前系统的时间。
修改数据(UPDATE … SET语句):
UPDATE 表名 SET 字段1名=值,字段2名=值,字段3名=值 where 字段名=值;
注:where后面的部分表示修改的条件。修改时,按照字段1、字段2、字段3的先后顺序修改。
删除数据:
DELETE FROM 表名;
删除ID为1的记录:
DELETE FROM 表名 where id=1;
四、数据查询语言(DRL):
数据查询语言(Data Retrieval Language --DRL):SELECT语句。
在实际开发中,数据查询语言用的是最多的。注:实际开发中,要避免使用通配符"*"(通配符代表所有字段),因为系统要先解析出所有的字段名,将其还原为真实的名字,然后再进行操作。如果记录数据库内容特别多,会影响效率。
查询所有信息:
select id,name,gender,age,job,createDate from tab_teacher;
在没有表被引用的情况下,允许指定DUAL作为一个假的表名:
DUAL是虚拟表。也就是说,表中没有这个数据,但是要执意使用sql语句,系统就会用这个虚拟表来满足你。举例效果如下:
查询ID为2的老师信息:
select * from tab_teacher where id=2;
查询职业为空的老师信息:
select * from tab_teacher where job is null;#字段为空用“job is null”来表示,而不是“job=null”。
查询ID为2的老师的姓名和性别:
select name,gender from tab_teacher where id=2;
查询性别为女和指定日期的老师信息:
select $ from tab_teacher where gender='w' and ceateDate='2014-10-14'; #并且用“and”,或用“or”。
查询性别为男或者ID小于2的老师:
select * from tab_teacher where gender='m' or id<2;
查询姓名的最后一个字符为“e”的老师:(关键字:like '%+指定字符')
select * from tab_teacher where name like '%e';
查询姓名以指定字符开头的老师:
select * from tab_teacher where name like 's%';
查询姓名中包含“m”的老师:
select * from tab_teacher where name like '%m%';
查询所有老师信息,并按日期降序或者升序排列:(ORDER BY 字段,+默认为升序:ASC/降序:DESC)
- 升序:
select * from tab_teacher order by createDate; #最后一个单词ASC可写可不写,因为默认为升序
- 降序:
select * from tab_teacher order by createDate desc;
多个排序条件:(当第一个条件相同时,按照第二个条件排序)
例如:上面图片的排序中,是按照日期降序排序的,但是id为2和id为3的日期相同,这两条记录按照默认顺序排序。
举例:现在排序的第一条件为:日期降序,第二条件为:年龄降序。多个排序条件用逗号隔开。命令为:
select * from tab_teacher order by createDate desc,age desc;
按性别分组查询男女老师的人数(GROUP BY ):
select gender,count(gender) from tab_teacher group by gender;
上面的命令表示,查找gender这个字段;并计算gender有多少个(count(gender));然后按照gender里的内容将个数进行分组(group by gender)。
问题:我觉得应该是先分组,再查询性别,再数性别的个数。
注:这里面用到了count()这个内置的函数。关于count()这个聚合函数,将在下一篇文章中讲到。
正确的效果和错误的效果如下:
按性别分组,查询出女老师人数的总数:
select gender,count(gender) from tab_teacher group by gender having gender='m';
这里在上一个命令的基础上,增加了一个关键字:having。having关键字专门用来在分组之后添加的条件。意思是:先求总数,然后进行分组,然后再从分组里找到字段等于“m”的个数。注:不能用where作为关键字,因为where是加在分组之前的条件。
显示效果如下:
注:这种写法操作繁琐,效率较低,having语句尽量少用,可以用其他语句代替,例如:
select gender,count(gender) from tab_teacher where gender='m';
效果是一样的。
查询表的总记录数:
- 方式一:(不推荐)
select count(*) from tab_teacher;
- 方式二:(使用主键的方式查询)
select count(id) from tab_teacher;
方式一将空记录也包含进来了。所以采用方式二,因为主键唯一,且不能为空,此时id总数则代表总记录数。
别名的用法:
- 使用别名查询表的总记录数:
select count(id) as counts from tab_teacher;
不用别名和用别名的效果对比如下:(命令中的"as"可以省略)
- 使用别名来代替表的名字:
举例:将表的名字起为t。
select t.name,t.age from tab_teacher t;
当表名比较长,或者同时有多个表存在时,用别名就显得非常方便了。
查询老师记录的前三条(从0位置开始找出3条):(非常有用)
select * from tab_teacher limit 0,3;
命令解释:limit后面有两个参数:第一个参数是起始位置,第二个参数是偏移量。声明:第一条记录的id不管为多少,索引位置都是0。
注:这种分页查询方式非常有用,例如使用百度搜索时,告诉你总记录数,但是会分页显示。
五、事务控制语言(TCL):
事务控制语言:Transaction Control Language--TCL。如COMMIT,ROLLBACK语句。
1、事务:
事务(Transaction)的概念:事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。
事务的属性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持续性(durability)。这四个属性通常称为ACID特性。
事务的特点:事务就是对数据库的多步操作,要么一起成功,要么一起失败。
总结:事务就是可以把多步操作看成一个整体,这个整体要么一起成功,要么一起失败。
2、事务的提交和回滚命令:
设置默认事务提交方式:(默认为true)
- 设置事务提交方式为“手动提交”:
set autocommit = false;
- 设置事务提交方式为“自动提交”:
set autocommit = true;
手动提交事务:
commit;
回滚事务:
rollback;
注:只要还没手动commit提交,一旦回滚,之前的修改操作都将清零。
注:commit命令和rollback命令只有在提交方式为“手动提交”时,才可以用。
3、保存还原点的命令:
当数据未commit之前,增删改查的操作都是暂时保存在内存之中的,当我们修改操作进行到某一步时,可以给这一步设置一个还原点,方便以后回滚到此还原点(类似于PS当中的快照)。
保存还原点:
savepoint name_point;
回滚到指定还原点:
rollback to name_point;
九、MySQL的一些函数:
1、字符串链接——CONCAT()
>SELECT CONCAT(name,'=>',score) FROM tb_name
2、数学函数:
AVG、SUM、MAX、MIN、COUNT;
3、文本处理函数:
TRIM、LOCATE、UPPER、LOWER、SUBSTRING
4、运算符:
+、-、*、\
5、时间函数:
DATE()、CURTIME()、DAY()、YEAR()、NOW().....
十、分组查询:
1、分组查询可以按照指定的列进行分组:
>SELECT COUNT(*) FROM tb_name GROUP BY score HAVING COUNT(*)>1;
2、条件使用Having;
3、ORDER BY 排序:
ORDER BY DESC|ASC =>按数据的降序和升序排列
十一、UNION规则——可以执行两个语句(可以去除重复行)
十二、全文检索——MATCH和AGAINST
1、SELECT MATCH(note_text)AGAINST('PICASO') FROM tb_name;
2、InnoDB引擎不支持全文检索,MyISAM可以;
十三、视图
1、创建视图
>CREATE VIEW name AS SELECT * FROM tb_name WHERE ~~ ORDER BY ~~;
2、视图的特殊作用:
a、简化表之间的联结(把联结写在select中);
b、重新格式化输出检索的数据(TRIM,CONCAT等函数);
c、过滤不想要的数据(select部分)
d、使用视图计算字段值,如汇总这样的值。
十四、使用存储过程:
个人理解,存储过程就是一个自定义函数,有局部变量参数,可传入参数,可以返回值,不过这语法够呆滞的~~~
1、创建存储过程:
>CREATE PROCEDURE pro(
>IN num INT,OUT total INT)
>BEGIN
>SELECT SUM(score) INTO total FROM tb_name WHERE id=num;
>END;
***这里的 IN (传递一个值给存储过程),OUT(从存储过程传出一个值),INOUT(对存储过程传入、传出),INTO(保存变量)
2、调用存储过程:
>CALL pro(13,@total) //这里的存储过程两个变量,一个是IN一个是OUT,这里的OUT也是需要写上的,不写会出错
>SELECT @total //这里就可以看到结果了;
3、存储过程的其他操作:
>SHOW PROCEDURE STATUS; //显示当期的存储过程
>DROP PROCEDURE pro; //删除指定存储过程
十五、使用游标:
对这个理解不是很懂,朋友多多指点哦~~~
1、游标的操作
>CREATE PROCEDURE pro()
>BEGIN
>DECLARE ordername CURSOR FOR
>SELECT order_num FROM orders;
>END;
>OPEN ordername; //打开游标
>CLOSE ordername; //关闭游标
十六、触发器:
触发器是指在进行某项指定操作时,触发触发器内指定的操作;
1、支持触发器的语句有DELETE、INSERT、UPDATE,其他均不支持
2、创建触发器:
>CREATE TRIGGER trig AFTER INSERT ON ORDERS FOR EACH ROW SELECT NEW.orser_name;
>INSERT语句,触发语句,返回一个值
3、删除触发器
>DROP TRIGGER trig;
十七、语法整理:
1、ALTER TABLE(修改表)
ALTER TABLE table_name
( ADD column datatype [ NULL | NOT NULL ] [ CONSTRAINTS ]
CHANGE column datatype COLUMNS [ NULL | NOT NULL ] [ CONSTRAINTS ]
DROP column,
。。。。
)
2、COMMIT(处理事务)
>COMMIT;
3、CREATE INDEX(在一个或多个列上创建索引)
CREATE INDEX index_name ON tb_name (column [ ASC | DESC ] , .......);
4、CREATE PROCEDURE (创建存储过程)
CREATE PROCEDURE pro([ parameters ])
BEGIN
........
END
5、CREATE TABLE(创建表)
CREATE TABLE tb_name(
column_name datetype [ NULL | NOT NULL ] [ condtraints] ,
column_name datetype [ NULL | NOT NULL ] [ condtraints] ,
.......
PRIMARY KEY( column_name )
)ENGINE=[ InnoDB | MyiSAM ]DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
6、CREATE USER(创建用户)
CREATE USER user_name [ @hostname ] [ IDENTIFIED BY [ PASSWORD ] 'pass_word' ];
7、CREATE VIEW (在一个或多个表上创建视图)
CREATE [ OR REPLACE ] VIEW view_name AS SELECT。。。。。。
8、DELETE (从表中删除一行或多行)
DELETE FROM table_name [WHERE ......]
9、DROP(永久删除数据库及对象,如视图、索引等)
DROP DATEBASE | INDEX | PROCEDURE | TABLE | TRIGGER | USER | VIEW name
10、INSERT (给表添加行)
INSERT INTO tb_name [ ( columns,...... ) ] VALUES(value1,............);
使用SELECT值插入:
INSERT INTO tb_name [ ( columns,...... ) ]
SELECT columns , ....... FROM tb_name [ WHERE ...... ] ;
11、ROLLBACK(撤销一个事务处理块)
ROLLBACK [ TO savapointname ];
12、SAVEPOINT(为ROLLBACK设置保留点)
SAVEPOINT sp1;
13、SELECT (检索数据,显示信息)
SELECT column_name,.....FROM tb_name [ WHERE ] [ UNION ] [ RROUP BY ] [ HAVING ] [ ORDER BY ]
14、START TRANSACTION (一个新的事务处理块的开始)
START TRANSACTION
15、UPDATE(更新一个表中的一行或多行)
UPDATE tb_name SET column=value,......[ where ]
其它mysql基本操作:
http://www.cnblogs.com/RanNing/archive/2012/11/17/2870484.html
几个最常用的api函数
mysql_affected_rows() 返回被最新的UPDATE, DELETE或INSERT查询影响的行数。
mysql_close() 关闭一个服务器连接。
mysql_errno() 返回最近被调用的MySQL函数的出错编号。
mysql_error() 返回最近被调用的MySQL函数的出错消息。
mysql_fetch_row() 从结果集合中取得下一行。
mysql_field_count() 返回最近查询的结果列的数量。
mysql_init() 获得或初始化一个MYSQL结构。
mysql_insert_id() 返回有前一个查询为一个AUTO_INCREMENT列生成的ID。
mysql_num_rows() 返回一个结果集合中的行的数量。
mysql_query() 执行指定为一个空结尾的字符串的SQL查询。
mysql_real_connect() 连接一个MySQL服务器。
mysql_real_query() 执行指定为带计数的字符串的SQL查询。
mysql常用字符串操作函数大全,以及实例
http://www.cnblogs.com/xiangxiaodong/archive/2011/02/21/1959589.html
CREATE TABLE tab2 AS (SELECT * FROM tab1)
这种做法表的存储引擎也会采用服务器默认的存储引擎而不是源表的存储引擎,此种复制方法把表的内容也一起复制过来了。
CREATE TALBE tab2 ENGINE=MYISAM, CHARSET='UTF8' AS (SELECT * FROM tab1)
可以自己指定存储引擎和字符集,弥补方法一的不足
CREATE TABLE tab2 LIKE tab1
使用和tab1表相同的结构来创建一个新表,列名、数据类型、空指和索引也将复制,但是表的内容不会被复制。外键和专用的权限也没有被复制。
MySQL复制表结构及数据到新表
CREATE TABLE tab_new SELECT * FROM tab_old
复制旧表的数据到新表(假设两个表结构一样)
INSERT INTO tab1 SELECT * FROM tab2
复制旧表的数据到新表(假设两个表结构不一样)
INSERT INTO tab1(字段1, 字段2, ...) SELECT 字段1, 字段2, ... FROM tab2
更改表名
ALTER TABLE employee RENAME TO staff
更改列类型
ALTER TABLE employee MODIFY COLUMN truename VARCHAR(10) NOT NULL DEFAULT ''
更改列名
ALTER TABLE employee CHANGE COLUMN truename employeename VARCHAR(10) NOT NULL DEFAULT ''
添加默认值
ALTER TABLE employee ALTER COLUMN truename SET DEFAULT ''
删除默认值
ALTER TABLE employee ALTER COLUMN truename DEOP DEFAULT
mysql修改表
表的结构如下:
mysql> show create table person;
| person | CREATE TABLE `person` (
`number` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`birthday` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
删除列:
ALTER TABLE person DROP COLUMN birthday;
添加列:
ALTER TABLE person ADD COLUMN birthday datetime;
修改列,把number修改为bigint:
ALTER TABLE person MODIFY number BIGINT NOT NULL;
或者是把number修改为id,类型为bigint:
ALTER TABLE person CHANGE number id BIGINT;
添加主键:
ALTER TABLE person ADD PRIMARY KEY (id);
删除主键:
ALTER TABLE person DROP PRIMARY KEY;
添加唯一索引:
ALTER TABLE person ADD UNIQUE name_unique_index (`name`);
为name这一列创建了唯一索引,索引的名字是name_unique_index.
添加普通索引:
ALTER TABLE person ADD INDEX birthday_index (`birthday`);
删除索引:
ALTER TABLE person DROP INDEX birthday_index;
ALTER TABLE person DROP INDEX name_unique_index;
禁用非唯一索引
ALTER TABLE person DISABLE KEYS;
ALTER TABLE...DISABLE KEYS让MySQL停止更新MyISAM表中的非唯一索引。
激活非唯一索引
ALTER TABLE person ENABLE KEYS;
ALTER TABLE ... ENABLE KEYS重新创建丢失的索引。
把表默认的字符集和所有字符列(CHAR, VARCHAR, TEXT)改为新的字符集:
ALTER TABLE person CONVERT TO CHARACTER SET utf8;
修改表某一列的编码
ALTER TABLE person CHANGE name name varchar(255) CHARACTER SET utf8;
仅仅改变一个表的默认字符集
ALTER TABLE person DEFAULT CHARACTER SET utf8;
修改表名
RENAME TABLE person TO person_other;
移动表到其他数据库
RENAME TABLE current_db.tbl_name TO other_db.tbl_name;
在mysql中我们对数据表字段的修改命令只要使用alter就可以了,下面我来给大家详细介绍mysql中修改表字段名/字段长度/字段类型等等一些方法介绍,有需要了解的朋友可参考。
先来看看常用的方法
MySql的简单语法,常用,却不容易记住。当然,这些Sql语法在各数据库中基本通用。下面列出:
1.增加一个字段
alter table user add COLUMN new1 VARCHAR(20) DEFAULT NULL; //增加一个字段,默认为空
alter table user add COLUMN new2 VARCHAR(20) NOT NULL; //增加一个字段,默认不能为空
2.删除一个字段
alter table user DROP COLUMN new2; //删除一个字段
3.修改一个字段
alter table user MODIFY new1 VARCHAR(10); //修改一个字段的类型
alter table user CHANGE new1 new4 int; //修改一个字段的名称,此时一定要重新
//主键
alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列
alter table t2 add d timestamp;
alter table infos add ex tinyint not null default ‘0′;
//删除列
alter table t2 drop column c;
//重命名列
alter table t1 change a b integer;
//改变列的类型
alter table t1 change b b bigint not null;
alter table infos change list list tinyint not null default ‘0′;
//重命名表
alter table t1 rename t2;
加索引
mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引
mysql> alter table tablename add primary key(id);
加唯一限制条件的索引
mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引
mysql>alter table tablename drop index emp_name;
增加字段:
mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:
mysql> ALTER TABLE table_name DROP field_name;
mysql修改字段长度
alter table 表名 modify column 字段名 类型;
例如
数据库中user表 name字段是varchar(30)
可以用
alter table user modify column name varchar(50) ;
mysql更改表结构:添加、删除、修改字段、调整字段顺序
mysqltablenulluserlist
添加字段:
alter table `user_movement_log`
Add column GatewayId int not null default 0 AFTER `Regionid` (在哪个字段后面添加)
删除字段:
alter table `user_movement_log` drop column Gatewayid
调整字段顺序:
ALTER TABLE `user_movement_log` CHANGE `GatewayId` `GatewayId` int not null default 0 AFTER RegionID
//主键
alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列
alter table t2 add d timestamp;
alter table infos add ex tinyint not null default '0';
//删除列
alter table t2 drop column c;
//重命名列
alter table t1 change a b integer;
//改变列的类型
alter table t1 change b b bigint not null;
alter table infos change list list tinyint not null default '0';
//重命名表
alter table t1 rename t2;
加索引
mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引
mysql> alter table tablename add primary key(id);
加唯一限制条件的索引
mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引
mysql>alter table tablename drop index emp_name;
修改表:
增加字段:
mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:
mysql> ALTER TABLE table_name DROP field_name;
MySql表结构修改详解
修改表的语法
=========================
增加列[add 列名]
=========================
①alter table 表名 add 列名 列类型 列参数【加的列在表的最后面】
例:alter table test add username char(20) not null default '';
alter table test add birth date not null default '0000-00-00';
②alter table 表名 add 列名 列类型 列参数 after 某列【把新列加在某列后面】
例:alter table test add gender char(1) not null default '' after username;
③alter table 表名 add 列名 列类型 列参数 first【把新列加在最前面】
例:alter table test add pid int not null default 0 first;
=========================
删除列[drop 列名]
=========================
①alter table 表名 drop 列名
例:alter table test drop pid;
=========================
修改列[modife 列名]
=========================
①alter table 表名 modify 列名 新类型 新参数【修改列类型】
例:alter table test modify gender char(4) not null default '';
②alter table 表名 change 旧列名 新列名 新类型 新参数【修改列名和列类型】
例:alter table test change pid uid int unsigned not null default 0;
=========================
查询列
=========================
①desc 表名【查询所有列】
例: desc test;
mysql> desc department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| dId | int(11) | NO | PRI | | |
| dName | varchar(32) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
②show columns from 表名【效果和desc一样】
mysql> show columns from department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| dId | int(11) | NO | PRI | | |
| dName | varchar(32) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
③show create table 表名【查看表的创建代码】
mysql> show create table department;
CREATE TABLE `department` (
`dId` int(11) NOT NULL,
`dName` varchar(32) DEFAULT NULL,
PRIMARY KEY (`dId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
总结一下对mysql表结构的修改操作,包括对字段及索引的修改操作: 添加字段: alter table `user_movement_log` Add column GatewayId int not null default 0 AFTER `Regionid` (在哪个字段后面添加) 删除字段: alter table `user_movement_log` drop column Gatewayid 调整字段顺序: ALTER TABLE `user_movement_log` CHANGE `GatewayId` `GatewayId` int not null default 0 AFTER RegionID //主键 alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id); //增加一个新列 alter table t2 add newfield timestamp; (简单语法,只指定新添字段newfield 类型为timestamp) alter table infos add newfield tinyint not null default '0'; (同时指定字段null属性、默认值) //删除列 alter table t2 drop column c; (删除列c) //重命名列 alter table t1 change a b integer; (把列a改名为b,注意要指定列类型) //改变列的类型 alter table t1 change b b bigint not null; (把列a改名为b,指定列类型及null属性) alter table infos change list list tinyint not null default '0'; //重命名表 alter table t1 rename t2; 加索引 mysql> alter table tablename change depno depno int(5) not null; mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]); mysql> alter table tablename add index emp_name (name); 加主关键字的索引 mysql> alter table tablename add primary key(id); 加唯一限制条件的索引 mysql> alter table tablename add unique emp_name2(cardnumber); 删除某个索引 mysql>alter table tablename drop index emp_name; 修改表: 增加字段: mysql> ALTER TABLE table_name ADD field_name field_type; 修改原字段名称及类型: mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type; 删除字段: mysql> ALTER TABLE table_name DROP field_name;
ORDER BY _column1, _column2; /* _column1升序,_column2升序 */
ORDER BY _column1, _column2 DESC; /* _column1升序,_column2降序 */
ORDER BY _column1 DESC, _column2 ; /* _column1降序,_column2升序 */
ORDER BY _column1 DESC, _column2 DESC; /* _column1降序,_column2降序 */
用 DESC 表示按倒序排序(即:从大到小排序)
用 ACS 表示按正序排序(即:从小到大排序)
order应该是以汉字的 ASCII 码排序,下面是按照汉字拼音排序
select * from corp_data where Chengshi like "图木舒克" order by convert(name using gbk);
#select count(*) as count from corp_data where Chengshi like "图木舒克";
select * from corp_data where Chengshi like "图木舒克" order by convert(name using gbk);
#delete from corp_data where Chengshi like "图木舒克";
#desc corp_data;
#alter table corp_data modify column hangye varchar(100) ;
#alter table corp_data modify column jianjie varchar(10000) ;
mysql如何查询最新的5条数据
select * from tb_content where id=(select msx(id) from tb_content) limit 0,5;
jdbcTemplate.execute("CREATE
建数据库不合适,要手动drop database ,再create database.
查总数:
select count(*) as count from tb_content;
select count(id) as count from tb_content;
navicat->分析表->取得表的总数
select * from corp_data where Chengshi like "上海";
select * from corp_data where Shengzhixiashi like "河南";
select name ,count(distinct(url)) from corp_data group by name;
select Chengshi ,count(distinct(url)) from corp_data group by Chengshi;
select Chengshi ,count(*) from corp_data group by Chengshi;
select count(*) from corp_data where Chengshi like "北京";
select * from corp_data where Chengshi like "北京";
select name ,url from corp_data limit 1;
select * from corp_data limit 1;
select * from corp_data limit 10;
select count(*) as count from corp_data limit 10;
select count(distinct(name)) as count from corp_data;
varchar(N), 这里的N是指字符数,并不是字节数.占用的字节数与编码有关
utf-8, 一个汉字3字节 英文字母1字节
mysql编码最好使用utf-8,导出导入不用考滤编码。
GB2312是GBK的子集,GBK是GB18030的子集,是国标。utf-8为国际标准,特殊中文时使用gb18030。
下面总结的知识点全是经常用的,全都是干货,好好收藏吧。
/* 启动mysql */
net start mysql
/* 连接与断开服务器 */
mysql -h 地址 -p 端口 -u 用户名 -p 密码
/* 跳过权限验证登录mysql */
mysqld --skip-grant-tables
-- 修改root密码
密码加密函数password()
update mysql.user set password=password('root');
show processlist -- 显示哪些线程正在运行
show variables --
/* 数据库操作 */ ------------------
-- 查看当前数据库
select database();
-- 显示当前时间、用户名、数据库版本
select now(), user(), version();
-- 创建库
create database[ if not exists] 数据库名 数据库选项
数据库选项:
character set charset_name
collate collation_name
-- 查看已有库
show databases[ like 'pattern']
-- 查看当前库信息
show create database 数据库名
-- 修改库的选项信息
alter database 库名 选项信息
-- 删除库
drop database[ if exists] 数据库名
同时删除该数据库相关的目录及其目录内容
/* 表的操作 */ ------------------
-- 创建表
create [temporary] table[ if not exists] [库名.]表名 ( 表的结构定义 )[ 表选项]
每个字段必须有数据类型
最后一个字段后不能有逗号
temporary 临时表,会话结束时表自动消失
对于字段的定义:
字段名 数据类型 [not null | null] [default default_value] [auto_increment] [unique [key] | [primary] key] [comment 'string']
-- 表选项
-- 字符集
charset = charset_name
如果表没有设定,则使用数据库字符集
-- 存储引擎
engine = engine_name
表在管理数据时采用的不同的数据结构,结构不同会导致处理方式、提供的特性操作等不同
常见的引擎:innodb myisam memory/heap bdb merge example csv maxdb archive
不同的引擎在保存表的结构和数据时采用不同的方式
myisam表文件含义:.frm表定义,.myd表数据,.myi表索引
innodb表文件含义:.frm表定义,表空间数据和日志文件
show engines -- 显示存储引擎的状态信息
show engine 引擎名 {logs|status} -- 显示存储引擎的日志或状态信息
-- 数据文件目录
data directory = '目录'
-- 索引文件目录
index directory = '目录'
-- 表注释
comment = 'string'
-- 分区选项
partition by ... (详细见手册)
-- 查看所有表
show tables[ like 'pattern']
show tables from 表名
-- 查看表机构
show create table 表名 (信息更详细)
desc 表名 / describe 表名 / explain 表名 / show columns from 表名 [like 'pattern']
show table status [from db_name] [like 'pattern']
-- 修改表
-- 修改表本身的选项
alter table 表名 表的选项
eg: alter table 表名 engine=myisam;
-- 对表进行重命名
rename table 原表名 to 新表名
rename table 原表名 to 库名.表名 (可将表移动到另一个数据库)
-- rename可以交换两个表名
-- 修改表的字段机构
alter table 表名 操作名
-- 操作名
add[ column] 字段名 -- 增加字段
after 字段名 -- 表示增加在该字段名后面
first -- 表示增加在第一个
add primary key(字段名) -- 创建主键
add unique [索引名] (字段名)-- 创建唯一索引
add index [索引名] (字段名) -- 创建普通索引
add
drop[ column] 字段名 -- 删除字段
modify[ column] 字段名 字段属性 -- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上)
change[ column] 原字段名 新字段名 字段属性 -- 支持对字段名修改
drop primary key -- 删除主键(删除主键前需删除其auto_increment属性)
drop index 索引名 -- 删除索引
drop foreign key 外键 -- 删除外键
-- 删除表
drop table[ if exists] 表名 ...
-- 清空表数据
truncate [table] 表名
-- 复制表结构
create table 表名 like 要复制的表名
-- 复制表结构和数据
create table 表名 [as] select * from 要复制的表名
-- 检查表是否有错误
check table tbl_name [, tbl_name] ... [option] ...
-- 优化表
optimize [local | no_write_to_binlog] table tbl_name [, tbl_name] ...
-- 修复表
repair [local | no_write_to_binlog] table tbl_name [, tbl_name] ... [quick] [extended] [use_frm]
-- 分析表
analyze [local | no_write_to_binlog] table tbl_name [, tbl_name] ...
/* 数据操作 */ ------------------
-- 增
insert [into] 表名 [(字段列表)] values (值列表)[, (值列表), ...]
-- 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。
-- 可同时插入多条数据记录!
replace 与 insert 完全一样,可互换。
insert [into] 表名 set 字段名=值[, 字段名=值, ...]
-- 查
select 字段列表 from 表名[ 其他子句]
-- 可来自多个表的多个字段
-- 其他子句可以不使用
-- 字段列表可以用*代替,表示所有字段
-- 删
delete from 表名[ 删除条件子句]
没有条件子句,则会删除全部
-- 改
update 表名 set 字段名=新值[, 字段名=新值] [更新条件]
/* 字符集编码 */ ------------------
-- mysql、数据库、表、字段均可设置编码
-- 数据编码与客户端编码不需一致
show variables like 'character_set_%' -- 查看所有字符集编码项
character_set_client 客户端向服务器发送数据时使用的编码
character_set_results 服务器端将结果返回给客户端所使用的编码
character_set_connection 连接层编码
set 变量名 = 变量值
set character_set_client = gbk;
set character_set_results = gbk;
set character_set_connection = gbk;
set names gbk; -- 相当于完成以上三个设置
-- 校对集
校对集用以排序
show character set [like 'pattern']/show charset [like 'pattern'] 查看所有字符集
show collation [like 'pattern'] 查看所有校对集
charset 字符集编码 设置字符集编码
collate 校对集编码 设置校对集编码
/* 数据类型(列类型) */ ------------------
1. 数值类型
-- a. 整型 ----------
类型 字节 范围(有符号位)
tinyint 1字节 -128 ~ 127 无符号位:0 ~ 255
smallint 2字节 -32768 ~ 32767
mediumint 3字节 -8388608 ~ 8388607
int 4字节
bigint 8字节
int(m) m表示总位数
- 默认存在符号位,unsigned 属性修改
- 显示宽度,如果某个数不够定义字段时设置的位数,则前面以0补填,zerofill 属性修改
例:int(5) 插入一个数'123',补填后为'00123'
- 在满足要求的情况下,越小越好。
- 1表示bool值真,0表示bool值假。mysql没有布尔类型,通过整型0和1表示。常用tinyint(1)表示布尔型。
-- b. 浮点型 ----------
类型 字节 范围
float(单精度) 4字节
double(双精度) 8字节
浮点型既支持符号位 unsigned 属性,也支持显示宽度 zerofill 属性。
不同于整型,前后均会补填0.
定义浮点型时,需指定总位数和小数位数。
float(m, d) double(m, d)
m表示总位数,d表示小数位数。
m和d的大小会决定浮点数的范围。不同于整型的固定范围。
m既表示总位数(不包括小数点和正负号),也表示显示宽度(所有显示符号均包括)。
支持科学计数法表示。
浮点数表示近似值。
-- c. 定点数 ----------
decimal -- 可变长度
decimal(m, d) m也表示总位数,d表示小数位数。
保存一个精确的数值,不会发生数据的改变,不同于浮点数的四舍五入。
将浮点数转换为字符串来保存,每9位数字保存为4个字节。
2. 字符串类型
-- a. char, varchar ----------
char 定长字符串,速度快,但浪费空间
varchar 变长字符串,速度慢,但节省空间
m表示能存储的最大长度,此长度是字符数,非字节数。
不同的编码,所占用的空间不同。
char,最多255个字符,与编码无关。
varchar,最多65535字符,与编码有关。
一条有效记录最大不能超过65535个字节。
utf8 最大为21844个字符,gbk 最大为32766个字符,latin1 最大为65532个字符
varchar 是变长的,需要利用存储空间保存 varchar 的长度,如果数据小于255个字节,则采用一个字节来保存长度,反之需要两个字节来保存。
varchar 的最大有效长度由最大行大小和使用的字符集确定。
最大有效长度是65532字节,因为在varchar存字符串时,第一个字节是空的,不存在任何数据,然后还需两个字节来存放字符串的长度,所以有效长度是64432-1-2=65532字节。
例:若一个表定义为 create table tb(c1 int, c2 char(30), c3 varchar(n)) charset=utf8; 问n的最大值是多少? 答:(65535-1-2-4-30*3)/3
-- b. blob, text ----------
blob 二进制字符串(字节字符串)
tinyblob, blob, mediumblob, longblob
text 非二进制字符串(字符字符串)
tinytext, text, mediumtext, longtext
text 在定义时,不需要定义长度,也不会计算总长度。
text 类型在定义时,不可给default值
-- c. binary, varbinary ----------
类似于char和varchar,用于保存二进制字符串,也就是保存字节字符串而非字符字符串。
char, varchar, text 对应 binary, varbinary, blob.
3. 日期时间类型
一般用整型保存时间戳,因为php可以很方便的将时间戳进行格式化。
datetime 8字节 日期及时间 1000-01-01 00:00:00 到 9999-12-31 23:59:59
date 3字节 日期 1000-01-01 到 9999-12-31
timestamp 4字节 时间戳 19700101000000 到 2038-01-19 03:14:07
time 3字节 时间 -838:59:59 到 838:59:59
year 1字节 年份 1901 - 2155
datetime “yyyy-mm-dd hh:mm:ss”
timestamp “yy-mm-dd hh:mm:ss”
“yyyymmddhhmmss”
“yymmddhhmmss”
yyyymmddhhmmss
yymmddhhmmss
date “yyyy-mm-dd”
“yy-mm-dd”
“yyyymmdd”
“yymmdd”
yyyymmdd
yymmdd
time “hh:mm:ss”
“hhmmss”
hhmmss
year “yyyy”
“yy”
yyyy
yy
4. 枚举和集合
-- 枚举(enum) ----------
enum(val1, val2, val3...)
在已知的值中进行单选。最大数量为65535.
枚举值在保存时,以2个字节的整型(smallint)保存。每个枚举值,按保存的位置顺序,从1开始逐一递增。
表现为字符串类型,存储却是整型。
null值的索引是null。
空字符串错误值的索引值是0。
-- 集合(set) ----------
set(val1, val2, val3...)
create table tab ( gender set('男', '女', '无') );
insert into tab values ('男, 女');
最多可以有64个不同的成员。以bigint存储,共8个字节。采取位运算的形式。
当创建表时,set成员值的尾部空格将自动被删除。
/* 选择类型 */
-- php角度
1. 功能满足
2. 存储空间尽量小,处理效率更高
3. 考虑兼容问题
-- ip存储 ----------
1. 只需存储,可用字符串
2. 如果需计算,查找等,可存储为4个字节的无符号int,即unsigned
1) php函数转换
ip2long可转换为整型,但会出现携带符号问题。需格式化为无符号的整型。
利用sprintf函数格式化字符串
sprintf("%u", ip2long('192.168.3.134'));
然后用long2ip将整型转回ip字符串
2) mysql函数转换(无符号整型,unsigned)
inet_aton('127.0.0.1') 将ip转为整型
inet_ntoa(2130706433) 将整型转为ip
/* 列属性(列约束) */ ------------------
1. 主键
- 能唯一标识记录的字段,可以作为主键。
- 一个表只能有一个主键。
- 主键具有唯一性。
- 声明字段时,用 primary key 标识。
也可以在字段列表之后声明
例:create table tab ( id int, stu varchar(10), primary key (id));
- 主键字段的值不能为null。
- 主键可以由多个字段共同组成。此时需要在字段列表后声明的方法。
例:create table tab ( id int, stu varchar(10), age int, primary key (stu, age));
2. unique 唯一索引(唯一约束)
使得某字段的值也不能重复。
3. null 约束
null不是数据类型,是列的一个属性。
表示当前列是否可以为null,表示什么都没有。
null, 允许为空。默认。
not null, 不允许为空。
insert into tab values (null, 'val');
-- 此时表示将第一个字段的值设为null, 取决于该字段是否允许为null
4. default 默认值属性
当前字段的默认值。
insert into tab values (default, 'val'); -- 此时表示强制使用默认值。
create table tab ( add_time timestamp default current_timestamp );
-- 表示将当前时间的时间戳设为默认值。
current_date, current_time
5. auto_increment 自动增长约束
自动增长必须为索引(主键或unique)
只能存在一个字段为自动增长。
默认为1开始自动增长。可以通过表属性 auto_increment = x进行设置,或 alter table tbl auto_increment = x;
6. comment 注释
例:create table tab ( id int ) comment '注释内容';
7. foreign key 外键约束
用于限制主表与从表数据完整性。
alter table t1 add constraint `t1_t2_fk` foreign key (t1_id) references t2(id);
-- 将表t1的t1_id外键关联到表t2的id字段。
-- 每个外键都有一个名字,可以通过 constraint 指定
存在外键的表,称之为从表(子表),外键指向的表,称之为主表(父表)。
作用:保持数据一致性,完整性,主要目的是控制存储在外键表(从表)中的数据。
mysql中,可以对innodb引擎使用外键约束:
语法:
foreign key (外键字段) references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作]
此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下,可以设置为null.前提是该外键列,没有not null。
可以不指定主表记录更改或更新时的动作,那么此时主表的操作被拒绝。
如果指定了 on update 或 on delete:在删除或更新时,有如下几个操作可以选择:
1. cascade,级联操作。主表数据被更新(主键值更新),从表也被更新(外键值更新)。主表记录被删除,从表相关记录也被删除。
2. set null,设置为null。主表数据被更新(主键值更新),从表的外键被设置为null。主表记录被删除,从表相关记录外键被设置成null。但注意,要求该外键列,没有not null属性约束。
3. restrict,拒绝父表删除和更新。
注意,外键只被innodb存储引擎所支持。其他引擎是不支持的。
/* 建表规范 */ ------------------
-- normal format, nf
- 每个表保存一个实体信息
- 每个具有一个id字段作为主键
- id主键 + 原子表
-- 1nf, 第一范式
字段不能再分,就满足第一范式。
-- 2nf, 第二范式
满足第一范式的前提下,不能出现部分依赖。
消除符合主键就可以避免部分依赖。增加单列关键字。
-- 3nf, 第三范式
满足第二范式的前提下,不能出现传递依赖。
某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。
将一个实体信息的数据放在一个表内实现。
/* select */ ------------------
select [all|distinct] select_expr from -> where -> group by [合计函数] -> having -> order by -> limit
a. select_expr
-- 可以用 * 表示所有字段。
select * from tb;
-- 可以使用表达式(计算公式、函数调用、字段也是个表达式)
select stu, 29+25, now() from tb;
-- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。
- 使用 as 关键字,也可省略 as.
select stu+10 as add10 from tb;
b. from 子句
用于标识查询来源。
-- 可以为表起别名。使用as关键字。
select * from tb1 as tt, tb2 as bb;
-- from子句后,可以同时出现多个表。
-- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。
select * from tb1, tb2;
c. where 子句
-- 从from获得的数据源中进行筛选。
-- 整型1表示真,0表示假。
-- 表达式由运算符和运算数组成。
-- 运算数:变量(字段)、值、函数返回值
-- 运算符:
=, <=>, <>, !=, <=, <, >=, >, !, &&, ||,
in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor
is/is not 加上ture/false/unknown,检验某个值的真假
<=>与<>功能相同,<=>可用于null比较
d. group by 子句, 分组子句
group by 字段/别名 [排序方式]
分组后会进行排序。升序:asc,降序:desc
以下[合计函数]需配合 group by 使用:
count 返回不同的非null值数目 count(*)、count(字段)
sum 求和
max 求最大值
min 求最小值
avg 求平均值
group_concat 返回带有来自一个组的连接的非null值的字符串结果。组内字符串连接。
e. having 子句,条件子句
与 where 功能、用法相同,执行时机不同。
where 在开始时执行检测数据,对原数据进行过滤。
having 对筛选出的结果再次进行过滤。
having 字段必须是查询出来的,where 字段必须是数据表存在的。
where 不可以使用字段的别名,having 可以。因为执行where代码时,可能尚未确定列值。
where 不可以使用合计函数。一般需用合计函数才会用 having
sql标准要求having必须引用group by子句中的列或用于合计函数中的列。
f. order by 子句,排序子句
order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...
升序:asc,降序:desc
支持多个字段的排序。
g. limit 子句,限制结果数量子句
仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。
limit 起始位置, 获取条数
省略第一个参数,表示从索引0开始。limit 获取条数
h. distinct, all 选项
distinct 去除重复记录
默认为 all, 全部记录
/* union */ ------------------
将多个select查询的结果组合成一个结果集合。
select ... union [all|distinct] select ...
默认 distinct 方式,即所有返回的行都是唯一的
建议,对每个select查询加上小括号包裹。
order by 排序时,需加上 limit 进行结合。
需要各select查询的字段数量一样。
每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。
/* 子查询 */ ------------------
- 子查询需用括号包裹。
-- from型
from后要求是一个表,必须给子查询结果取个别名。
- 简化每个查询内的条件。
- from型需将结果生成一个临时表格,可用以原表的锁定的释放。
- 子查询返回一个表,表型子查询。
select * from (select * from tb where id>0) as subfrom where id>1;
-- where型
- 子查询返回一个值,标量子查询。
- 不需要给子查询取别名。
- where子查询内的表,不能直接用以更新。
select * from tb where money = (select max(money) from tb);
-- 列子查询
如果子查询结果返回的是一列。
使用 in 或 not in 完成查询
exists 和 not exists 条件
如果子查询返回数据,则返回1或0。常用于判断条件。
select column1 from t1 where exists (select * from t2);
-- 行子查询
查询条件是一个行。
select * from t1 where (id, gender) in (select id, gender from t2);
行构造符:(col1, col2, ...) 或 row(col1, col2, ...)
行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。
-- 特殊运算符
!= all() 相当于 not in
= some() 相当于 in。any 是 some 的别名
!= some() 不等同于 not in,不等于其中某一个。
all, some 可以配合其他运算符一起使用。
/* 连接查询(join) */ ------------------
将多个表的字段进行连接,可以指定连接条件。
-- 内连接(inner join)
- 默认就是内连接,可省略inner。
- 只有数据存在时才能发送连接。即连接结果不能出现空行。
on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真)
也可用where表示连接条件。
还有 using, 但需字段名相同。 using(字段名)
-- 交叉连接 cross join
即,没有条件的内连接。
select * from tb1 cross join tb2;
-- 外连接(outer join)
- 如果数据不存在,也会出现在连接结果中。
-- 左外连接 left join
如果数据不存在,左表记录会出现,而右表为null填充
-- 右外连接 right join
如果数据不存在,右表记录会出现,而左表为null填充
-- 自然连接(natural join)
自动判断连接条件完成连接。
相当于省略了using,会自动查找相同字段名。
natural join
natural left join
natural right join
select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;
/* 导入导出 */ ------------------
select * into outfile 文件地址 [控制格式] from 表名; -- 导出表数据
load data [local] infile 文件地址 [replace|ignore] into table 表名 [控制格式]; -- 导入数据
生成的数据默认的分隔符是制表符
local未指定,则数据文件必须在服务器上
replace 和 ignore 关键词控制对现有的唯一键记录的重复的处理
-- 控制格式
fields 控制字段格式
默认:fields terminated by '\t' enclosed by '' escaped by '\\'
terminated by 'string' -- 终止
enclosed by 'char' -- 包裹
escaped by 'char' -- 转义
-- 示例:
select a,b,a+b into outfile '/tmp/result.text'
fields terminated by ',' optionally enclosed by '"'
lines terminated by '\n'
from test_table;
lines 控制行格式
默认:lines terminated by '\n'
terminated by 'string' -- 终止
/* insert */ ------------------
select语句获得的数据可以用insert插入。
可以省略对列的指定,要求 values () 括号内,提供给了按照列顺序出现的所有字段的值。
或者使用set语法。
insert into tbl_name set field=value,...;
可以一次性使用多个值,采用(), (), ();的形式。
insert into tbl_name values (), (), ();
可以在列值指定时,使用表达式。
insert into tbl_name values (field_value, 10+10, now());
可以使用一个特殊值 default,表示该列使用默认值。
insert into tbl_name values (field_value, default);
可以通过一个查询的结果,作为需要插入的值。
insert into tbl_name select ...;
可以指定在插入的值出现主键(或唯一索引)冲突时,更新其他非主键列的信息。
insert into tbl_name values/set/select on duplicate key update 字段=值, …;
/* delete */ ------------------
delete from tbl_name [where where_definition] [order by ...] [limit row_count]
按照条件删除
指定删除的最多记录数。limit
可以通过排序条件删除。order by + limit
支持多表删除,使用类似连接语法。
delete from 需要删除数据多表1,表2 using 表连接操作 条件。
/* truncate */ ------------------
truncate [table] tbl_name
清空数据
删除重建表
区别:
1,truncate 是删除表再创建,delete 是逐条删除
2,truncate 重置auto_increment的值。而delete不会
3,truncate 不知道删除了几条,而delete知道。
4,当被用于带分区的表时,truncate 会保留分区
/* 备份与还原 */ ------------------
备份,将数据的结构与表内数据保存起来。
利用 mysqldump 指令完成。
-- 导出
1. 导出一张表
mysqldump -u用户名 -p密码 库名 表名 > 文件名(d:/a.sql)
2. 导出多张表
mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(d:/a.sql)
3. 导出所有表
mysqldump -u用户名 -p密码 库名 > 文件名(d:/a.sql)
4. 导出一个库
mysqldump -u用户名 -p密码 -b 库名 > 文件名(d:/a.sql)
可以-w携带备份条件
-- 导入
1. 在登录mysql的情况下:
source 备份文件
2. 在不登录的情况下
mysql -u用户名 -p密码 库名 < 备份文件
/* 视图 */ ------------------
什么是视图:
视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来*定义视图的查询所引用的表,并且在引用视图时动态生成。
视图具有表结构文件,但不存在数据文件。
对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。
视图是存储在数据库中的查询的sql语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,如:社会保险基金表,可以用视图只显示姓名,地址,而不显示社会保险号和工资数等,另一原因是可使复杂的查询易于理解和使用。
-- 创建视图
create [or replace] [algorithm = {undefined | merge | temptable}] view view_name [(column_list)] as select_statement
- 视图名必须唯一,同时不能与表重名。
- 视图可以使用select语句查询到的列名,也可以自己指定相应的列名。
- 可以指定视图执行的算法,通过algorithm指定。
- column_list如果存在,则数目必须等于select语句检索的列数
-- 查看结构
show create view view_name
-- 删除视图
- 删除视图后,数据依然存在。
- 可同时删除多个视图。
drop view [if exists] view_name ...
-- 修改视图结构
- 一般不修改视图,因为不是所有的更新视图都会映射到表上。
alter view view_name [(column_list)] as select_statement
-- 视图作用
1. 简化业务逻辑
2. 对客户端隐藏真实的表结构
-- 视图算法(algorithm)
merge 合并
将视图的查询语句,与外部查询需要先合并再执行!
temptable 临时表
将视图执行完毕后,形成临时表,再做外层查询!
undefined 未定义(默认),指的是mysql自主去选择相应的算法。
/* 事务(transaction) */ ------------------
事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。
- 支持连续sql的集体成功或集体撤销。
- 事务是数据库在数据晚自习方面的一个功能。
- 需要利用 innodb 或 bdb 存储引擎,对自动提交的特性支持完成。
- innodb被称为事务安全型引擎。
-- 事务开启
start transaction; 或者 begin;
开启事务后,所有被执行的sql语句均被认作当前事务内的sql语句。
-- 事务提交
commit;
-- 事务回滚
rollback;
如果部分操作发生问题,映射到事务开启前。
-- 事务的特性
1. 原子性(atomicity)
事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2. 一致性(consistency)
事务前后数据的完整性必须保持一致。
- 事务开始和结束时,外部数据一致
- 在整个事务过程中,操作是连续的
3. 隔离性(isolation)
多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。
4. 持久性(durability)
一个事务一旦被提交,它对数据库中的数据改变就是永久性的。
-- 事务的实现
1. 要求是事务支持的表类型
2. 执行一组相关的操作前开启事务
3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。
-- 事务的原理
利用innodb的自动提交(autocommit)特性完成。
普通的mysql执行语句后,当前的数据提交操作均可被其他客户端可见。
而事务是暂时关闭“自动提交”机制,需要commit提交持久化数据操作。
-- 注意
1. 数据定义语言(ddl)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。
2. 事务不能被嵌套
-- 保存点
savepoint 保存点名称 -- 设置一个事务保存点
rollback to savepoint 保存点名称 -- 回滚到保存点
release savepoint 保存点名称 -- 删除保存点
-- innodb自动提交特性设置
set autocommit = 0|1; 0表示关闭自动提交,1表示开启自动提交。
- 如果关闭了,那普通操作的结果对其他客户端也不可见,需要commit提交后才能持久化数据操作。
- 也可以关闭自动提交来开启事务。但与start transaction不同的是,
set autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接)
而start transaction记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)
/* 锁表 */
表锁定只用于防止其它客户端进行不正当地读取和写入
myisam 支持表锁,innodb 支持行锁
-- 锁定
lock tables tbl_name [as alias]
-- 解锁
unlock tables
/* 触发器 */ ------------------
触发程序是与表有关的命名数据库对象,当该表出现特定事件时,将激活该对象
监听:记录的增加、修改、删除。
-- 创建触发器
create trigger trigger_name trigger_time trigger_event on tbl_name for each row trigger_stmt
参数:
trigger_time是触发程序的动作时间。它可以是 before 或 after,以指明触发程序是在激活它的语句之前或之后触发。
trigger_event指明了激活触发程序的语句的类型
insert:将新行插入表时激活触发程序
update:更改某一行时激活触发程序
delete:从表中删除某一行时激活触发程序
tbl_name:监听的表,必须是永久性的表,不能将触发程序与temporary表或视图关联起来。
trigger_stmt:当触发程序激活时执行的语句。执行多个语句,可使用begin...end复合语句结构
-- 删除
drop trigger [schema_name.]trigger_name
可以使用old和new代替旧的和新的数据
更新操作,更新前是old,更新后是new.
删除操作,只有old.
增加操作,只有new.
-- 注意
1. 对于具有相同触发程序动作时间和事件的给定表,不能有两个触发程序。
-- 字符连接函数
concat(str1[, str2,...])
-- 分支语句
if 条件 then
执行语句
elseif 条件 then
执行语句
else
执行语句
end if;
-- 修改最外层语句结束符
delimiter 自定义结束符号
sql语句
自定义结束符号
delimiter ; -- 修改回原来的分号
-- 语句块包裹
begin
语句块
end
-- 特殊的执行
1. 只要添加记录,就会触发程序。
2. insert into on duplicate key update 语法会触发:
如果没有重复记录,会触发 before insert, after insert;
如果有重复记录并更新,会触发 before insert, before update, after update;
如果有重复记录但是没有发生更新,则触发 before insert, before update
3. replace 语法 如果有记录,则执行 before insert, before delete, after delete, after insert
/* sql编程 */ ------------------
--// 局部变量 ----------
-- 变量声明
declare var_name[,...] type [default value]
这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个default子句。值可以被指定为一个表达式,不需要为一个常数。如果没有default子句,初始值为null。
-- 赋值
使用 set 和 select into 语句为变量赋值。
- 注意:在函数内是可以使用全局变量(用户自定义的变量)
--// 全局变量 ----------
-- 定义、赋值
set 语句可以定义并为变量赋值。
set @var = value;
也可以使用select into语句为变量初始化并赋值。这样要求select语句只能返回一行,但是可以是多个字段,就意味着同时为多个变量进行赋值,变量的数量需要与查询的列数一致。
还可以把赋值语句看作一个表达式,通过select执行完成。此时为了避免=被当作关系运算符看待,使用:=代替。(set语句可以使用= 和 :=)。
select @var:=20;
select @v1:=id, @v2=name from t1 limit 1;
select * from tbl_name where @var:=30;
select into 可以将表中查询获得的数据赋给变量。
-| select max(height) into @max_height from tb;
-- 自定义变量名
为了避免select语句中,用户自定义的变量与系统标识符(通常是字段名)冲突,用户自定义变量在变量名前使用@作为开始符号。
@var=10;
- 变量被定义后,在整个会话周期都有效(登录到退出)
--// 控制结构 ----------
-- if语句
if search_condition then
statement_list
[elseif search_condition then
statement_list]
...
[else
statement_list]
end if;
-- case语句
case value when [compare-value] then result
[when [compare-value] then result ...]
[else result]
end
-- while循环
[begin_label:] while search_condition do
statement_list
end while [end_label];
- 如果需要在循环内提前终止 while循环,则需要使用标签;标签需要成对出现。
-- 退出循环
退出整个循环 leave
退出当前循环 iterate
通过退出的标签决定退出哪个循环
--// 内置函数 ----------
-- 数值函数
abs(x) -- 绝对值 abs(-10.9) = 10
format(x, d) -- 格式化千分位数值 format(1234567.456, 2) = 1,234,567.46
ceil(x) -- 向上取整 ceil(10.1) = 11
floor(x) -- 向下取整 floor (10.1) = 10
round(x) -- 四舍五入去整
mod(m, n) -- m%n m mod n 求余 10%3=1
pi() -- 获得圆周率
pow(m, n) -- m^n
sqrt(x) -- 算术平方根
rand() -- 随机数
truncate(x, d) -- 截取d位小数
-- 时间日期函数
now(), current_timestamp(); -- 当前日期时间
current_date(); -- 当前日期
current_time(); -- 当前时间
date('yyyy-mm-dd hh:ii:ss'); -- 获取日期部分
time('yyyy-mm-dd hh:ii:ss'); -- 获取时间部分
date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); -- 格式化时间
unix_timestamp(); -- 获得unix时间戳
from_unixtime(); -- 从时间戳获得时间
-- 字符串函数
length(string) -- string长度,字节
char_length(string) -- string的字符个数
substring(str, position [,length]) -- 从str的position开始,取length个字符
replace(str ,search_str ,replace_str) -- 在str中用replace_str替换search_str
instr(string ,substring) -- 返回substring首次在string中出现的位置
concat(string [,...]) -- 连接字串
charset(str) -- 返回字串字符集
lcase(string) -- 转换成小写
left(string, length) -- 从string2中的左边起取length个字符
load_file(file_name) -- 从文件读取内容
locate(substring, string [,start_position]) -- 同instr,但可指定开始位置
lpad(string, length, pad) -- 重复用pad加在string开头,直到字串长度为length
ltrim(string) -- 去除前端空格
repeat(string, count) -- 重复count次
rpad(string, length, pad) --在str后用pad补充,直到长度为length
rtrim(string) -- 去除后端空格
strcmp(string1 ,string2) -- 逐字符比较两字串大小
-- 流程函数
case when [condition] then result [when [condition] then result ...] [else result] end 多分支
if(expr1,expr2,expr3) 双分支。
-- 聚合函数
count()
sum();
max();
min();
avg();
group_concat()
-- 其他常用函数
md5();
default();
--// 存储函数,自定义函数 ----------
-- 新建
create function function_name (参数列表) returns 返回值类型
函数体
- 函数名,应该合法的标识符,并且不应该与已有的关键字冲突。
- 一个函数应该属于某个数据库,可以使用db_name.funciton_name的形式执行当前函数所属数据库,否则为当前数据库。
- 参数部分,由"参数名"和"参数类型"组成。多个参数用逗号隔开。
- 函数体由多条可用的mysql语句,流程控制,变量声明等语句构成。
- 多条语句应该使用 begin...end 语句块包含。
- 一定要有 return 返回值语句。
-- 删除
drop function [if exists] function_name;
-- 查看
show function status like 'partten'
show create function function_name;
-- 修改
alter function function_name 函数选项
--// 存储过程,自定义功能 ----------
-- 定义
存储存储过程 是一段代码(过程),存储在数据库中的sql组成。
一个存储过程通常用于完成一段业务逻辑,例如报名,交班费,订单入库等。
而一个函数通常专注与某个功能,视为其他程序服务的,需要在其他语句中调用函数才可以,而存储过程不能被其他调用,是自己执行 通过call执行。
-- 创建
create procedure sp_name (参数列表)
过程体
参数列表:不同于函数的参数列表,需要指明参数类型
in,表示输入型
out,表示输出型
inout,表示混合型
注意,没有返回值。
/* 存储过程 */ ------------------
存储过程是一段可执行性代码的集合。相比函数,更偏向于业务逻辑。
调用:call 过程名
-- 注意
- 没有返回值。
- 只能单独调用,不可夹杂在其他语句中
-- 参数
in|out|inout 参数名 数据类型
in 输入:在调用过程中,将数据输入到过程体内部的参数
out 输出:在调用过程中,将过程体处理完的结果返回到客户端
inout 输入输出:既可输入,也可输出
-- 语法
create procedure 过程名 (参数列表)
begin
过程体
end
/* 表维护 */
-- 分析和存储表的关键字分布
analyze [local | no_write_to_binlog] table 表名 ...
-- 检查一个或多个表是否有错误
check table tbl_name [, tbl_name] ... [option] ...
option = {quick | fast | medium | extended | changed}
-- 整理数据文件的碎片
optimize [local | no_write_to_binlog] table tbl_name [, tbl_name] ...
/* 杂项 */ ------------------
1. 可用反引号(`)为标识符(库名、表名、字段名、索引、别名)包裹,以避免与关键字重名!中文也可以作为标识符!
2. 每个库目录存在一个保存当前数据库的选项文件db.opt。
3. 注释:
单行注释 # 注释内容
多行注释 /* 注释内容 */
单行注释 -- 注释内容 (标准sql注释风格,要求双破折号后加一空格符(空格、tab、换行等))
4. 模式通配符:
_ 任意单个字符
% 任意多个字符,甚至包括零字符
单引号需要进行转义 \'
5. cmd命令行内的语句结束符可以为 ";", "\g", "\g",仅影响显示结果。其他地方还是用分号结束。delimiter 可修改当前对话的语句结束符。
6. sql对大小写不敏感
7. 清除已有语句:\c
MySQL学习笔记
Chapter 1. MySQL数据库的数据
MySQL数据库是由数据组成的,为了能方便管理和使用这些数据,我们把这些数据进行分类,形成各种数据类型,有数据值的类型,有表中数据列的类型,有数据表的类型。理解MySQL的这些数据类型能使我们更好地使用MySQL数据库。下面对各种数据类型进行简单的介绍。
1.1. 数据值类型(data type)
对MySQL中数据值的分类,有数值型、字符型、日期型和空值等,这和一般的编程语言的分类差不多。
1.1.1. 数值
MySQL中的数值分整型和浮点型两种。MySQL支持科学记数法。整型可以是十进制,也可是十六进制数。
1.1.2. 字符串
MySQL支持以单或双引号包围的字符序列。如“MySQL tutorial”、‘Mysql Database’。
MySQL能识别字符串中的转义序列,转义序列用反斜杠(\)表示。下面是一个转义序列列表。
Table 1.1. 转义序列
转义序列 | 含义 |
---|---|
\0 | NUL(ASCII的0值) |
\' | 单引号 |
\" | 双引号 |
\b | 后退符 |
\n | 换行符 |
\r | 回车符 |
\t | 制表符 |
\\ | 反斜杠 |
\Z | Ctrl+Z |
如果字符串本身包含有单双引号,则用以下三种方法中的一种来表示:
字符串的引号和字符串两端的引号双同,则双写该引号。如:'mysql''s test'。
用与字符串的引号不同的引号把字符串引起来,如:"mysql's test"。
用反斜杠转义引号,如:"mysql\' test",'mysql\' test'。这样就不用理会字符串两端的是单引号还是双引号了。
字符串可由一个十六进制数表示,如0x61表示字符"a"。由MySQL 4.0开始,字符串值也可用ANSI SQL表示法X'val'来表示。如X'61'表示字符"a"。
从MySQL 4.1开始,可以为字符串值专门指定一个字符集。
1.1.3. 日期和时间
MySQL默认按“年-月-日”的顺序显示日期。
1.2. 列类型(column type)
MySQL数据库的表是一个二维表,由一个或多个数据列构成。每个数据列都有它的特定类型,该类型决定了MySQL如何看待该列数据,我们可以把整型数值存放到字符类型的列中,MySQL则会把它看成字符串来处理。MySQL中的列类型有三种:数值类、字符串类和日期/时间类。从大类来看列类型和数值类型一样,都是只有三种。但每种列类型都还可细分。下面对各种列类型进行详细介绍。
1.2.1. 数值类的数据列类型
数值型的列类型包括整型和浮点型两大类。
Table 1.2. 数值类数据列类型
数据列类型 | 存储空间 | 描述 |
---|---|---|
TINYINT | 1字节 | 非常小的正整数,带符号:-128~127,不带符号:0~255 |
SMALLINT | 2字节 | 小整数,带符号:-32768~32767,不带符号:0~65535 |
MEDIUMINT | 3字节 | 中等大小的整数,带符号:-8388608~8388607,不带符号:0~16777215 |
INT | 4字节 | 标准整数,带符号:-2147483648~2147483647,不带符号:0~4294967295 |
BIGINT | 8字节 | 大整数,带符号:-9223372036854775808~9233372036854775807,不带符号:0~18446744073709551615 |
FLOAT | 4字节 | 单精度浮点数,最小非零值:+-1.175494351E-38,最大非零值:+-3.402823466E+38 |
DOUBLE | 8字节 | 双精度浮点数,最小非零值:+-2.2250738585072014E-308,最大非零值:+-1.7976931348623157E+308 |
DECIMAL | M+2字节 | 以字符串形式表示的浮点数,它的取值范围可变,由M和D的值决定。 |
1.2.1.1. 整型数据列类型
MySQL有五种整型数据列类型,即TINYINT,SMALLINT,MEDIUMINT,INT和BIGINT。它们之间的区别是取值范围不同,存储空间也各不相同。在整型数据列后加上UNSIGNED属性可以禁止负数,取值从0开始。
声明整型数据列时,我们可以为它指定个显示宽度M(1~255),如INT(5),指定显示宽度为5个字符,如果没有给它指定显示宽度,MySQL会为它指定一个默认值。显示宽度只用于显示,并不能限制取值范围和占用空间,如:INT(3)会占用4个字节的存储空间,并且允许的最大值也不会是999,而是INT整型所允许的最大值。
1.2.1.2. 浮点型数据列类型
MySQL有三种浮点型数据列类型,分别是:FLOAT,DOUBLE和DECIMAL。浮点类数据类型有一个最大可表示值和一个最小非零可表示值,最小非零可表示值决定了该类型的精确度。
MySQL 4.0.2版之后,FLOAT和DOUBLE都可以指定UNSIGNED属性。当指定该属性时,取值范围不平移到正数区间,而只是简单地把浮点类型的负数部份去掉。
浮点类型也有M(1~255)和D(1~30,且不能大于M-2)。分别表示显示宽度和小数位数。M和D在FLOAT和DOUBLE中是可选的,默认,当MySQL版本大于3.23.6时,FLOAT和DOUBLE类型将被保存为硬件所支持的最大精度。DECIMAL的M和D值在MySQL3.23.6后可选,默认D值为0,M值为10。
1.2.1.3. 如何选择数值类数据列类型?
为了节省存储空间和提高数据库处理效率,我们应根据应用数据的取值范围来选择一个最适合的数据列类型。如果把一个超出数据列取值范围的数存入该列,则MySQL就会截短该值,如:我们把99999存入SMALLINT(3)数据列里,因为SMALLINT(3)的取值范围是-32768~32767,所以就会被截短成32767存储。显示宽度3不会影响数值的存储。只影响显示。
对于浮点数据列,存入的数值会被该列定义的小数位进行四舍五入。如把一个1.234存入FLOAT(6.1)数据列中,结果是1.2。
DECIMAL与FLOAT和DOUBLE的区别是:DECIMAL类型的值是以字符串的形式被储存起来的,它的小数位数是固定的。它的优点是,不会象FLOAT和DOUBLE类型数据列那样进行四舍五入而产生误差,所以很适合用于财务计算;而它的缺点是:由于它的存储格式不同,CPU不能对它进行直接运算,从而影响运算效率。DECIMAL(M,D)总共要占用M+2个字节。
1.2.1.4. 数值类数据列的属性
ZEROFILL属性适用于所有数值类数据列类型,作用是,如果数值的宽度小于定义的显示宽度,则在数值前填充0。
UNSIGNED属性不允许数据列出现负数。
AUTO_INCREMENT属性可生成独一无二的数字序列。只对整数类的数据列有效。
NULL和NOT NULL属性设置数据列是否可为空。
DEFAULT属性可为数据列指定默认值。
1.2.2. 字符串类数据列类型
字符串可以用来表示任何一种值,所以它是最基本的类型之一。我们可以用字符串类型来存储图象或声音之类的二进制数据,也可存储用gzip压缩的数据。下表介绍了各种字符串类型:
Table 1.3. 字符串类数据列类型
类型 | 最大长度 | 占用存储空间 |
---|---|---|
CHAR[(M)] | M字节 | M字节 |
VARCHAR[(M)] | M字节 | L+1字节 |
TINYBLOD,TINYTEXT | 2^8-1字节 | L+1字节 |
BLOB,TEXT | 2^16-1字节 | L+2 |
MEDIUMBLOB,MEDIUMTEXT | 2^24-1字节 | L+3 |
LONGBLOB,LONGTEXT | 2^32-1字节 | L+4 |
ENUM('value1','value2',...) | 65535个成员 | 1或2字节 |
SET('value1','value2',...) | 64个成员 | 1,2,3,4或8字节 |
L+1、L+2是表示数据列是可变长度的,它占用的空间会根据数据行的增减面则改变。数据行的总长度取决于存放在这些数据列里的数据值的长度。L+1或L+2里多出来的字节是用来保存数据值的长度的。在对长度可变的数据进行处理时,MySQL要把数据内容和数据长度都保存起来。
如果把超出字符串最大长度的数据放到字符类数据列中,MySQL会自动进行截短处理。
ENUM和SET类型的数据列定义里有一个列表,列表里的元素就是该数据列的合法取值。如果试图把一个没有在列表里的值放到数据列里,它会被转换为空字符串(“”)。
字符串类型的值被保存为一组连续的字节序列,并会根据它们容纳的是二进制字符串还是非二进制字符而被区别对待为字节或者字符:
二进制字符串被视为一个连续的字节序列,与字符集无关。MySQL把BLOB数据列和带BINARY属性的CHAR和VARCHAR数据列里的数据当作二进制值。
非二进制字符串被视为一个连续排列的字符序列。与字符集有关。MySQL把TEXT列与不带BINARY属性的CHAR和VARCHAR数据列里的数据当作二进制值对待。
在MySQL4.1以后的版本中,不同的数据列可以使用不同的字符集。在MySQL4.1版本以前,MySQL用服务器的字符集作为默认字符集。
非二进制字符串,即我们通常所说的字符串,是按字符在字符集中先后次序进行比较和排序的。而二进制字符串因为与字符集无关,所以不以字符顺序排序,而是以字节的二进制值作为比较和排序的依据。下面介绍两种字符串的比较方式:
二进制字符串的比较方式是一个字节一个字节进行的,比较的依据是两个字节的二进制值。也就是说它是区分大小写的,因为同一个字母的大小写的数值编码是不一样的。
非二进制字符串的比较方式是一个字符一个字符进行的,比较的依据是两个字符在字符集中的先后顺序。在大多数字符集中,同一个字母的大小写往往有着相同的先后顺序,所以它不区分大小写。
二进制字符串与字符集无关,所以无论按字符计算还是按字节计算,二进制字符串的长度都是一样的。所以VARCHAR(20)并不表示它最多能容纳20个字符,而是表示它最多只能容纳可以用20个字节表示出来的字符。对于单字节字符集,每个字符只占用一个字节,所以这两者的长度是一样的,但对于多字节字符集,它能容纳的字符个数肯定少于20个。
1.2.2.1. CHAR和VARCHAR
CHAR和VARCHAR是最常用的两种字符串类型,它们之间的区别是:
CHAR是固定长度的,每个值占用相同的字节,不够的位数MySQL会在它的右边用空格字符补足。
VARCHAR是一种可变长度的类型,每个值占用其刚好的字节数再加上一个用来记录其长度的字节即L+1字节。
CHAR(0)和VARCHAR(0)都是合法的。VARCHAR(0)是从MySQL4.0.2版开始的。它们的作用是作为占位符或用来表示各种on/off开关值。
如何选择CHAR和VARCHAR,这里给出两个原则:
如果数据都有相同的长度,选用VARCHAR会多占用空间,因为有一位用来存储其长度。如果数据长短不一,选用VARCHAR能节省存储空间。而CHAR不论字符长短都需占用相同的空间,即使是空值也不例外。
如果长度出入不大,而且是使用MyISAM或ISAM类型的表,则用CHAR会比VARCHAR好,因为MyISAM和ISAM类型的表对处理固定长度的行的效率高。
在一个数据表里,只要有一个数据列的长度是可变的,则所有数据列的长度将是可变的。MySQL会进行自动地转换。一个例外,CHAR长度小于4的不会进行自动转换,因为MySQL会认为这样做没必要,节省不了多少空间。反而MySQL会把大量长度小的VARCHAR转换成CHAR,以减少空间占用量。 |
1.2.2.2. BLOB和TEXT
BLOB是二进制字符串,TEXT是非二进制字符串。两者都可存放大容量的信息。
有关BLOB和TEXT索引的建立:
BDB表类型和MySQL3.23.2以上版本的MyISAM表类型允许在BLOB和TEXT数据列上建立索引。
ISAM、HEAP和InnoDB表不支持大对象列的索引。
使用BLOB和TEXT应注意的问题:
由于这两个列类型所存储的数据量大,所以删除和修改操作容易在数据表里产生大量的碎片,需定期运行OPTIMIZE TABLE以减少碎片和提高性能。
如果使用的值非常巨大,就需对服务器进行相应的优化调整,增加max_allowed_packet参数的值。对那些可会用到变些巨大数据的客户程序,也需加大它们的数据包大小。
1.2.2.3. ENUM和SET
ENUM和SET都是比较特殊的字符串数据列类型,它们的取值范围是一个预先定义好的列表。ENUM或SET数据列的取值只能从这个列表中进行选择。ENUM和SET的主要区别是:
ENUM只能取单值,它的数据列表是一个枚举集合。它的合法取值列表最多允许有65535个成员。例如:ENUM("N","Y")表示,该数据列的取值要么是"Y",要么就是"N"。
SET可取多值。它的合法取值列表最多允许有64个成员。空字符串也是一个合法的SET值。
ENUM和SET的值是以字符串形式出现的,但在内部,MySQL以数值的形式存储它们。
ENUM的合法取值列表中的字符串被按声明定义的顺序被编号,从1开始。
SET的编号不是按顺序进行编号的,SET中每一个合法取值都对应着SET值里的一个位。第一个合法取值对应0位,第二个合法取值对应1位,以此类推,如果数值形式的SET值等于0,则说明它是一个空字符串,如果某个合法的取值出现在SET数据列里,与之对应的位就会被置位;如果某个合法的取值没有出现在SET数据列里,与之对应的位就会被清零。正因为SET值与位有这样的对应关系,所以SET数据列的多个合法取值才能同时出现并构成SET值。
1.2.2.4. 字符串类型数据列的字符集属性
在MySQL 4.1以前的版本,字符串数据列的字符集由服务器的字符决定,MySQL 4.1版以后的版本可对每个字符串数据列指定不同的字符串。如果按默认方式设置,可按数据列、数据表、数据库、服务器的顺序关联字符串的字符集,直到找一个明确定义的字符集。
1.2.3. 日期,时间型数据列类型
MySQL的日期时间类型有:DATE,DATETIME,TIME,TIMESTAMP和YEAR,下表是这些类型的取值范围和存储空间要求:
Table 1.4. 日期,时间类型列
类型 | 取值范围 | 存储空间 | 零值表示法 |
---|---|---|---|
DATE | 1000-01-01~9999-12-31 | 3字节(MySQL3.23版以前是4字节 ) | 0000-00-00 |
TIME | -838:59:59~838:59:59 | 3字节 | 00:00:00 |
DATETIME | 1000-01-01 00:00:00~9999-12-31 23:59:59 | 8字节 | 0000-00-00 00:00:00 |
TIMESTAMP | 19700101000000~2037年的某个时刻 | 4字节 | 00000000000000 |
YEAR | YEAR(4):1901~2155 YEAR(2):1970~2069 | 1字节 | 0000 |
MySQL总是把日期和日期里的年份放在最前面,按年月日的顺序显示。 |
1.2.3.1. DATE、TIME、DATATIME数据列类型
DATE、TIME和DATATIME类型分别存放日期值、时间值、日期和时间值的组合。它们的格式分别是“CCYY-MM-DD”、“hh:mm:ss”、“CCYY-MM-DD hh:mm:ss”。
DATATIME里的时间值和TIME值是有区别的,DATATIME里的时间值代表的是几点几分,TIME值代表的是所花费的时间。当向TIME数据列插值时,需用时间的完整写法,如12分30秒要写成“00:12:30”。
1.2.3.2. TIMESTAMP数据列类型
TIMESTAMP数据列的格式是CCYYMMDDhhmmss,取值范围从19700101000000开始,即1970年1月1号,最大到2037年。它的特点是能把数据行的创建或修改时间记录下来:
如果把一个NULL值插入TIMESTAMP列,这个数据列就将自动取值为当前的日期和时间。
在创建和修改数据行时,如果没有明确对TIMESTAMP数据列进行赋值,则它就会自动取值为当前的日期和时间。如果行中有多个TIMESTAMP列,只有第一个会自动取值。
如果对TIMESTAMP设置一个确定的日期和时间值,则会使TIMESTAMP的自动取值功能失效。
TIMESTAMP默认的列宽是14,可指定列宽,以改变显示效果。但不论你指定的列宽如何,MySQL都是以4字节来存储TIMESTAMP值,也总是以14位精度来计算。
如果需要把创建时间和最近一次修改时间同时记录下来,可以用两个时间戳来记录,一个记录创建时间,一个记录修改时间。不过需记住两件事,一是要把记录修改时间的TIMESTAMP数据列放在最前面,这样才会自动取值;二是创建一条新记录时,要用now()函数来初始化创建时间TIMESTAMP数据列,这样,该TIMESTAMP数据列就不会再变化。
1.2.3.3. YEAR
YEAR是一种单字节的数据列类型,YEAR(4)的取值范围是1901~2155,YEAR(2)的取值范围是1970~2069,但只显示最后两位数。MySQL能自动把两位数字年份转换成四位数字的年份,如97和14分被转换成1997和2014。转换规则是这样的:
年份值00~69将被转换成2000~2069;
年份值70~99将被转换成1970~1999。
00被转换成0000,而不是2000。因为数值00也就是0,而0值是YEAR的一个合法取值。 |
1.3. 唯一编号
在数据库应用,我们经常要用到唯一编号,以标识记录。在MySQL中可通过数据列的AUTO_INCREMENT属性来自动生成。MySQL支持多种数据表,每种数据表的自增属性都有差异,这里将介绍各种数据表里的数据列自增属性。
-
ISAM表
如果把一个NULL插入到一个AUTO_INCREMENT数据列里去,MySQL将自动生成下一个序列编号。编号从1开始,并1为基数递增。
把0插入AUTO_INCREMENT数据列的效果与插入NULL值一样。但不建议这样做,还是以插入NULL值为好。
当插入记录时,没有为AUTO_INCREMENT明确指定值,则等同插入NULL值。
当插入记录时,如果为AUTO_INCREMENT数据列明确指定了一个数值,则会出现两种情况,情况一,如果插入的值与已有的编号重复,则会出现出错信息,因为AUTO_INCREMENT数据列的值必须是唯一的;情况二,如果插入的值大于已编号的值,则会把该插入到数据列中,并使在下一个编号将从这个新值开始递增。也就是说,可以跳过一些编号。
如果自增序列的最大值被删除了,则在插入新记录时,该值被重用。
如果用UPDATE命令更新自增列,如果列值与已有的值重复,则会出错。如果大于已有值,则下一个编号从该值开始递增。
如果用replace命令基于AUTO_INCREMENT数据列里的值来修改数据表里的现有记录,即AUTO_INCREMENT数据列出现在了replace命令的where子句里,相应的AUTO_INCREMENT值将不会发生变化。但如果replace命令是通过其它的PRIMARY KEY OR UNIQUE索引来修改现有记录的(即AUTO_INCREMENT数据列没有出现在replace命令的where子句中),相应的AUTO_INCREMENT值--如果设置其为NULL(如没有对它赋值)的话--就会发生变化。
last_insert_id()函数可获得自增列自动生成的最后一个编号。但该函数只与服务器的本次会话过程中生成的值有关。如果在与服务器的本次会话中尚未生成AUTO_INCREMENT值,则该函数返回0。
其它数据表的自动编号机制都以ISAM表中的机制为基础。
-
MyISAM数据表
删除最大编号的记录后,该编号不可重用。
可在建表时可用“AUTO_INCREMENT=n”选项来指定一个自增的初始值。
可用alter table table_name AUTO_INCREMENT=n命令来重设自增的起始值。
可使用复合索引在同一个数据表里创建多个相互独立的自增序列,具体做法是这样的:为数据表创建一个由多个数据列组成的PRIMARY KEY OR UNIQUE索引,并把AUTO_INCREMENT数据列包括在这个索引里作为它的最后一个数据列。这样,这个复合索引里,前面的那些数据列每构成一种独一无二的组合,最末尾的AUTO_INCREMENT数据列就会生成一个与该组合相对应的序列编号。
-
HEAP数据表
HEAP数据表从MySQL4.1开始才允许使用自增列。
自增值可通过CREATE TABLE语句的 AUTO_INCREMENT=n选项来设置。
可通过ALTER TABLE语句的AUTO_INCREMENT=n选项来修改自增始初值。
编号不可重用。
HEAP数据表不支持在一个数据表中使用复合索引来生成多个互不干扰的序列编号。
-
BDB数据表
不可通过CREATE TABLE OR ALTER TABLE的AUTO_INCREMENT=n选项来改变自增初始值。
可重用编号。
支持在一个数据表里使用复合索引来生成多个互不干扰的序列编号。
-
InnDB数据表
不可通过CREATE TABLE OR ALTER TABLE的AUTO_INCREMENT=n选项来改变自增初始值。
不可重用编号。
不支持在一个数据表里使用复合索引来生成多个互不干扰的序列编号。
在使用AUTO_INCREMENT时,应注意以下几点:
AUTO_INCREMENT是数据列的一种属性,只适用于整数类型数据列。
设置AUTO_INCREMENT属性的数据列应该是一个正数序列,所以应该把该数据列声明为UNSIGNED,这样序列的编号个可增加一倍。
AUTO_INCREMENT数据列必须有唯一索引,以避免序号重复。
AUTO_INCREMENT数据列必须具备NOT NULL属性。
AUTO_INCREMENT数据列序号的最大值受该列的数据类型约束,如TINYINT数据列的最大编号是127,如加上UNSIGNED,则最大为255。一旦达到上限,AUTO_INCREMENT就会失效。
-
当进行全表删除时,AUTO_INCREMENT会从1重新开始编号。全表删除的意思是发出以下两条语句时:
delete from table_name;
or
truncate table table_name这是因为进行全表操作时,MySQL实际是做了这样的优化操作:先把数据表里的所有数据和索引删除,然后重建数据表。如果想删除所有的数据行又想保留序列编号信息,可这样用一个带where的delete命令以抑制MySQL的优化:
delete from table_name where 1;
这将迫使MySQL为每个删除的数据行都做一次条件表达式的求值操作。
-
强制MySQL不复用已经使用过的序列值的方法是:另外创建一个专门用来生成AUTO_INCREMENT序列的数据表,并做到永远不去删除该表的记录。当需要在主数据表里插入一条记录时,先在那个专门生成序号的表中插入一个NULL值以产生一个编号,然后,在往主数据表里插入数据时,利用LAST_INSERT_ID()函数取得这个编号,并把它赋值给主表的存放序列的数据列。如:
insert into id set id = NULL;
insert into main set main_id = LAST_INSERT_ID(); 可用alter命令给一个数据表增加一个具有AUTO_INCREMENT属性的数据列。MySQL会自动生成所有的编号。
要重新排列现有的序列编号,最简单的方法是先删除该列,再重建该,MySQL会重新生连续的编号序列。
-
在不用AUTO_INCREMENT的情况下生成序列,可利用带参数的LAST_INSERT_ID()函数。如果用一个带参数的LAST_INSERT_ID(expr)去插入或修改一个数据列,紧接着又调用不带参数的LAST_INSERT_ID()函数,则第二次函数调用返回的就是expr的值。下面演示该方法的具体操作:
先创建一个只有一个数据行的数据表:
create table seq_table (id int unsigned not null);
insert into seq_table values (0);
接着用以下操作检索出序列号:
update seq_table set seq = LAST_INSERT_ID( seq + 1 );
select LAST_INSERT_ID();
通过修改seq+1中的常数值,可生成不同步长的序列,如seq+10可生成步长为10的序列。该方法可用于计数器,在数据表中插入多行以记录不同的计数值。再配合LAST_INSERT_ID()函数的返回值生成不同内容的计数值。这种方法的优点是不用事务或LOCK,UNLOCK表就可生成唯一的序列编号。不会影响其它客户程序的正常表操作。
1.4. 字符集支持
MySQL4.1以前版本服务器只能使用单一字符集,从MySQL4.1版本开始,不仅服务器能够使用多种字符集,而且在服务器、数据库、数据表、数据列以及字符串常数多个级别上设置不同的字符集。
1.4.1. MySQL4.1以前版本
MySQL4.1以前版本的字符集由服务器默认指定,默认值是编译系统时指定的字符集,该字符集也可通过在启动服务器时指定--default-character-set来修改。这种修改会对数据表的索引造成影响,因为索引的顺序是和字符集有关的,修改字符集会使这个已排序的顺序产生错误。要解决该问题,我们要用修改后的字符集的排序顺序重建表的索引。重建索引有以下几种方法:
用mysqldump导出数据,再清除表里的内容,最后用导出文件重新导入。数据表的索引将在导入数时重建。该方法适用于所有数据表类型。
删除索引,然后重建。用alter table命令或drop index和create index命令来完成。该方法也适用于所有数据表类型。但该方法需要我们了解重建索引的精确定义。
MyISAM数据表的索引可以用myisamchk程序的--recover和--quick选项加上一个用来设定新字符集的--set-character-set选项进行重建。还可以用mysqlcheck程序的--repair和--quick选项或者一个带QUICK选项的REPLACE TABLE语句来重建索引,这种方式较方便。
1.4.2. MySQL4.1以后版本
MySQL4.1以后的版本对字符集的支持好了很多,具有以下新增功能:
支持服务器同时使用多种字符集。
-
允许在服务器,数据库,数据表,数据列等多级别上设置不同的字符集。
服务器的默认字符集在编译时选定,但可在启动服务器时用--default-character-set选项来更改。
用ALTER DATABASE db_name DEFAULT CHARACTER SET charset来设置数据库字符集。 如果只有default参数,则使用服务器的字符集。
用CREATE TABLE table_name(...) CHARACTER SET = charset设置数据表字符集。如果charset为default,则使用数据表所在数据库的字符集作为数据表的字符集。
在数据列中,可用CHARACTER SET charset属性来设置数据列的字符集。charset不能是default,如果没有该属性,则默认使用数据表的字符集。允许设置字符集的数据列有char,varchar(不带binary属性)及TEXT类型。
用_charset str转换字符串常数的字符集。如:_utf8 'mysql',_latinl 'oracle'。该方法只适用于括在引号内的字符串,其它十六进制常数 、字符串表达式等可用CONVERT()函数进行转换,如:SELECT CONVERT( str USING charset)。
通过MySQL提供的函数可进行字符集转换和查询。
新增的COLLATE操作符使我们可按某一种字符集的排序顺序来处理另一种字符集的数据。如:SELECT a from t ORDER BY a COLLATE utf-8;
用SHOW CHARACTER SET命令可显示服务器支持的字符集列表。
当服务器转换到另一种字符集时,会自动对索引进行重新排序。
通过UTF-8和UCS2字符集提供了Unicode支持。
MySQL现在还不支持:1,在同一个字符串里混用不同字符集的字符;2,在同一个数据列里混用不同的字符集。
1.4.3. 各级字符集的查询方法
-
服务器级
SHOW CHARACTER SET;可查出可供使用的所有字符集。
SHOW VARIABLES LIKE 'character_set';可查出服务器的默认字符集。 -
可查出数据库级的字符集。
SHOW CREATE DATABASE db_name;
-
两条命令可查出数据表的字符集。
SHOW CREATE TABLE table_name;
SHOW TABLE STATUS LIKE 'table_name' -
以下几命令可查出数据列的字符集:
DESCRIBE table_name;
SHOW COLUMNS FROM table_name;
SHOW CREATE TABLE table_name; 用CHARSET()函数可确定特定字符串,字符串表达式或数据列值相关联的字符串的字符集。如:SELECT CHARSET(str)。
1.4.4. Unicode支持
MySQL提供两种字符集来支持Unicode。一个是UTF-8,一种可变长的编码格式,需用1至4个字节来表示一个字符;另一个是UCS2,该字符集中的每个字符需要用两个字节来表示。
1.5. 如何选择数据列类型?
选择正确的数据列类型能大大提高数据库的性能和使数据库具有高扩展性。在选择数据列类型时,请从以下几个方面考虑:
存放到数据列中的数据类型。
数据值的取值范围。
-
考虑性能和处理效率。
数值操作比字符操作快。
小类型的处理速度比大类型快。
-
不同数据表中固定长度类型和可变长度类型的处理效率是不同的。
可变长度类型在经过删除和修改操作后容易产生碎片,降低系统性能,需定期运行OPTIMIZE TABLE命令以优化数据表。
固定长度类型由于有固定的长度,所以容易确定每条记录的起始点,可加快数据表的修复速度。
在MyISAM和ISAM表中使用固定长度类型数据列有助改善数据库性能。
在InnoDB表中,固定长度和可变长度数据列类型都以相同方式存储,所以固定长度数据列类型并没有性能优势,反而由于可度长度数据列类型由于占用存储空间较少,所以处理速度会快些。
可索引类型能加快数据的查询速度。
明确指定数据列的NOT NULL属性可使MySQL在检索过程中不用去判断数据列是否是NULL,所以可加快处理速度。
数据如何进行比较,是否区分大小写。
是否要在数据列上建立索引。
1.6. 表达式操作符
Table 1.5. 算术操作符
操作符 | 语法 | 含义 |
---|---|---|
+ | a + b | 相加 |
- | a - b | 相减 |
- | - a | 求负 |
* | a * b | 乘法 |
/ | a / b | 除法 |
% | a % b | 求余 |
Table 1.6. 逻辑操作符
操作符 | 语法 | 含义 |
---|---|---|
AND 或 && | a AND b 或 a && b | 逻辑与,若两个操作数同时为真,则为真 |
OR 或 || | a OR b 或 a || b | 逻辑或,只要有一个操作数为真,则为真 |
XOR | a XOR b | 逻辑异或,若有且仅有一个操作数为真,则为真 |
NOT 或 ! | NOT a 或 !a | 逻辑非,若操作数为假,则为真 |
Table 1.7. 位操作符
操作符 | 语法 | 含义 |
---|---|---|
& | a & b | 按位与,若操作数同位同为1,则该位为1 |
| | a | b | 按位或,若操作数同位有一位为1,则该位为1 |
^ | a ^ b | 按拉异或,若操作数同一位分别为1和0,则该位为1 |
<< | a << b | 把a中的各个位左移b个位置 |
>> | a >> b | 把a中的各个位右移b个位置 |
Table 1.8. 比较操作符
操作符 | 语法 | 含义 |
---|---|---|
= | a = b | 若两个操作数相等,则为真 |
<=> | a <=> b | 若两个操作数相等,则为真,可用于NULL值比较 |
!= 或 <> | a != b 或 a <> b | 若两个操用数不等,则为真 |
< | a < b | 若a小于b,则为真 |
<= | a <= b | 若a小于或等于b,则为真 |
> | a > b | 若a大于b,则为真 |
>= | a > b | 若a大于或等于b,则为真 |
IN | a IN (b1,b2,...) | 若a等于b1,b2,...中的某一个,则为真 |
BETWEEN | a BETWEEN b AND c | 若a在b和c之间(包括b和c),则为真 |
NOT BETWEEN | a NOT BETWEEN b AND c | 若a不在b和c之间(包括b和c),则为真 |
LIKE | a LIKE b | SQL模式匹配,若a匹配b,则为真 |
NOT LIKE | a NOT LIKE b | SQL模式匹配,若a不匹配b,则为真 |
REGEXP | a REGEXP b | 正则表达式匹配,若a匹配b,则为真 |
NOT REGEXP | a NOT REGEXP b | 正则表达式匹配,若a不匹配b,则为真 |
IS NULL | a IS NULL | 若a为NULL,则为真 |
IS NOT NULL | a IS NOT NULL | 若a不为NULL,则为真 |
LIKE模式匹配中的“%”匹配任意个字符,“_”匹配一个字符。匹配不区分大小写字符。 |
Table 1.9. 操作符优先级(由高至低排列)
操作符 |
---|
BINARY,COLLATE |
NOT、! |
^ |
XOR |
-(一元求负操作符)、~(一元取反操作符) |
*、/、% |
+、- |
<<、>> |
& |
| |
<、<=、=、<=>、!=、<>、>=、>、IN、IS、LIKE、REGEXP、RLIKE |
BETWEEN、CASE、WHEN、THEN、ELSE |
AND、&& |
OR、|| |
:= |
1.7. 类型转换
在MySQL的表达式中,如果某个数据值的类型与上下文所要求的类型不相符,MySQL则会根据将要进行的操作自动地对数据值进行类型转换。如:
1 + '2' 会转换成1 + 2 = 3
1+ 'abc' 会转换成1 + 0 = 1 由于abc不能转换成任何的值,所以默认为0
MySQL会根据表达式上下文的要求,把字符串和数值自动转换为日期和时间值
对于超范围或非法的值,MySQL也会进行转换,但转换出来的结果是错误的。出现该情况时,MySQL会提示警告信息,我们可捕获该信息以进行相应的处理。
Chapter 2. 查询优化
Table of Contents
数据库是数据的集合,与数学的集合论有密不可分的关系。
为提高查询速度,我们可以:
对数据表添加索引,以加快搜索速度;
通过编程技巧最大限度地利用索引;
优化查询语句,以使服务器最快响应多客户的请求。
研究硬件处理过程,减少物理约束。
2.1. 索引
索引技术是关系数据查询中最重要的技术。如果要加提升数据库的性能,索引优化是首先应该考虑的。因为它能使我们的数据库得到最大性能方面的提升。
索引的优点:
没有索引的表是没有排序的数据集合,如果要查询数据需进行全表扫描。有索引的表是一个在索引列上排序了数据表,可通过索引快速定位记录。在MyISAM和ISAM数据表中,数据行保存在数据文件中,索引保存在索引文件中。BDB与InnoDB数据表把数据与索引放在同一个文件中。
在多表关联查询中,索引的作用就更大。如果没有索引,在最坏的情况下,全表扫描的次数可能是各表数据行的组合个数,可能是一个天文数字。这样的查询是破坏性的,可能会造成数据库瘫痪。
对于使用了MIN()或是MAX()函数的查询,如果相关的数据列上有索引,MySQL能直接找到该最大、最小值的行,根本不用一个一个地去检查数据行。
索引加快ORDER BY 和 GROUP BY子句的操作。
当在数值型数据列上查询数据,而该列有索引,索引能使MySQL根本不用去读取数据行,直接从索引取值。
索引的缺点:
索引需占用磁盘空间。
索引会减慢在索引数据列上的插入、删除和修改操作。
索引列的选择
索引应该创建在搜索、排序、分组等操作所涉及的数据列上。也就是说,在where子句,关联检索中的from子句、order by或group by子句中出现过的数据列最适合用来创建索引。
尽量使用唯一索引,它能使索引发挥最好的效能。
尽量用比较短的值进行索引。当对字符串进行索引时,应该指定一个前缀长度,比如对字符串的前10位或20位的字符进行排序,而不用把整个字符串几十个字符用来索引排序。这样能减少磁盘I/O,提高处理速度。最重要的一点是,键值越短,索引缓冲区里容纳的键值也就越多,而MySQL同时保存在内存里的索引越多,索引缓冲区的命中率也就越高。当然,只对数据列第一个字符进行索引是没什么意义的。
充分利用最左前缀。所谓最左前缀也就是在复合索引中最边的索引列。如复合索引(a,b,c) ,其中a就是最左前缀。它是使用率最高的索引,需认真选择。
不要建太多索引,索引是会消耗系统资源的,要适可而止。
索引主要用于<、<=、=、>=、>、BETWEEN等的比较操作中,所以索引应该建立在与这样操作相关的数据列上。
利用慢查询日志来找出性能差的查询,通过mysqldumpslow可查看该日志。针对性能差的查询可利用索引来加快查询速度。
2.2. 查询优化程序
当我们发一条查询命令时,MySQL分对它进行分析,以优化查询。把explain语名放到查询前面可显示查询的执行路线,对优化查询提供有用的信息。以下几个原则可帮助系统挑选和使用索引:
尽量对同类型的数据列进行比较。如:VARCHAR(5)和VARCHAR(5)是同类型的,CHAR(5)和VARCHAR(5)是不同类型的。
尽量让索引的数据列在比较表达式中单独出现,不要把它包含在函数或复杂表达式。否则索引会不起作用。
尽量不要在LIKE模式的开头使用通配符。如:%string%。
对于MyISAM和BDB数据表,用ANALYZE TABLE语句让服务器对索引键值的分布进行分析,为优化程序提供更有价值的信息。另一个方法是用myisamchk --analyze(适用于MyISAM表)或isamchk --analyze(适用于ISAM表)命令。
用EXPLAIN语句来分析查询语句的执行效率。检查查询所使用的索引是不是能够迅速地排除不符合条件的数据行,如果不是,可以试着用STRAIGHT_JOIN强制各有关数据表按指定顺序进行关联。
尝试查询的不同写法,比较运行情况。
不要滥用MySQL的类型自动转换功能。自动转换会减慢查询的速度并会使有关的索引失效。
2.3. 数据列类型与查询效率
选用适当的数据列类型有助于提高查询命令的执行速度,下面是几点关于如何选择合适数据列类型的建议:
尽量选用尺寸较小的数据列。这样能节约磁盘空间和加快查询速度。如果较短的数据列上建有索引,则索引的处理速度会进一步提高。
针对数据列类型,尽量选择最适用的数据表类型。如固定长度数据列在MyISAM或ISAM数据表中的速度是最快的,所以在这样数据表中尽量使用char类型而不是varchar类型来保存字符串数据。对于InnoDB数据表类型,由于varchar类型可有效减少占用空间,从而减少磁盘I/O,所以使用varchar类型是有利的。对于BDB类型数据表,使用定长和不定长列类型的区别就不大,可任选一种。
尽量把数据列声明为NOT NULL,以节约存储空间和加快处理速度。
对于取值范围有限的数据列,考虑使用ENUM数据列类型。ENUM数据列类型在MySQL中的处理速度是很快。
-
使用PROCEDURE ANALYSE()语句来分析数据表,它会对数据列的声明提出建议,我们可根据建议进行修改。
select * from table_name PROCEDURE ANALYSE();
select * from table_name PROCEDURE ANALYSE(16,256); #(16,256)含义是:如果某列的不同取值在16个以上或长度超过256字节,就不提出使用ENUM的建议。 -
用OPTIMIZE TABLE语句对容易出现碎片的数据表进行整理。包含可变长数据列的数据表都会产生碎片,从而占用多余的磁盘空间和影响查询速度。所以要定期运行OPTIMIZE TABLE语句以防止数据表查询性能降低。但该语句只对MyISAM数据表有效。对各种数据表通用的碎片整理方法是这样的:先用工具程序mysqldump导出数据表,再删除数据表后重建,如:
$ mysqldump --opt db_name table_name > dump.sql
$ mysql db_name < dump.sql 把非结构化和变化大的数据放在BLOB数据列里,定期用OPTIMIZE TABLE命令优化。
人为地给数据表增加一个数据列,以充当索引。做法是这样的,先根据数据表里的其它数据列计算出一个散列值,并保存在一个数据列里,然后通过搜索散列值来检索数据行。注意,该技巧只适用于精确匹配型查询。散列值在大于,小于等的操作中不起作用。散列值可以MD5()(适用于3.23及以上版本),SHA1()(适用于4.0.1及以上版本),CRC32()(适用于4.1及以上版本)等函数生成。使用散列值支检索BLOB和TEXT值的做法比直接检索BLOB和TEXT本身的做法快。
尽量避免对大尺寸的BLOB值进行检索。如果要检索都应该通过它的上面提到散列值先进行筛选。而不应该盲目地在网络中传送大量BLOB值。
如果把BLOB值剥离到另外一个数据表里去,可实现数据表中其它数据列转变成固定长度数据列的话。就即可减少数据表碎片,又可使在原始表中的select *查询不会把大尺寸的BLOB值不必要地通过网络传送。
2.4. 有效地加载数据
有时我们需大量地把数据加载到数据表,采用批量加载的方式比一个一个记录加载效率高,因为MySQL不用每加载一条记录就刷新一次索引。下面介绍几个有助于加快数据加载的操作:
使用LOAD DATA语句要比INSERT语句的加载速度快。
LOAD DATA比LOAD DATA LOCAL语句的效率高。前者可由服务器直接从本地磁盘读取加载数据,后者需由客户程序去读取文件并通过网络传送到服务器。
如果一定要用INSERT语句,应尽量在一条语句中插入多个数据行。
-
如果必须使用多条INSERT语句,则应尽量把它们集中在一起放到一个事务中进行处理,而不是在自动提交模式下执行它们:如:
BEGIN;
INSERT INTO table_name values (...);
INSERT INTO table_name values (...);
INSERT INTO table_name values (...);
...
COMMIT;对于不支持事务的表,应对表进行写锁定,然后在表锁定期间对表进行INSERT操作,如:
LOCK TABLES table_name WRITE;
INSERT INTO table_name ...;
INSERT INTO table_name ...;
INSERT INTO table_name ...;
...
UNLOCK TABLES; 利用客户/服务器通信协议中的压缩功能以减少网络传输的数据量。但该压缩会消耗大量的系统资源,所以小心使用。
尽量让MySQL插入默认值。不要在INSERT中写太多值,以减少网络传输量和服务器端的语法分析时间。
对于MyISAM和ISAM数据表,如果需加载大量数据,应先建立一个没索引的表,加载数据后再创建索引。该方法不适用于InnoDB或BDB数据表。
禁用和重新激活索引的方法有两种:
-
使用ALTER TABLE语句的DISABLE KEYS和ENABLE KEYS命令,如:
ALTER TABLE table_name DISABLE KEYS;
ALTER TABLE table_name ENABLE KEYS; -
使用myisamchk或isamchk工具。如:
$ myisamchk --keys-used=0 table_name #禁止
$ myisamchk --recover --quick --key-used=n table_name #激活
n是用来表明需要激活索引的位掩码,第0位对应第一个索引,如果有三个索引,n值就是7(二进制111)。索引编号可以下命令确定:
$ myisamchk --description table_name
2.5. 调度和锁定
在很多客户一起查询数据表时,如果使客户能最快地查询到数据就是调度和锁定做的工作了。在MySQL中,我们把select操作叫做读,把对数据表修改增加的操作(INSERT,UPDATE,REPLACE...)叫做写。MySQL的基本调度策略可以归纳为以下两条:
写入请求将按它们到达服务器的顺序进行处理;
写操作的优先级要高于读操作。
MyISAM和ISAM数据表的调度策略是在数据表锁的帮助下实现的,在客户程序要访问数据表之前,需获得相应的锁,在完成对数据表的操作后,再释放该锁。锁的管理通常由服务器管理,也可人为地用LOCK TABLES和UNLOCK TABLES命令来申请和释放锁。写操作时,需要申请一个独占性的锁,也就是说在写操作其间,该表只能由写操作的客户使用。读操作时,客户必须申请一个允许其他客户对数据表进行写操作的锁,以确保客户在读的过程中数据表不会发生改变。但读操作锁不是独占的,可有多个读操作同时作用于同一个数据表。
通过一些修饰符可影响调度策略,如LOW_PRIORITY(用于DELETE,INSERT,LOAD DATA,REPLACE,UPDATE语句)、HIGH_PRIORITY(用于SELECT语句)、DELAYED(用于INSERT和REPLACE语句)。它们的作用是这样的:
LOW_PRIORITY会使写操作的优先级降低到读操作以下,也就是说读操作会阻塞该级别的写操作,SELECT的HIGH_PRIORITY有类似的作用。
INSERT语句中的DELAYED修饰会使插入操作被放入一个“延迟插入”队列。并返回状态信息给客户,使客户程序可在新数据行还没插入到数据表之前继续执行后面的操作。如果一直有客户读该数据表,新数据行会一直待在队列中,直到数据表没有读操作时,服务器才会把队列中的数据行真正插入到数据表中。该语句可用在以下场合,在一个有冗长查询的数据表中插入数据,而你又不想被阻塞,你就可发出INSERT DELAYED语句,把插入操作放入服务器“延迟插入”队列,你无需等待就马上可进行接下来的操作。
-
当一个数据表里从未进行过删除操作或刚刚对它进行过碎片整理的情况下,用INSERT语句插入的数据行只会被添加到数据表的末尾,而不会插入到数据表的中间位置。这样,对于MyISAM表,MySQL允许在有其它客户正在读操作的时间进行写操作。我们称之这并发插入。要使用该技巧,需注意以下两个问题:
不要在INSERT语句中使用LOW_PRIORITY修饰符。
读操作应用LOCK TABLES ... READ LOCAL而不是用LOCK TABLES ... READ语句来进行数据表读锁定。LOCAL关键字只对数据表中已存在行进行锁定,不会阻塞把新行添加到数据表末尾。
BDB数据表使用页面级操作锁,InnoDB数据表使用数据行级操作锁。所以这两种表的并发性比MyISAM和ISAM数据表这种表级锁的并发性会好很多。其中InnoDB的并发性最好。综上所述,我们可得出以下结论:
MyISAM和ISAM数据表的检索速度最快,但如果在检索和修改操作较多的场合,会出锁竞争的问题,造成等待时间延长。
BDB和InnoDB数据表能在有大量修改操作的环境下提供很好的并发性,从而提供更好的性能。
MyISAM和ISAM数据表由于进行表级锁定,所以不会出现死锁现象,BDB和InnoDB数据表则存在死锁的可能性。
2.6. 服务器优化
优化原则:
内存里的数据要比磁盘上的数据访问起来快;
站数据尽可能长时间地留在内存里能减少磁盘读写活动的工作量;
让索引信息留在内存里要比让数据记录的内容留在内存里更重要。
针对以上几个原则,我们应该调整服务器:
-
增加服务器的缓存区容量,以便数据在内存在停留的时间长一点,以减少磁盘I/0。下面介绍几个重要的缓冲区:
-
数据表缓冲区存放着与打开的数据表相的信息,它的大小可由服务器参数“table_cache”设置。Opened_tables参数记录服务器进行过多少次数据表打开操作,如果该值变化很大,就可能是数据表缓冲区已满,需把一些不常用的表移出缓冲区,以腾出空打开新的数据表。可用以下命令查看Opened_tables的值:
SHOW STATUS LIKE 'Opened_tables';
在MyISAM和ISAM数据表中,索引被缓存在“key buffer”里,它的大小由服务器参数“key_buffer_size”来控制。系统默认的大小是8M,如果内存充足的话可适当扩大该值,以使更多索引块缓存在该区里,以加快索引的速度。
InnoDB和BDB数据表也各有一个缓冲区,分别叫innodb_buffer_pool_size和bdb_cache_size。InnoDB还有一个日志缓冲区叫innodb_log_buffer_size。
-
自4.0.1开始,MySQL多了一个缓冲区,叫查询缓冲区,主要用来存放重复执行的查询文本和结果,当再次遇到相同的查询,服务器会直接从缓冲区中返回结果。该功能是内建的功能,如不想支持该功能,可在编译服务器时用configure脚本的--without-query-cache选项去掉该功能。
查询缓冲区由三个服务器参数控制,分别是:
1、query_cache_size
控制缓冲区的大小,如果该值为0,则禁用查询缓冲功能。设置方法是在选项文件中设置:
[mysqld]
set-variable = query_cache_size = 16M
这样就设置了一个16M的查询缓冲区 2、query_cache_limit
缓冲结果集的最大容量(以字节为单位),如果查询的结果集大于该值,则不缓冲该值。 3、query_cache_type
缓冲区的操作模式。
0表示不进行缓冲;
1表示除SELECT SQL_NO_CACHE开头的查询外,其余的都缓冲;
2表示只对以SELECT SQL_ON_CACHE开头的查询进行缓冲。默认情况下,按服务器的设置进行缓冲,但客户端也可通过命令改变服务器设置。客户端可直接用SELECT SQL_NO_CACHE和SELECT SQL_CACHE命令来要求服务器缓冲或不缓冲查询结果。如果不想每条查询都写参数,我们也可在客户端用SET SQL_QUERY_CACHE_TYPE = val;来改变服务器的查询缓冲行为。val可取值0,1,2或OFF,ON,或DEMAND。
-
禁用用不着的数据表处理程序。如服务器是从源码创建,就可彻底禁用ISAM,InnoDB和BDB数据表。
权限表里的权限关系应尽可能简单,当然了,是要在保证安全的前提下。
在从源码创建服务器时,尽量使用静态库而不是共享库来完成其配置工作。静态库的执行速度更快,但如果要加载用户定义函数(UDF)的话,就不能使用静态库,因为UDF机制必须依赖动态库才能实现。
2.7. 硬件优化
为了提高数据运行速度,升级硬件是最直接的解决方案。针对数据库应用的特点,在升级硬件时应考虑以下内容:
对于数据库服务器,内存是最重要的一个影响性能因素。通过加大内存,数据库服务器可把更多的数据保存在缓冲区,可大大减少磁盘I/O,从而提升数据库的整体性能。
配置高速磁盘系统,以减少读盘的等待时间,提高响应速度。
合理分布磁盘I/O,应把磁盘I/O分散在多个设备上,以减少资源竞争,提高并行操作能力。
配置多处理器,MySQL是多线程的数据库,多处理器可同时执行多个线程。
Chapter 3. 数据库管理
Table of Contents
数据库是一个复杂而又关键的系统,为确保系统安全、高效运行,需熟悉数据库内部的运作机制,掌握各种维护工具,并做好日常的管理工作。下面列举几项主要工作职责:
服务器的关闭和启动;
管理用户帐号;
管理日志文件;
数据库备份恢复;
数据库优化;
确保数据库数据安全;
数据库软件升级。
3.1. 数据目录
数据目录是用来存放数据表和相关信息的地方,是数据库的核心。在MySQL中的数据目录根据不同平台的有一些差异:
在UNIX/Linux系统上,如果用源码编译安装,数据目录的位置默认是在/usr/local/mysql/var中;
在UNIX/Linux系统上,如果用二进制发行版安装,数据目录的位置默认是在/usr/local/mysql/data中;
在WINDOWS系统上,数据目录的位置默认是在c:/mysql/data中;
在服务器启动时,可用--datadir=dir_name来指定数据目录,也可把它写到配置文件中。 |
我们还可用命令向服务器查询数据目录的位置,数据目录的变量名是datadir,如:
-
% mysqladmin variables
如果在一台机器上同时运行多个服务器,则可根据端口的不时来查询每个服务器的数据目录,如:
% mysqladmin --host=127.0.0.1 --port=port_number variables
如果--host是localhost,系统则会用一个UNIX套接字去连接数据库服务器,这时要使用--socket选项,所以查询语句变成:
% mysqladmin --host=localhost --socket=/path/to/socket variables
mysql> SHOW VARIABLES LIKE 'datadir';
-
在windows NT平台上可以使用“.”作为一条命名管道连接的主机名,用--socket选项给出命名管道的名字,如:
c:\ mysqladmin --host=. --socket=pipe_name variables
配置文件的中[mysqld]段中的datadir=/path/to/datadir设置也可查询到数据目录。
-
在mysqld程序的帮助信息里也有程序编译时默认的数据目录信息,可用以下命令显示:
% mysqld --help
数据目录是存放数据文件的地方,每个数据库对应目录的不同文件。InnoDB数据表由于用表空间来管理数据库,所以就没这种对应关系。但也是保存在数据目录中的,在数据目录除保存数据库文件外,还可能会保存以下几类文件:
服务器的配置文件,my.cnf;
服务器的进程ID(PID)文件;
服务器的日志文件和状态文件,这些文件对管理数据库有重要的价值;
DES密钥文件或服务器的SSL证书与密钥文件。
数据目录中的所有数据库全部由服务器(mysqld)来管理,客户端不直接操作数据。服务器是客户使用数据的唯一通道。
在MySQL中,每个数据库其实就是在数据目录下一个子目录,show databases命令相当于列出数据目录中的目录清单。create database db_name命令会在数据目录下新建一个db_name的目录,以存放数据库的数据文件。所以我们也可下面的shell命令方式来建立一个空数据库:
% cd datadir
% mkdir db_name
% chmod u=rwx,go-rwx db_name
同理,删除数据库drop database db_name也就是删除数据目录中一个名为db_name的目录及目录中的数据表文件。我们也可用shell这进行操作:
% cd datadir
% rm -rf db_name
比较shell方式与drop database方式,drop database db_name命令不能删除db_name目录中创建的其它非数据表文件;由于InnoDB是表空间来管理数据表,所以不能用rm或del命令删除InnoDB的数据表。 |
3.2. MySQL数据表在系统中表现形式
MySQL数据表类型有:ISAM、MyISAM、MERGE、BDB、InnoDB和HEAP。每种数据表在文件系统中都有不同的表示方式,有一个共同点就是每种数据表至少有一个存放数据表结构定义的.frm文件。下面介绍每种数据表文件:
-
ISAM数据表是最原始的数据表,有三个文件,分别是:
.frm,存放数据表的结构定义;
.ISD,数据文件,存放数据表中的各个数据行的内空;
.ISM,索引文件,存放数据表的所有索引信息。
-
MyISAM数据表是ISAM数据表的继承者,也有三个文件,分别是:
.frm,结构定义文件;
.MYD,数据文件;
.MYI,索引文件。
-
MERGE数据表是一个逻辑结构,代表一组结构完全相同的MyISAM数据表构成的集合。它在文件系统中有二个文件,分别是:
.frm,结构定义文件;
.MRG,构成MERGE表的MyISAM数据表清单,每个MyISAM数据表名占一行。也就是说可通过改变该表的内容来改变MERGE数据表的结构。修改前请先刷新缓存(flush tables),但不建议这样修改MERGE数据表。
-
BDB数据表用两个文件来表示,分别是:
.frm,结构定义文件;
.db,数据表数据和索引文件
InnoDB由于采用表空间的概念来管理数据表,所以它只有一个与数据表对应.frm文件,同一目录下的其它文件表示为表空间,存储数据表的数据和索引。
HEAP数据表是一个存在于内存中的表,所以它的数据和索引都存在于内存中,文件系统中只有一个.frm文件,以定义结构。
了解MySQL数据表在文件系统中表现形式后,我们可知道,创建、修改或删除数据表,其实就是对这些文件进行操作。例如一些数据表(除InnoDB和HEAP数据表外),我们可直接在文件系统中删除相应的文件来删除数据表。
% cd datadir
% rm -f mydb/mydb.*
以上命令可删除mydb数据库中的mydb数据表。
3.3. 数据表最大尺寸限制
在MySQL中影响数据表尺寸的因素有很多,下面分别进行介绍:
-
MySQL数据表类型的不同对数据表尺寸的限制:
ISAM数据表中单个.ISD和.ISM文件的最大尺寸为4G;
MyISAM数据表中单个.MYD和.MYI文件的默认最大尺寸也是4G,但可在创建数据表时用AVG_ROW_LENGTH和MAX_ROWS选项把这个最值扩大到800万TB。
MERGE数据表的最大尺寸是它的各组成MyISAM数据表的最大尺寸之和。
BDB数据表的尺寸受限于BDB处理程序所允许的.db文件的最大尺寸。这个最大尺寸随着数据表页面尺寸(编译时确定)而变化,但即使是最小的页面尺寸(512字节),.db文件的最大尺寸也可达2TB。
InnoDB数据表的表空间的最大尺寸是40亿个页面,默认的页面尺寸是16K,该值可在8K到64K之间,在编译时确定。InnoDB数据表的最大尺寸也就是表空间的最大尺寸。
操作系统对文件的尺寸限制,一般文件系统都对单个文件不得超过2G的限制。该约束会对数据库文件造成限制。InnoDB数据表可通过利用未格式化硬盘作为表空间来绕过该限制。
对于数据和索引分开两个文件存放的数据表,其中任何一个文件达到操作系统文件的最大限制,数据库表也就达到最大尺寸。
包含AUTO_INCREMENT数据列的表受到该数据列类型最大上限值的限制。
由于InnoDB数据表用表空间来管理,一个表空间可同时空纳多个数据表,所以数据表的最大尺寸受系统文件和同一表空间中数据表空间的约束。
3.4. 状态文件和日志文件
在MySQL数据目录中还包含着许多状态文件和日志文件,这些文件的文件名都是以主机名加上相关后缀来命名的。下面是这些文件的一个说明列表:
Table 3.1. 状态文件和日志文件
文件类型 | 默认名 | 文件内容 |
---|---|---|
进程ID文件 | hostname.pid | MySQL服务器进程的ID |
常规查询日志 | hostname.log | 连接/断开连接事件和查询信息 |
慢查询日志 | hostname-slow.log | 记录查询时间很长的命令信息 |
变更日志 | hostname.nnn | 创建或修改数据表结构和内容的查询命令信息 |
二进制变更日志 | hostname-bin.nnn | 创建或修改数据表结构和内容的查询命令的二进制表示法 |
二进制变更日志的索引文件 | hostname-bin.index | 使用中的“二进制变更日志”列表 |
错误日志 | hostname.err | 记录“启动/关闭”事件和异常情况 |
变更日志和二进制变更日志主要用于MySQL数据库服务器的崩溃恢复中,由于变更日志记录了数据库的所有变更操作,所以可以进行事件重放。具体操作请参考相关数据库备份恢复章节。对于变更日志,我们可用--log-long-format选项来让它以扩展方式记录有关事件。扩展方式可记录谁发出查询和什么时候发出查询的信息。可使我们更好地掌握客户端的操作情况。日志记录着查询命令的所有操作,里面可能会有一些敏感信息。所以我们要确保日志文件的安全。
3.5. 调整MySQL数据目录位置
MySQL数据库的数据目录位置,包括目录里的各种文件的位置)可根据实际情况进行调整。调整的方法有两种,一种是使用符号链接;一种用服务器启动选项。下面一个列表说明了数据目录及目录中文件各自适宜采用的方法:
Table 3.2. MySQL数据目录及目录中文件位置的调整方法
调整对象 | 适用方法 |
---|---|
整个数据目录 | 启动选项和符号链接 |
数据库目录 | 符号链接 |
数据表 | 符号链接 |
InnoDB数据表空间 | 启动选项 |
PID文件 | 启动选项 |
日志文件 | 启动选项 |
下面是各种调整方法的具体操作过程:
在调整MySQL的数据目录时,要先停止服务器,再把数据目录移动到新的位置。接着,我们可选择在原来目录下创建一个符号链接指向新的位置,或者用启动选择--datadir指向新的数据目录。推荐用创建符号链接的方法,因为如果那个数据目录中有my.cnf文件,相应的服务器还能找到它。
-
数据库只能存在于MySQL数据目录中,所以只能使用符号链接的方法调整它的位置。在Linux系统的操作步骤如:
关闭服务器;
把数据库目录拷贝到新的位置;
删除原来的数据库目录;
在原来的MySQL数据目录中创建一个同名符号链接指向新的位置;
重新启动服务器。
在windows下的操作方法不些不同,操作方法如下:
关闭服务器;
把数据库目录移动新的位置;
删除原来的数据库目录;
在原来数据目录下建一个同名的.sym文件,在文件中输入数据库新目录的全路径,如c:\mysql\newdir\mydb。这个文件就相当于Linux下的符号链接;
-
重启服务器。
为了支持符号链接功能,必须用--use-symbolic-links选项启动服务器;或在选项文件的[mysqld]节中添加use-symbolic-links选项。 MySQL必须是3.23.16以上版本且是max服务器(mysqld-max或mysqld-max-nt)。
-
要移动数据表,必须满足以下所有条件才行:
MySQL的版本必须是4.0或以上的版本;
操作系统必须有一个可用的realpath()调用;
移动的数据表必须是MyISAM类型的数据表。
在满足以上所有条件后,我们就可把.MYD数据文件和MYI索引文件移到新位置,再在原来位置创建两个同名符号链接指定新的位置。注意,.frm定义文件仍需留在原来的数据库目录中。
如以上条件不能全部满足,最好不要移动数据表文件。否则一旦你运行ALTER TABLE、OPTIMIZE TABLE、REPAIR TABLE语句对移动过的数据表进行优化或修改,这样数据表就会回到原来的位置,使移动操作失效。因为这些命令的执行过程是这样的:它会先在数据目录中创建一个临时数据表并对这个临时数据表进行优化或修改,然后删除原来的数据表(这里是你为了移动数据表而创建的一个符号链接),再把临时数据表更名为原来的数据表名称。这样一来,你移走的数据表就和这个数据库完全没有关系了。基于以下的不稳定因素,如无特殊必要,不建议移动数据表。
-
InnoDB表空间是通过在选项文件中使用innodb_data_home_dir和innodb_data_file_path选项列出InnoDB表空间组成文件清单的方法来配置的,所以我们可通过修改这些选项来重新安置InnoDB表空间的组成文件。步骤如下:
关闭服务器;
移动组成表空间的文件;
修改选项文件,指出组成表空间的文件的新位置;
重启服务器。
状态文件和日志文件的位置可通过选项文件或启动服务器时指定。
Chapter 4. MySQL数据库日常管理
Table of Contents
为了确保数据库平稳可靠运行,我们需进行维护和管理,这是每一位数据库管理员的职责。下面分几个专题分别介绍。
4.1. 数据库安全管理
MySQL数据库通过用户和密码来控制用户对数据库的访问,当我们新安装了一个数据库服务器时,MySQL的权限表设置是很不安全,它默认允许任何人不需要密码就可访问数据库。所以我们安装好服务器后第一件需要做的就是设置用户密码。
在MySQL中的mysql数据库的user数据表中存有用户的帐号信息,在初始状态下已存在root和一些匿名用户,且所有用户都没有设置密码。该数据表的这些用户信息是通过一个mysql_install_db脚本安装的。该表的主要列有:
User,连接数据库的用户名。
Host,允许连接到数据库服务器的主机名,“%”通配符代表所有主机。
Password,连接密码,已加密。
其它权限列,以“Y”或“N”标识是否有效。
在这种状态下的数据库是极不安全的,我们可用以下命令轻易地访问数据库:
% mysql -h localhost -u root #通过本地主机,root用户访问,不需要密码验证
% mysql -h localhost #通过本地主机,匿名用户访问,不需要密码验证
设置MySQL用户帐号密码的方法有三种:
-
使用mysqladmin程序:
% mysqladmin -h localhost -u root password "password" #设置在本地以root身分登录的密码
% mysqladmin -h remote -u root password "password" #设置远程主机以root身分登录的密码在初始设置时,这两条语句都要运行,以确保数据库本地访问和网络访问的安全。
-
通过set password这条SQL语句设置:
mysql> set password for 'root'@'localhost' = password('password');
mysql> set password for 'root'@'remote' = password('password'); -
直接修改user权限表:
mysql> use mysql;
mysql> update user set password=password('password') where user='root';
mysql> flush privileges; #重载权限表,使修改马上生效MySQL使用驻留在内存中的权限表拷贝来进行访问控制,当使用mysqladmin和set password设置密码,MySQL会监察到权限表已被修改,它自动重载该表。而用update的方式,MySQL就监察不到变化,需手动用flush privileges命令刷新内存中的权限表,以使它马上生效。
为root用户设置密码后,如果需以root身份连接数据库,就需验证密码。我们可用以下语句连接数据库:
% mysql -u root -p
Enter password: #输入root的密码
在user表中,user列为空的为匿名用户。它也是没有密码的,我们需为它们设置一个密码,或干脆把它们删除。在windows系统上的本地匿名用户帐号和root用户有着同样的权限,这是一个很大的安全漏洞。应该把它删除或把权限削弱。
4.2. 服务器的启动和关闭
在Linux和windows平台下MySQL服务器的启动方式有很大不同,这里将分开介绍:
-
Linux平台:
Linux平台下,每一个进程都需由一个用户来运行,MySQL最好不要以root用户来运行。我们可创建一个mysql用户和mysql组,MySQL服务器程序目录和数据目录由这个用户和组所拥有,其它用户没有任何权限。以mysql用户来运行MySQL服务器。
% mysqld --user=mysql #即使以root用户执行该命令,MySQL数据库还是会与mysql用户ID关联。
为了使服务器在系统启动时自动以mysql用户运行,需配置my.cnf配置文件 ,把user=mysql包含在[mysqld]段中。
关闭服务器可用% mysql.server stop或% mysqladmin -u root -p shutdown
-
windows平台:
手动方式:直接运行c:\mysqld命令。
作为服务方式:运行c:\mysqld-nt --install命令,把mysqld-nt安装为windows的服务,此后,每当windows启动时,它就会自动运行。mysqld-nt是一个支持命名管道的MySQL服务器。运行c:\mysqld-nt --remove可把服务删除。手动启动关闭服务的方法是运行c:\net start mysql和c:\net stop mysql命令。
4.3. 连接故障恢复
当由于误删mysql套接字时(/tmp/mysql.sock),我们就不能通过套接字连接服务器。这时我们可通过tcp/ip来连接服务器,要建立一个tcp/ip连接,需用127.0.0.1代替locahost作为-h参数的值来连接服务器。如:
% mysqladmin -h 127.0.0.1 -u root -p shutdown #关闭服务器再重启会重建套接字
当我们因为忘记root用户密码而不能连接服务器时,重设置密码的步骤如:
用 % kill -TERM PID关闭服务器,用-TERM信息可使服务器在关闭前把内存中的数据写入磁盘。如果服务器没有响应,我们可用% kill -9 PID来强制删除进程,但不建议这样做。这时内存中的数据不会写入磁盘,造成数据不完整。如果你是用mysql_safe脚本启动MySQL服务器的,这个脚本会监控服务器的运行情况并在它被终止时重启服务器,所以如需关闭服务器,要先终止该进程,然后再真正终止mysqld进程。
接着用--skip_grant-tables启动服务器。这时MySQL服务器将不使用权限表对连接操作进行验证。你就可在不提供root密码的情况下连接上服务器,并获得root的权限。这样你就可用上面介绍的修改密码的方法重设root用户的密码。注意:连接上服务器后,要马上执行flush privileges命令,使权限表读入内存并生效,以阻止其他的连接。该语句还重新激活grant语句,在MySQL服务器不使用权限表时,grant语句被禁用。
修改完root用户密码后,我们就可关闭服务器并重启使所有配置正常运作。
4.5. 日志文件管理
有关MySQL的日志文件前面章节已简要讨论过了,主要有四种日志文件,分别是常规查询日志、慢查询日志、变更查询日志和二进制变更日志。这些日志文件的创建需在启动服务器时用选项指定。
Table 4.3. 日志启动选项
启动选项 | 激活日志 |
---|---|
--log[=file_name] | 常规日志文件 |
--log-bin[=file_name] | 二进制变更日志文件 |
--log-bin-index=file_name | 二进制变更日志文件索引文件 |
--log-update[=file_name] | 变更日志文件 |
--log-slow-queries[=file_name] | 慢查询日志文件 |
--log-isam[=file_name] | ISAM/MyISAM日志文件 |
--log-long-format | 设置慢查询日志和变更日志的格式 |
BDB和InnoDB数据表的日志文件会自动创建不用指定选项。但可用以下选项指时日志文件的存放路径。
Table 4.4. BDB和InnoDB数据表日志选项
启动选项 | 用途 |
---|---|
--bdb-logdir=dir_name | 存放BDB日志文件的位置 |
--innodb-log_arch_dir=dir_name | 存放InnoDB日志文件的归档目录 |
--innodb_log_group_home_dir=dir_name | 存放InnoDB日志文件的位置 |
MySQL日志文件选项可在mysqld和mysqld_safe脚本中使用,也可在选项文件my.cnf的[mysqld]中使用。推荐在选项文件中使用,因为每次启动服务器的日志选项基本上都是一致的。
日志的刷新可用mysqladmin flush-logs命令或flush logs语句实现。另外,对MySQL服务器发送一条SIGHUP信号也会刷新日志。错误日志和DBD/InnoDB日志不能用以上方法刷新。
错误日志记录MySQL数据库系统的论断和出错信息,由mysqld_safe脚本创建,文件名默认为hostname.err,也可通过--err-log或选项文件的err-log语句指定另外的名字。如果直接用mysqld程序启动服务器,错误信息会直接输出到输出设备,也就是屏幕。但我们可用重定向方法把错误信息输出到其它地方,如把错误信息输出到/var/log/mysql.err文件中,可以执行以下语句:
% mysqld > /var/log/mysql.err 2>&1 &
在windows平台下,MySQL服务器默认把诊断信息写到数据目录的mysql.err文件中,并且不允许另外指定错误日志文件名。如在启动MySQL服务器时给出了--console选项,则MySQL会把诊断信息输出到控制台窗口而不创建错误日志。但如MySQL是作为一个服务运行,则--console选项不起作用。
4.5.1. 日志失效处理
在服务器正常运行中,会产生大量的日志文件。我们要对这些日志文件进行失效管理,以节省磁盘空间和方便查询。进行日志失效处理的方式主要有以下几种:
-
日志轮转。该方法适用于常规查询日志和慢查询日志这些文件名固定的日志文件,在日志轮转时,应进行日志刷新操作(mysqladmin flush-logs命令或flush logs语句),以确保缓存在内存中的日志信息写入磁盘;
日志轮转的操作过程是这样的:第一次轮转时,把log更名为log.1,然后服务器再创建一个新的log文件,在第二轮转时,再把log.1更名为log.2,把log更名为log.1,然后服务器再创建一个新的log文件。如此循环,创建一系列的日志文件。当到达日志轮转失效位置时,下次轮转就不再对它进行更名,直接把最后一个日志文件覆盖掉。例如:如果每天进行一次日志轮转并想保留最后7天的日志文件,就需要保留log.1--log.7共七个日志文件,等下次轮转时,用log.6覆盖原来的log.7成新的log.7,原来的log.7就自然失效。下面是一个失效处理的shell脚本,以供参考:
#!/bin/sh
# shell script --- rotate_log.sh if [ $# -ne 1 ]; then
echo "Usage: $0 logname" 1>&2
exit 1
if logfile=$1 mv $logfile.6 $logfile.7
mv $logfile.5 $logfile.6
mv $logfile.4 $logfile.5
mv $logfile.3 $logfile.4
mv $logfile.2 $logfile.3
mv $logfile.1 $logfile.2
mv $logfile $logfile.1
mysqladmin -u flush -pflushpass flush-logs #执行mysqladmin flush-logs会打开一个日志文件----重新生成一个新的日志文件该脚本以日志文件名为参数,执行方法如下:
% rotate_log.sh /usr/local/mysql/data/log
注意,脚本中的mysqladmin命令是带有-u和-p参数的,因为我们进行日志刷新时需连接服务器。为确保安全,我们建立一个flush用户,密码为flushpass。该用户只有日志刷新的权限(reload权限)。创建该用户的语句如下:
GRANT RELOAD ON *.* TO 'flush'@'localhost' IDENTIFIED BY 'fulshpass';
设置好后,我们就可利用系统的自动处理机制定期运行该脚本以生成轮转日志。在Linux系统上的MySQL发行版中带有一个用来安装mysql-log-rotate日志轮转脚本的logrotate工具,如用RPM安装,则在/usr/share/mysql目录,如用二进制方式安装,则在MySQL安装目录的support-files目录,如用源码安装,则在安装目录的share/mysql目录中。
在windows平台下,不能在线更名,需停掉服务器,再进行。下面是一个进行日志更名的批处理文件:
@echo off
REM script name : rotate_log.bat if not "%1" == "" goto ROTATE @echo Usage: rotate_log logname
goto DONE :ROTATE
set logfile=%1
erase %logfile%.7
rename %logfile%.6 %logfile%.7
rename %logfile%.5 %logfile%.6
rename %logfile%.4 %logfile%.5
rename %logfile%.3 %logfile%.4
rename %logfile%.2 %logfile%.3
rename %logfile%.1 %logfile%.2
rename %logfile% %logfile%.1
:DONE该脚本的执行方法如下:
c:\rotate_log c:\mysql\data\log
-
以时间为依据对日志进行失效处理。该方法将定期删除超过给定时间的日志文件,适用于变更日志和二进制日志等文件名用数字编号标识的日志文件。下面是一个用Perl写成的处理脚本:
#!/usr/bin/perl -w # script name: expire_log.pl
# Usage: expire_log.pl logfile ... use strict
die "Usage: $0 logfile ...\n" if @ARGV == 0;
my $max_allowed_age = 7; #max allowed age in days
foreach my $file (@ARGV) #chack each argument
{
unlink ($file) if -e $file && -M $file >= $max_allowed_age;
}
exit(0);该脚本需提供一个将被轮转的日志文件名作为参数,如:
% expire_log.pl /usr/local/mysql/data/log.[0-9]*
在给脚本参数时请小心,如给出*为参数,则会删除目录中所有更新时间大于7天的文件。 -
镜像机制。把日志文件镜像到所有的从服务器上。要使用镜像机制,你必须知道主服务器有多少个从服务器,哪些正在运行,并需依次连接每一个从服务器并发出show slave status语句以确定它正处理主服务器的哪个二进制日志文件(语句输出列表的Master_Log_File项),只有所有的从服务器都不会用到的日志文件才能删除。删除方法是在主服务器上发出以下语句:
mysql> PURGE MASTER LOGS TO 'last_log.xx';
上面语句中的last_log.xx是所有从服务器已处理的最小编号日志文件。
4.6. MySQL服务器的一些优化配置
-
服务器的监听端口设置
TCP/IP端口3306是MySQL服务器默认的网络监听端口,如用--skip-networking选项启动服务器,则不监听TCP/IP端口。可用--port端口另行指定一个监听端口。如服务器主机有多个IP,还可用--bind-address选项对服务器在监听客户连接时使用的IP地址进行设定。
在UNIX系统上,MySQL可在一个UNIX域套接字文件上监听有无本地客户在试图以localhost为主机名进行连接。默认的套接字文件是/tmp/mysql.sock,可用--socket选项指定另外一个套接字文件。
在基于NT的Windows平台上,有-nt的MySQL服务器都支持命名管道。默认的命名管道是MySql,可用--socket选项另行指定。
-
启用或禁用LOAD DATA语句的LOCAL能力
可在MySQL服务器编译时,用configure脚本的--enable-local-infile或--disable-local-infile选项把LOAD DATA语句的LOCAL能力设置为启用或禁用;
在MySQL服务器启动是,可以用--local-infile或--disable-local-infile选项来启用或禁用服务器的LOCAL能力(在MySQL 4.0.2之前的版本里,要用--local-infile=0来禁用它)。
如果在服务器端禁用了LOCAL的能力,则客户端就不能使用该功能;如服务器启用了LOCAL的能力,客户端默认也是禁止使用的,但可用mysql程序的--local-infile选项启用它。
-
国际化和本地化,国际化是指软件能够在世界多个国家地区使用,而本地化则是指可从国际化软件中选择一套适合本地区的语言和习惯的设置来使用。在MySQL中的国际化和本地化设置有以下几方面内容:
-
时区,如果时区设置不对,则服务器显示的时间将会和当地时间有冲突。设置方法可通过mysqld_safe脚本的--timezone选项来设置,但最好还是在选项文件里设置,如:
[mysqld_safe]
timezone=US/Central 配置显示信息的语言,MySQL能用多种语言来显示诊断信息与出错信息,默认是英语。查看share/mysql目录下有几个以语言名称作为目录名的目录就可知道有哪些语言可供选择。可用--language启动选项来指定语言,如--language=/usr/local/mysql/share/mysql/french。
-
配置服务器的字符集,MySQL支持多种字符集,可在share/mysql/charsets目录下查询支持的字符集,也可用show variables like 'character_sets'来显示支持的字符集清单。MySQL把latin1作为默认的字符集。可在编译时用--with-charset指定另外一个字符集为默认字符集。如要增加另外的字符集支持,可用--with-extra-charasets选项进行添加。如:
% ./configure --with-extra-charsets=latin1,gb2312,big5
--with-extra-charsets有两个特殊的选项,一个是all,代表所有可用字符集;一个是complex,代表所有的复杂字符集(包括多字节字符集和有特殊排序规则的字符集)。
服务器启动时,使用默认字符集,如需指定另外的字符集,需用--default-character-set选项指明。
在MySQL 4.1以前,如果在创建好数据表后改变服务器的默认字符集,就需对索引重新排序才能保证索引键值能够正确反映出数据表记录在新字符集下的排列顺序。重新排序的操作命令如下:
% myisamchk --recover --quick --set-character-set=gb2312 #在执行该语句需关闭服务器,适用于MyISAM数据表
也可用:
% mysqlcheck --repair --quick #不需关闭服务器,适用于各种数据表
或者用:
mysql> REPLACE TABLE ... QUICK;在客户端,可用--default-character-set选项指定客户程序使用的字符集。--character-sets-dir选项可指出字符集文件的安装目录。
-
-
升级数据表到4.1,支持多字符集数据表。步骤如下:
-
用mysqldump程序备份数据库:
% mysqldump -p -u root --all-databases --opt > dumpfile.sql
--all-databases选项的作用是转储所有数据库;
--opt选项的作用是对转储文件进行优化。 关闭服务器,升级MySQL服务器软件到4.1版。
-
用备份文件重新加载数据表:
% mysql -p -u root < dumpfile.sql
这样,字符集信息就被分配到每一个数据列中,此后,即使服务器改变了默认的字符集,各数据列的字符集也不会改变。当以后修改某个数据列的字符集时,服务器会自动重索引,以反映最新变化。
-
-
配置InnoDB表空间。InnoDB表空间在逻辑上是一个连接的存储区域,但实际上是由一个或多个磁盘文件组成。这些文件可以是普通的文件,也可以是一个未格式化的原始硬盘分区。InnoDB表空间通过一系列的配置选项来设置,其中最重要的有以下两个:
为确保服务器每次启动时都能调用同样的选项,InnoDB的选项最好存放到选文件中。下面是一个例子:
innodb_data_home_dir =
innodb_data_file_path=/usr/loca/mysql/data/idbdata1:10M:autoextend:max:100M
说明:
InnoDB表空间文件默认存放到了MySQL的数据目录中,名字叫idbdata1;
文件长度为10M;
可自动扩展,以8M为步长扩展,如有多个数据文件,只允许最后一个文件可自动扩展;
规定了最大的可扩展尺寸为100M。innodb_data_home_dir,设置InnoDB表空间各组成文件的父目录,如果没有指出,则默认是MySQL的数据目录。
innodb_data_file_path,描述InnoDB主目录中各有关文件,包括文件名,文件长度和一些选项。各文件以分号分隔,各组成文件长度至少为10M。
把选项写入选项文件后,启动服务器就可自动创建和初始化InnoDB表空间。
利用原始磁盘分区作为InnoDB表空间可创建一个非常大的表空间,不受操作系统单文件最大容量的限制。并且能有效减少磁盘碎片的产生。要使用原始磁盘分区,需作如下配置:
-
首先,要进行初始化,在选项文件的[mysqld]中配置:
innodb_data_home_dir=
innodb_data_file_path=/dev/hda1:10Gnewraw #初始化/dev/hda1这个10G容量的分区启动服务器,服务器会对这个10G的分区进行初始化。
-
接着,关闭服务器,修改配置文件,把newraw改为raw,如:
innodb_data_home_dir=
innodb_data_file_path=/dev/hda1:10Graw
重新启动服务器,MySQL就会以读/写方式使用该表空间了。在windows平台上配置InnoDB表空间时,windows路径名中的反斜杠可以写成单个的斜线字符(/)。也可写成两个反斜杠(\\)。如:
innodb_data_home_dir=
innodb_data_file_path=c:/mysql/data/ibdata1:10M;d:/ibdata2:20M默认情况下,InnoDB的日志文件会存储在MySQL的数据目录,文件名以ib开头。一旦完成InnoDB表空间的初始化,就不能改变组成文件的大小,但可通过添加数据文件或设置自动扩展来增加表空间容量。如需通过增加文件的方法扩大表空间的容量,可按以下步骤进行:
关闭正在运行的MySQL服务器
-
如果InnoDB表空间的最后一个组成文件是可自扩展的,就要先把它改变成一个固定长度文件才能把另一个文件添加到它后面。方法是先计算出该文件的近似大小,重新设置,如:
innodb_data_file_path=ibdata1:100M:autoextend
改成:
innodb_data_file_path=ibdata1:150M 把新的组成文件添加到文件清单的末尾,该文件可以是普通文件,也可以是一个原始硬盘分区。
重启服务器。
还有一种方法重新配置InnoDB表空间,就是先备份,再重新配置,最后重新加载备份。具体步骤如下:
使用mysqldump备份整个InnoDB数据库;
关闭服务器,删除所有InnoDB表空间、InnoDB日志文件 及InnoDB数据表的.frm文件;
重新配置InnoDB表空间;
配置完成后,用备份文件重载数据,生成新的InnoDB数据表。
4.7. 优化服务器
MySQL服务器为我们提供了丰富的参数,以调整服务器满足不同环境的要求。下面分别讨论一下这些参数:
-
服务器参数变量的设置。MySQL服务器参数可在服务器启动时设置,在MySQL4.0.3及以后的版本中,有些参数也允许在线设置。在MySQL4.0.2及以后的版本里,可以把一个变量名视为一个选项名来设置。如数据表缓冲区的尺寸由服务器参数talbe_cache来设置。如果需把它设置为128,则可以在命令行里增加
--table_cache=128
也可在选项文件中设置:
[mysqld]
table_cache=128在命令行选项中'_'可写'-',变成:
--table-cache=128 #这种写法更像一个标准选项
还有一种是使用--set-variable或-O选项,如:
--set-variable=table_cache=128
or
-O table_cache=128
在选项文件中可写成:
[mysqld]
set-variable=table_cache=128服务器参数分为全局级和会话级两个级别。全局级参数将影响整个服务器,会话级参数则只影响某给定客户连接上的工作。如果某个变量同时存在于两个级别,则服务器在客户建立连接时用全局变量的值去初始化相应的会话级参数,一旦客户连接建立起来后,对全局参数所作的修改不会影响到相应的会话级参数当前值。设置全局参数和会话级参数的语句:
全局级:
mysql> SET GLOBAL variable = value;
mysql> SET @@GLOBAL.variable = value;
会话级:
mysql> SET SESSION variable = value;
mysql> SET @@SESSION.variable = value;
默认不带级别限定符的SET语句修改的参数属会话级,如:
mysql> SET variable = value;
mysql> SET @@variable = value;
可用一条SET语句设置多个参数,参数间用逗号分隔,如:
SET SESSION variable = value1,value2,value3;SESSION和LOCAL是同义语,可用LOCAL代替SESSION,如:@@LOCAL
具备SUPER权限才能设置全局参数,新设置值的效力将持续到该参数被再次修改或服务器退出。设置会话级参数不用特殊的权限,新设置值的效力将持续到该值被再次修改或连接断开。显示参数的语句如下:
SHOW GLOBAL VARIABLES;
SHOW GLOBAL VARIABLES LIKE 'TEST';
SHOW SESSION VARIABLES;
SHOW SESSION VARIABLES LIKE 'TEST';
如不带限定符,则返回会话级参数,如会话级参数不存在则返回全局级参数。
也可用命令行方式显示服务器参数变量,如:
% mysqladmin variables -
下面介绍一些MySQL服务器通用的参数变量:
back_log,当多个客户同时连接服务器时,客户处理过程需进入一个队列排队等待服务器处理。该值定义服务器等待处理队列长度的最大值,如果站点访问量大,需加大该值。
delayed_queue_size,在实际插入数据表前,来自insert delayed语句的数据行会进入一个队列等待服务器处理。该值定义该队列能容纳的数据行的最大个数。当队列满时,会阻塞后续的语句。加大该值能提高insert delayed语句的执行速度。
flush_time,自动存盘间隔。如果系统经常死机或重启,把这个变量设置为一个适当的非零值,使MySQL服务器每隔flush_time称去刷新一次数据表缓冲区,将其中的信息写入磁盘。这将导致系统性能下降,但可减少数据表被破坏或丢失数据的概率。在命令行上用--flush选项启动服务器可使数据表在每次修改后被自动存盘。
key_buffer_size,用来容纳索引块的缓冲区的长度。加大该值可加快索引创建和修改操作的速度,该索引缓冲区越大,在内存中找到键值的可能性就越大,读盘次数就越少。MySQL3.23前的版本里,该参数叫key_buffer。3.23版本之后,两种叫法都可以。
-
max_allowed_packet,服务器与客户程序之间通信时使用的缓冲区在最大值。MySQL 4版本之前,该最大值可取16MB,MySQL 4版本以后,该值的最大值是1GB。如果客户端与服务器需传送大容量的数据,如BLOB或TEXT值,就要加大该值。客户端也有一个同名的变量,默认是16MB,该值也要加大。客户端的启动命令为:
% mysql --set-variable=max_allowed_packet=64M
max_connections,允许同时打开的连接数,如果站点繁忙,需加大该值。
table_cache,数据表缓存区的尺寸。加大该值可使服务器能够同时打开更多的数据表,从而减少文件打开/关闭操作的次数。
注意:加大max_connections和table_cache参数的值,会使服务器占用更多的文件描述符。运行多个服务器可绕过该限制。对一些分配给每个客户的资源变量,设置时不能过大,因为当连接数快速增长时会很快耗尽服务器的资源,造成服务器性能下降。
-
InnoDB处理程序变量:
innodb_buffer_pool_size,InnoDB数据库缓冲池的大小,如果有足够的内存,可把该值设置得大些以减少读盘操作。
innodb_log_file_size和innodb_log_files_in_group,前者设置日志文件的长度,后者设置日志文件的个数。InnoDB日志文件的总长度是两者的乘积,它的总长度不得超过4GB。
4.8. 运行多个MySQL服务器
需运行多个服务器的原因有很多,比如上面提到的可绕过最大文件描述符的限制,还有是进行版本测试和提供专用服务等。运行多个服务器比运行单个服务器复杂很多,需注意以下问题:
在安装不同版本的程序时,需分开目录存放程序和数据目录。如果同一版本的服务器软件,则程序目录可一样,但数据目录则要不同。可用--basedir=dir_name和--datadir=dir_name两个启动选项指时这两个目录。
要为不同的服务器指定不时的--port=port_name(TCP/IP监听端口),--socket=file_name(套接字文件名)和--pid-file=file_name(进程ID文件)值。
如果激活了日志功能,就要为不同的服务器指定不同的日志文件名。
在Windows平台上,被安装为服务的多个MySQL服务器必须有不同的服务名。
多服务器环境下选项文件的配置方法:
使用--defaults-file选项指定每个选项文件,这样,每个服务器就不会去读/etc/my.cnf这些配置文件,而会使用你所指定的配置文件。
可把一些公共的选项放到/etc/my.cnf文件里,再用--defaults-extra-file选项指出特定服务器的特定选项文件。这样就不用在所有的配置文件时重复公共的选项。
-
用mysql_multi脚本启动服务器,它允许我们把所有的选项放到同一个选项文件里。每一个服务器对应该文件中的一个选项组。
下面介绍用mysql_multi脚本启动多服务器的方法。
-
为每个服务器编一个编号xxx,对应选项文件的[mysqldxxx]选项组。mysql_multi本身要用到的选项可放到[mysqld_multi]里。这样/etc/my.cnf选项配置文件看起来就象下面这样:
[mysqld001]
basedir=/usr/local/mysql/001
datadir=/usr/local/mysql/001/data
mysqld=/usr/local/mysql/001/bin/mysqld_safe
socket=/usr/local/mysql/001/mysql.sock
port=3306
local-infile=1
user=mysqladm
log=log
log-update=update-log
innodb_data_file_path=ibdata1:10M [mysqld002]
basedir=/usr/local/mysql/002
datadir=/usr/local/mysql/002/data
mysqld=/usr/local/mysql/002/bin/mysqld_safe
socket=/usr/local/mysql/002/mysql.sock
port=3307
local-infile=1
user=mysqladm
log=log
log-update=update-log
innodb_data_file_path=ibdata1:10M ... -
配置好选项文件后,就可用以下命令启动服务器:
% mysqld_multi --no-log start 001,002
#启动001和002两个服务器,并把启动信息发送到控制台,也可用区间的形式给出服务器编号用以下命令可查看服务器状态:
% mysqld_multi --no-log --user=root --password=password report 001
可用以下命令停止MySQL服务器:
% mysqld_multi --no-log --user=root --password=password stop 001
-
-
在windows平台下运行多个MySQL服务器的方式有两种,一种是运行同一个MySQL程序的两个实例,一种是运行多个windows服务,下面分别介绍:
-
第一种情况需设置两个选项文件,指定不同的数据目录,如:
c:\mysql\my.cnf1 [mysqld]
basedir=c:/mysql
datedir=c:/mysql/data1
port=3306 c:\mysql\my.cnf2 [mysqld]
basedir=c:/mysql
datadir=c:/mysql/data2
port=3307在启动服务器时,用--defaults-file选项指出选项文件即可。如:
c:\> mysqld --defaults-file=c:\mysql\my.cnf1
c:\> mysqld --defaults-file=c:\mysql\my.cnf2 -
在MySQL 4.0.2版本开始,可以把MySQL安装为一个服务,并可指定一个服务名,如:
c:\> mysql-nt --install service_name
在MySQL 4.0.3开始,安装服务还支持--defaults-file=file_name选项这样,我们就可把MySQL安装为一系列不同的服务,如果不指定service_name,则安装的服务名默认为MySql,如果指定service_name,则安装的服务名为指定的service_name,并对应选项文件中的[service_name]选项组。以默认服务名运行的服务器还支持一个名为MySql的命名管道,而明确给出服务名的服务器将只监听TCP/IP连接而不支持命名管道--除非还用socket选项明确指定一个套接字文件。
移除服务需先用mysqladmin shutdown命令停掉服务器,再执行以下命令:
c:\> mysql-nt --remove #移除默认的服务
c:\> mysql-nt --remove service_name #移除指定服务
-
4.9. MySQL服务器镜像配置
通过镜像机制可把数据从一个地方复制到另一个地方,并能实现同步两个或多个地方的数据。MySQL服务器也支持镜像,大提高数据的安全性和稳定性。下面介绍一下MySQL数据中的镜像机制:
在镜像关系中,一个MySQL服务器扮演主服务器角色,另外一个或多个服务器扮演从服务器角色,从服务器中的数据和主服务器中的数据完全一样。
在镜像建立之前,主服务器和从服务器必须进行一次完全同步。同步之后,在主服务器上所做的操作将会在从服务器上再实现,主服务器上的操作不是直接作用于从服务器上的。
负责在主、从服务器上传输各种修改动作的媒介是主服务器上的二进制变更日志,该日志记录着主服务器上所有的操作动作。因此,主服务器必须激活二进制日志功能。
从服务器必须有足够的权限从主服务器上接收二进制日志文件。镜像协调信息记录从服务器的进展情况,包括,从服务器正在读取的二进制变更日志文件名和它在该文件里的当前读写位置。
每个主服务器可以有多个从服务器,但每个从服务器只能有一个主服务器。但MySQL服务器允许把一个从服务器作为另一个从服务器的主服务器,这样就可创建一个镜像服务器链。
镜像机制在MySQL中还是一个新生事物,最早实现于3.23.15版。各版本间的镜像能力有差异,一般来说,建议大家尽量使用最新的版本,下面列举了不同版本的MySQL服务器在镜像机制方面的兼容规则:
3.23.x系统版本的从服务器不能与4.x系统版本的主服务器通信。
4.0.0版本的从服务器只能与4.0.0版本的主服务器通信。
4.0.1或更高版本的从服务器既能与3.23.x系统版本的主服务器通信,也能与4.x系统版本的主服务器通信。但后一种情况要求主服务器的版本号等于或大于从服务器的版本号。
一般来说,建议遵循以下原则:
要尽可能地让主服务器和从服务器都使用同一版本系统。
在选定系统后,尽量使用该系统的最新版本。
建立主从镜像服务器的步骤:
确定主从服务器的镜像ID号,主从服务器的ID号不能相同。在启动主从服务器时,用--server_id启动选项给出其ID。
-
从服务器必须在主服务器上有一个具备足够的权限的帐户,从服务器将使用该帐户去连接主服务器并请求主服务器把二进制变更日志发送给它。可用以下命令创建这个帐户:
mysql> GRANT REPLICATION SLAVE ON *.* TO 'slave_user'@'slave_host' IDENTIFIED BY 'slave_pass';
#REPLICATION权限只MySQL4.0.2后版本,之前的版本请用FILE权限。 -
把主服务器上的数据库文件拷贝到从服务器上完成最初同步工作。也可用备份后再加载的方法。在MySQL 4.0.0及以后版本里,还可用在主服务器上运行LOAD DATA FROM MASTER语句来建立从服务器。但有约束条件:
数据表要全部是MyISAM表
为发出这条指令而在连接从服务器时使用的帐户必须有SUPER权限。
从服务器用来连接主服务器的帐户必须具备RELOAD和SUPER权限。注意,这是一个主服务器上的帐户,而用来发出LOAD DATA FROM MASTER语句的帐户是一个从服务器上的帐户。
LOAD DATA FROM MASTER语句在执行时需申请一个全局性的读操作锁,这个锁在语句执行期间阻塞主服务器上一切的写操作。
无论用哪种方法同步数据,都要确保在开始制作备份到给主服务器重新配置好二进制日志功能这段时间,不能在主服务器上发生修改操作。
关闭服务器。
-
对主服务器的配置进行修改--把它的镜像ID告诉它并激活其二进制日志功能。在主服务器要读取的选项文件内增加以下内容:
[mysqld]
server-id=master_server_id
log-bin=binlog_name 重新启动主服务器,从现在开始,它将把客户对数据库的修改操作记录到二进制变更日志里。如果在此之前已经激活了二进制日志功能,则要在重启前把二进制变更日志备份下来,在重启后再发一条RESET MASTER语句去清除现有的二进制变更日志。
关闭从服务器。
-
对从服务器进行配置,使它知道自已的镜像ID,到哪里去找主服务器以及如何去连接主服务器。配置内容如下:
[mysqld]
server-id=slave_server_id
master-host=master_host
master-user=slave_user #在主服务器上为从服务器建立的帐户
msater-password=slave_pass #在主服务器上为从服务器建立的帐户的密码
master-connet-retry=30 #设置连接重试间隔,默认为60秒
master-retry-count=100000 #设置重试次数,默认为86400次
注:最后两个选项在网络连接不可靠时设置 重新启动从服务器。从服务器用两个信息源来确定它自已在镜像工作中的进度位置:一个是数据目录中的master.info文件,另一个是启动选项所给定的配置信息。第一次启动从服务器时,master.info文件不存在,从服务器会根据选项文件中给出的各种master-xxx选项值去连接主服务器。一旦连接成功,从服务器会创建一个master.info文件以保存各种连接参数和它自已的镜像工作状态。如果以后再重启从服务器,从服务器会优先读取该文件,而不是选项文件。所以如果你修改了选项文件的内容,想该选项生效就要删除master.info文件并重启从服务器。
以上步骤是镜像所有数据库的操作过程,如果我们想把mysql权限数据保留在主服务器上,排除在镜像机制外的话,可用在选项文件的[mysqld]中加入--binlog-ignore-db=mysql选项,这样,mysql数据库上的操作就不会记录在二进制变更日志里。如要排除其它数据库,只要增加多几个该选项即可。
通过以下几个命令可监控和管理主从服务器:
SLAVE STOP,SLAVE START用于挂起来恢复从服务器上镜像,如当备份时,可用该语句让从服务器暂时停止镜像活动。
SHOW SLAVE STATUS,在从服务器上查看其镜像协调信息,这些信息可以用来判断哪些二进制变更日志已经不再使用。
PURGE MASTER,在主服务器上对二进制变更日志进行失效处理。删除所有从服务器都不再使用的二进制变更日志。
CHANGE MASTER,在从服务器上修改镜像参数。如正在读取主服务器上哪个二进制变更日志,正在写哪个中继日志文件等。
在MySQL4.0.2之后版本中,镜像机制中的从服务器由两个内部线程组成:
一个叫“I/O线程”,负责与主服务器通信,请求主服务器发送二进制变更日志,并把接收到的数据修改命令写入某个中继日志文件;用SLAVE STOP IO_THREAD或SLAVE START IO_THREAD可挂起或恢复该线程。
另一个叫“SQL线程”,负责从中继日志中读取数据修改命令并执行。同理,用SLAVE STOP SQL_THREAD或SLAVE START SQL_THREAD可挂起或恢复该线程。
中继日志文件默认的文件为hostname-relay-bin.nnn和hostname-relay-bin.index。可用从服务器的--relay-log和--relay-log-index选项修改。在从服务器中还有一个relay-log.info中继信息文件,可用--relay-log-info-file启动选项修改文件名。
Chapter 5. 数据库安全
Table of Contents
安全是一个过程,而不是一个方法,它贯穿在我们使用和维护MySQL数据库的过程中。这不单是系统管理员工作,用户也要有安全的意识,使安全问题得到有效控制。MySQL服务器的安全问题可分为内部安全和外部安全两部份。内部安全问题大都与系统文件有关,我们需确保MySQL程序文件和数据文件的安全。外部安全是指通过网络连接到服务器的安全问题,应该只允许合法用户访问数据库,在一些情况下还可用SSL加密信息传输通道。下分别介绍内部安全和外部安全的防范措施。
5.1. 保护MySQL安装程序文件
在重设置文件权限时,请先关闭数据库服务器。
-
用以下命令把MySQL安装程序目录的属主和所属组设置为MySQL管理员帐号的用户名和用户组名。
% chown -R mysql.mysql /usr/local/mysql
另外一种方法是把除数据目录外的所有目录属主设置为root所有,如:
% chown -R root.mysql /usr/local/mysql
% chown -R mysql.mysql /usr/local/mysql/data -
设置安装目录及各有关子目录的权限,允许管理员进行所有操作,只允许其他人进行读和执行访问,设置命令如下:
#设置mysql目录
% chmod 755 /usr/local/mysql
or
% chmod u=rwx,go=rx /usr/local/mysql
#设置mysql/bin目录
% chmod 755 /usr/local/mysql/bin
or
% chmod u=rwx,go=rx /usr/local/mysql/bin
#设置mysql/libexec目录
% chmod 700 /usr/local/mysql/libexec
or
% chmod u=rwx,go-rwx /usr/local/mysql/libexec -
把数据目录及目录中的所有子目录和文件设置为只允许MySQL管理员访问。
% chmod -R go-rwx /usr/local/mysql/data
如果数据目录下有选项文件或套接字文件,并一些客户需访问这些文件,则可用以下的权限设置,使客户在没有读权限的前提下使用这些文件:
% chmod go+x /usr/local/mysql/data
mysql.sock套接字文件一般放以/tmp目录下,要确保该目录设置了粘着位,使自户只能删除自已创建的文件,不能删除其他用户创建的文件。/etc/my.cnf中公共选项文件,是对所有用户可读的,所以不应把一些敏感信息保存在里面。.my.cnf是用户专用选项文件,要确保只有该用户有权访问。
这样设置以后,只有MySQL管理员才能启动服务器。
5.2. 权限表
MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些权限表分别user,db,table_priv,columns_priv和host。下面分别介绍一下这些表的结构和内容:
user权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。
db权限表:记录各个帐号在各个数据库上的操作权限。
table_priv权限表:记录数据表级的操作权限。
columns_priv权限表:记录数据列级的操作权限。
host权限表:配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。
大家注意到,以上权限没有限制到数据行级的设置。在MySQL只要实现数据行级控制就要通过编写程序(使用GET-LOCK()函数)来实现。
MySQL的版本很多,所以权限表的结构在不同版本间会有不同。如果出现这种情况,可用mysql_fix_privilege_tables脚本来修正。运行方式如下:
% mysql_fix_privilege_tables rootpassword #这里要给出MySQL的root用户密码
最好一下子升级到MySQL 4.0.4版本,因为4.0.2和4.0.3的db表没有Create_tmp_table_priv和Lock_tables_priv权限。
MySQL的权限表定义了两部份内容,一个部份定义权限的范围,即谁(帐户)可以从哪里(客户端主机)访问什么(数据库、数据表、数据列);另一部份定义权限,即控制用户可以进行的操作。下面是一些常用的权限介绍,可直接在GRANT语句中使用。
CREATE TEMPORARY TABLES,允许创建临时表的权限。
EXECUTE,允许执行存储过程的权限,存储过程在MySQL的当前版本中还没实现。
FILE,允许你通过MySQL服务器去读写服务器主机上的文件。但有一定限制,只能访问对任何用户可读的文件,通过服务器写的文件必须是尚未存在的,以防止服务器写的文件覆盖重要的系统文件。尽管有这些限制,但为了安全,尽量不要把该权限授予普通用户。并且不要以root用户来运行MySQL服务器,因为root用户可在系统任何地方创建文件。
GRANT OPTION,允许把你自已所拥有的权限再转授给其他用户。
LOCK TABLES,可以使用LOCK TABLES语句来锁定数据表
PROCESS,允许你查看和终止任何客户线程。SHOW PROCESSLIST语句或mysqladmin processlist命令可查看线程,KILL语句或mysqladmin kill命令可终止线程。在4.0.2版及以后的版本中,PROCESS权限只剩下查看线程的能力,终止线程的能力由SUPER权限控制。
RELOAD,允许你进行一些数据库管理操作,如FLUSH,RESET等。它还允许你执行mysqladmin命令:reload,refresh,flush-hosts,flush-logs,flush-privileges,flush-status,flush-tables和flush-threads。
REPLICATION CLIENT,允许查询镜像机制中主服务器和从服务器的位置。
REPLICATION SLAVE,允许某个客户连接到镜像机制中的主服务器并请求发送二进制变更日志。该权限应授予从服务器用来连接主服务器的帐号。在4.0.2版这前,从服务器是用FILE权限来连接的。
SHOW DATABASES,控制用户执行SHOW DATABASES语句的权限。
SUPER,允许终止线程,使用mysqladmin debug命令,使用CHANGE MASTER,PURGE MASTER LOGS以及修改全局级变量的SET语句。SUPER还允许你根据存放在DES密钥文件里的密钥进行DES解密的工作。
user权限表中有一个ssl_type数据列,用来说明连接是否使用加密连接以及使用哪种类型的连接,它是一个ENUM类型的数据列,可能的取值有:
NONE,默认值,表示不需加密连接。
ANY,表示需要加密连接,可以是任何一种加密连接。由GRANT的REQUIRE SSL子句设置。
X509,表示需要加密连接,并要求客户提供一份有效的X509证书。由GRANT的REQUIRE X509子句设置。
SPECIFIED,表示加密连接需满足一定要求,由REQUIRE子句的ISSUER,SUBJECT或CIPHER的值进行设置。只要ssl_type列的值为SPECIFIED,则MySQL会去检查ssl_cipher(加密算法)、x509_issuer(证书签发者)和x509_subject(证书主题)列的值。这几列的列类型是BLOB类型的。
user权限表里还有几列是设置帐户资源使用情况的,如果以下数据列中的数全为零,则表示没有限制:
max_connections,每小时可连接服务器的次数。
max_questions,每小时可发出查询命令数。
max_updates,每小时可以发出的数据修改类查询命令数。
设置权限表应注意的事项:
删除所有匿名用户。
-
查出所有没有口令用户,重新设置口令。可用以下命令查询空口令用户:
mysql> SELECT host,user FROM user WHERE password = '';
尽量不要在host中使用通配符。
最好不要用user权限表进行授权,因为该表的权限都是全局级的。
不要把mysql数据库的权限授予他人,因为该数据库包含权限表。
使用GRANT OPTION权限时不要滥用。
-
FILE权限可访问文件系统中的文件,所以授权时也要注意。一个具有FILE权限的用户执行以下语句就可查看服务器上全体可读的文件:
mysql> CREATE TABLE etc_passwd(pwd_entry TEXT);
mysql> LOAD DATA INFILE '/etc/passwd' INTO TABLE etc_passwd;
mysql> SELECT * FROM etc_passwd;如果MySQL服务器数据目录上的访问权限设置得不好,就会留下让具有FILE权限的用户进入别人数据库的安全漏洞。所以建议把数据目录设置成只能由MySQL服务器读取。下面演示一个利用具有FILE权限的用户读取数据目录中文件权限设置不严密的数据库数据的过程:
mysql> use test;
mysql> create table temp(b longblob);
mysql> show databases #显示数据库名清单,--skip-show-database可禁止该功能
mysql> load data infile './db/xxx.frm' into table temp fields escaped by '' lines terminated by '';
mysql> select * from temp into outfile 'xxx.frm' fields escaped by '' lines terminated by '';
mysql> delete from temp;
mysql> load data infile './db/xxx.MYD' into table temp fields escaped by '' lines terminated by '';
mysql> select * from temp into outfile 'xxx.MYD' fields escaped by '' lines terminated by '';
mysql> delete from temp;
mysql> load data infile './db/xxx.MYI' into table temp fields escaped by '' lines terminated by '';
mysql> select * from temp into outfile 'xxx.MYI' fields escaped by '' lines terminated by '';
mysql> delete from temp;这样,你的数据库就给人拷贝到本地了。如果服务器是运行在root用户下,那危害就更大了,因为root可在服务器上做任何的操作。所以尽量不要用root用户来运行服务器。
只把PROCESS权限授予可信用户,该用户可查询其他用户的线程信息。
不要把RELOAD权限授予无关用户,因为该权限可发出FLUSH或RESET语句,这些是数据库管理工具,如果用户不当使用会使数据库管理出现问题。
ALTER权限也不要授予一般用户,因为该权限可更改数据表。
GRANT语句对权限表的修改过程:
当你发送一条GRANT语句时,服务器会在user权限表里创建一个记录项并把你用户名、主机名和口令记录在User、Host和Password列中。如果设置了全局权限,由把该设置记录在相在的权限列中。
如果在GRANT里设置了数据库级权限,你给出的用户名和主机名就会记录到db权限表的User和Host列中,数据库名记录在Db列中,权限记录到相关的权限列中。
接着是到数据表和数据列级的权限设置,设置方法和上面的一样。服务器会把用户名、主机名、数据库名以及相应的数据表名和数据列名记录到数据表中。
删除用户权限其实就是把这些权限表中相应的帐号记录全部删除即可。
5.3. 建立加密连接
加密连接可提高数据的安全性,但会降低性能。要进行加密连接,必须满足以下要求:
user权限表里要有相关的SSL数据列。如果安装的MySQL服务器是4.0.0版的,user权限表已包含相关的SSL数据列,否则,我们也可用mysql_fix_privilege_tables脚本升级权限表。
-
服务器和客户程序都已经编译有OpenSSL支持。首先要安装openssl,在编译时MySQL服务器时加--with-vio和--with-openssl选项加上openssl支持。可用以下语句查询服务器是否支持SSL:
mysql> show variables like 'have_openssl';
-
在启动服务器时用有关选项指明证书文件和密钥文件的位置。在建立加密连接前,要准备三个文件,一个CA证书,是由可信赖第三方出具的证书,用来验证客户端和服务器端提供的证书。CA证书可向商业机构购买,也可自行生成。第二个文件是证书文件,用于在连接时向对方证明自已身份的文件。第三个文件是密钥文件,用来对在加密连接上传输数据的加密和解密。MySQL服务器端的证书文件和密钥文件必须首先安装,在sampdb发行版本的ssl目录里有几个供参考的样本文件:ca-cert.pem(CA证书),server-cert.pem(服务器证书),server-key.pem(服务器公共密钥)。把这几个文件拷贝到服务器的数据目录中,再在选项文件里加上以下内容:
[mysqld]
ssl-ca=/usr/local/mysql/data/ca-cert.pem
ssl-cert=/usr/local/mysql/data/server-cert.pem
ssl-key=/usr/local/mysql/data/server-key.pem重启服务器,使配置生效。
-
要想让某个客户程序建立加密连接,必须在调用这个客户程序时用有关选项告诉它在哪里能找到其证书文件和密钥文件。在sampdb发行版的ssl目录中提供了client-cert.pem(客户证书文件),client-key.pem(客户密钥文件),CA证书与服务器使用同样的ca-cert.pem。把他们拷贝到个人目录下,并在.my.cnf选项文件中指出文件位置,如:
[mysql]
ssl-ca=/home/mysql/ca-cert.pem
ssl-cert=/home/mysql/client-cert.pem
ssl-key=/home/mysql/client-key.pem配置完成后,调用mysql程序运行\s或SHOW STATUS LIKE 'SSL%'命令,如果看到SSL:的信息行就说明是加密连接了。如果把SSL相关的配置写进选项文件,则默认是加密连接的。也可用mysql程序的--skip-ssl选项取消加密连接。如果用命令行方式启用加密连接可以这样写:
% mysql --ssl-ca=ca-cert.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem
可用GRANT语句的REQUIRE SSL选项来强制用户使用加密连接。
使用sampdb发行版的证书可以建立一个加密连接,但由于该文件已公开,所以安全性不好,我们可以在测试成功后自行建立证书或购买商业证书,以提高安全性。如何自行建立SSL证书的文档在sampdb发行版的ssl/README文件里有说明。
Chapter 6. 数据库的备份、维护和修复
Table of Contents
数据库在运行中,会因为人为因素或一些不可抗力因素造成数据损坏。所以为了保护数据的安全和最小停机时间,我们需制定详细的备份/恢复计划,并定期对计划的有效性进行测试。本章结合MySQL服务器的运行机制和所提供的工具,介绍如何进行数据库的备份、维护和修复。
以下是几点防范的措施:
制定一份数据库备份/恢复计划,并对计划进行仔细测试。
启动数据库服务器的二进制变更日志,该功能的系统开销很小(约为1%),我们没有理由不这样做。
定期检查数据表,防范于未燃。
定期对备份文件进行备份,以防备份文件失效。
把MySQL的数据目录和备份文件分别放到两个不同的驱动器中,以平衡磁盘I/O和增加数据的安全。
6.1. 检查/修复数据表
对数据表进行维护最好通过发出CHECK TABLE(检查数据表)或REPAIRE TABLE(修复数据表)命令来做,这样MySQL服务器自动进行表锁定以协调数据表中数据的读写一致性问题。也可用myisamchk工具来做数据表的维护,但它直接访问有关的数据表文件,不通过服务器,所以需人为地协调数据表数据的读写一致性问题。使用myisamchk检查数据表的具体操作步骤如下:
-
以mysql客户端程序连接服务器,并发出LOCK TABLE命令,以只读方式锁住数据表。
% mysql
mysql> use db
mysql> LOCK TABLE table_name READ; #以只读方式锁定表
mysql> FLUSH TABLE table_name; #关闭数据表文件,并把内存中的信息写入磁盘 -
保持上面的状态不退出,另开一个shell窗口,用以下命令维护(检查)数据表。
% myisamchk table_name
如果不保持上面状态,退出mysql会话,则表锁定会自动取消。 -
维护完成,切换回mysql状态的shell窗口,发出以下命令解除表锁定。
mysql> UNLOCK TABLES;
使用myisamchk修复数据表的具体操作步骤如下:
-
进行修复操作需以读/写方式锁定数据表,命令如下:
% mysql
mysql> use db
mysql> LOCK TABLE table_name WRITE; #以读/写方式锁定数据表
mysql> FLUSH TABLE table_name; -
保持mysql客户端连接状态,切换到第二个shell窗口,运行修复命令:
% myisamchk --recover table_name
运行修复命令前最好先备份一下数据文件。 -
修复完成后,切换回mysql客户端连接窗口,运行以下命令解除数据表锁定:
mysql> FLUSH TABLE table_name; #使服务器觉察新产生的索引文件
mysql> UNLOCK TABLE;
还可用以下命令锁定所有表,锁定后,所有用户就只能读不能写数据,这样就可使我们能安全地拷贝数据文件。
mysql> FLUSH TABLES WITH READ LOCK;
下面是解除锁语句:
mysql> UNLOCK TABLES;
6.2. 备份数据库
定期的备份可使我们数据库崩溃造成的损失大大降低。在MySQL中进行数据备份的方法有两种,一种是使用mysqldump程序,一种是使用mysqlhotcopy、cp、tar或cpio等打包程序直接拷贝数据库文件。mysqldump程序备份数据库较慢,但它生成的文本文件便于移植。使用mysqlhotcopy等程序备份速度快,因为它直接对系统文件进行操作,需人为协调数据库数据的备份前后一致性。
-
使用mysqldump备份数据库其实就是把数据库转储成一系列CREATE TABLE和INSERT语句,通过这些语句我们就可重新生成数据库。使用mysqldump的方法如下:
% mysqldump --opt testdb | gzip > /data/backup/testdb.bak
#--opt选项会对转储过程进行优化,生成的备份文件会小一点,后的管道操作会进行数据压缩
% mysqldump --opt testdb mytable1,mytable2 | gzip > /data/backup/testdb_mytable.bak
#可在数据库后接数据表名,只导出指定的数据表,多个数据表可用逗号分隔--opt选项还可激活--add-drop-table选项,它将会在备份文件的每条CREATE TABLE前加上一条DROP TABLE IF EXISTS语句。这可方便进行数据表的更新,而不会发生“数据表已存在”的错误。 用mysqldump命令还可直接把数据库转移到另外一台服务器上,不用生成备份文件。重复执行可定期更新远程数据库。
% mysqladmin -h remote_host create testdb
% mysqldump --opt testdb | mysql -h remote_host testdb
另外还可通过ssh远程调用服务器上的程序,如:
% ssh remote_host mysqladmin create testdb
% mysqldump --opt testdb | ssh remote_host mysql testdb -
通过直接拷贝系统文件的方式备份数据库,在备份时,要确保没有人对数据库进行修改操作。要做到这点,最好关闭服务器。如果不能关闭的,要以只读方试锁定有关数据表。下面是一些示例:
% cp -r db /backup/db #备份db数据库到/backup/db目录
% cp table_name.* /backup/db #只备份table_name数据表
% scp -r db remotehot:/usr/local/mysql/data #用scp把数据库直接拷贝到远程服务器在把数据库直接拷贝到远程主机时,应注意两台机器必须有同样的硬件结构,或者将拷贝的数据表全部是可移植数据表类型。 -
使用mysqlhotcopy工具,它是一个Perl DBI脚本,可在不关闭服务器的情况下备份数据库,它主要的优点是:
它直接拷贝文件,所以它比mysqldump快。
可自动完成数据锁定工作,备份时不用关闭服务器。
能刷新日志,使备份文件和日志文件的检查点能保持同步。
下面是该工具的使用示例:
% mysqlhotcopy db /bakcup/ #把db数据库备份到backup/db目录里,会自动创建一个db目录
-
使用BACKUP TABLE语句进行备份,该语句最早出现在MySQL 3.23.25版本中,仅适用于MyISAM数据表。用法如下:
mysql> BACKUP TABLE mytable TO '/backup/db'; #把mytable数据表备份到/backup/db目录下
为了执行该语句,你必须拥有那些表的FILE权限和SELECT权限,备份目录还必须是服务器可写的。该语句执行时,会先把内存中的数据写入磁盘,再把各个数据表的.frm(表结构定义文件)、.MYD(数据)文件从数据目录拷贝到备份目录。它不拷贝.MYI(索引)文件,因为它能用另外两个文件重建。BACKUP TABLE语句备份时,依次锁定数据表,当同时备份多个数据表时,数据表可能会被修改,所以备份0完成时,备份文件中的数据和现时数据表中的数据可能会有差异,为了消除该差异,我们可用只读方式锁定数据表,在备份完成后再解锁。如:
mysql> LOCK TABLES tb1 READ,tb2 READ;
mysql> BACKUP TABLE tb1,tb2 TO 'backup/db';
mysql> UNLOCK TABLES;使用BACKUP TABLE语句备份的数据表可用RESTORE TABLE重新加载到服务器。
InnoDB和BDB数据库也可用mysqldump和直接拷贝法进行备份。使用直接拷贝法时应注意需把组成InnoDB和BDB数据库的所有文件都拷贝下来,如InnoDB的.frm文件、日志文件和表空间配置文件;BDB的数据文件、日志文件等。
使用镜像机制进行备份,我们可用SLAVE STOP语句挂起从服务器的镜像,在从服务器上通过直接拷贝法或其它工具制作备份。备份完成,用SLAVE START重新启动镜像,从服务器重新与主服务器同步,接收备份时主服务器所做的修改。
在MySQL中没有为数据库重命名的命令,但我们可用mysqldump转储数据库,再创建一个新的空数据库,把转储文件加载到该新数据库,这样就完成数据库重命名的工作。如:
% mysqldump old_db >db.sql #转储db数据库数据
% mysqladmin create new_db #新建一个空的数据库
% mysql new_db < db.sql #把db数据库的数据加载到新的数据库中
% mysqladmin drop old_db #删除旧的数据库
一个更简单的重命名数据库的方法是直接修改数据库目录名,但该方法不适用于InnoDB和BDB数据库。注意,在更名后,需在权限表中更新相关数据表信息,需执行以下语句:
mysql> UPDATE db SET db='new_db' WHERE db='old_db';
mysql> UPDATE tables_priv SET db='new_db' WHERE db='old_db';
mysql> UPDATE columns_priv SET db='new_db' WHERE db='old_db';
mysql> UPDATE host SET db='new_db' WHERE db='old_db';
6.3. 使用备份恢复数据
恢复过程包括两个信息源---备份文件和二进制日志,备份文件可使用数据恢复到执行备份时的状态,而二进制日志可恢复到发生故障时的状态。下面分别介绍如何利用这两个文件恢复一个数据库或恢复单个数据表。
恢复整个数据库的步骤:
把需恢复的数据库的整个目录的内容拷贝到其它地方,以备用。
使用最近的备份文件重载数据库。如果使用mysqldump生成的备份,则可使用它们作为mysql的输入重载;如果是通过拷贝数据库目录来备份的,则要关闭数据库服务器,再把备份重新拷贝到数据目录,再重启数据库服务器。
-
通过二进制日志重做事务,恢复到出错点的数据。具体操作是这样的,用mysqlbinlog把日志转换成ASCII格式,再把它作为mysql的输入,并指定--one-database选项,以便mysql只执行你指定的数据库恢复。如:
% ls -t -r -l binlog.[0-9]* | xargs mysqlbinlog | mysql --one-database db_name
但上面命令只适合所有日志文件名具有相同长度的情况。否则需用下面的Perl代码来处理:
#!/usr/bin/perl -w
# sort_num.pl use strict; my @files = <>; #read all input file
@files = sort { my $anum = $1 if $a =~/\.(\d+)$/; #sort them by numeric extension
my $bnum = $1 if $b =~/\.(\d+)$/;
$anum <=> $bnum;
} @files;
print @files; #print them
exit(0); 如下使用该脚本:
% ls -l binlog.[0-9]* | sort_num.pl | xargs mysqlbinlog | mysql --one-database db_name上面讨论的是需所有日志文件的情况,但多数情况下我们只需备份后生成的几个日志文件,这时,可用以下命令来重做。
% mysqlbinlog binlog.1234 | mysql --one-database db_name
% mysqlbinlog binlog.1235 | mysql --one_database db_name
...如果我们需恢复因执行DROP DATABASE,DROP TABLE或DELETE语句而损坏的数据库,就需在日志文件中删除该语句,否则重做后结果还是一样。所以需把日志转换成ASCII格式并保存起来,再用编辑器打开该文件,删除这些语句后再重做。
如果使用文本变更日志,则不需使用mysqlbinlog程序,因为该日志文件本身就是ASCII格式。
恢复使用BACKUP TABLE命令备份的数据表可用RESTORE TABLE语句:
备份语句:
mysql> BACKUP TABLE table_name1,table_name2 TO '/backup/table_backup';
恢复语句:
mysql> RESTORE TABLE table_name1,table_name2 FROM '/backup/table_backup';
恢复有外键的数据表,可用SET FOREIGN_KEY_CHECK = 0;语句先关闭键字检查,导入表后再重启它,赋值为1表示检查有效。
恢复InnoDB表空间,当服务器重启时,InnoDB处理程序会执行自动恢复工作,通过选项文件[mysqld]段中的set-variable=innodb_force_recovery=level设置自动恢复的级别,推荐典型的启动值为4。如果需从备份文件恢复,则和上面介绍的方法一样。BDB数据表的恢复也一样,启动服务器时它会进行自动恢复。
Chapter 7. MySQL程序介绍
安装完MySQL后,在MySQL的安装目录下会生成很多有用的程序,下面对这些程序进行一一介绍。
libmysqld----嵌入式MySQL服务器,它不能独立运行,它是一个函数库,可嵌入到其它程序中,使程序具有MySQL服务器的功能。
myisamchk和isamchk----检查和修复数据表、分析键值的分布情况、禁止或启用数据表索引的工具。
myisampack和pack_isam----压缩数据表并生成只读数据表。
mysql----最常用的一个与服务器交互的命令行客户端程序。
mysqlaccess----一个用来测试数据库访问权限的脚本。
mysqladmin----一个用来执行各种系统维护和管理工作的工具。
mysqlbinlog----一个以ASCII格式显示二进制变更日志内容的工具。
mysqlbug----一个用来生成程序漏洞报告的脚本。
mysql_config----当准备编译基于MySQL的程序时,可以利用这个工具程序来确定该程序的编译选项和标志。
mysqld----MySQL服务器程序,MySQL数据的核心。
mysqld_multi----一个用来同时启动和关闭多个MySQL服务器的脚本。
mysql_safe----一个用来启动和监控MySQL服务器的脚本。
mysqldump----一个用来导出数据表内容的工具。
mysqlhotcopy----数据库备份工具。
mysqlimport----一个对数据表批量加载数据的工具。
mysql_install_db----一个初始化系统权限表和数据目录的脚本。
mysql.server----一个用来启动和关闭MySQL服务器的脚本。
mysqlshow----一个用来显示数据库中数据表的工具。
Chapter 8. MySQL How-To
Table of Contents
8.1. 连接数据库服务器
$ ./mysql -h host_name -u user_name -p
-h host_name(--host=host_name),连接的数据库主机名,如果在本地主机上则可省略。
-u user_name(--user=user_name),数据库用户名,在unix系统上,如果系统的登录名与数据用户名一样,则可省略。在windows系统中,可通过设置环境变量USER来给出数据库用户名,如set USER=username。
-p(--password),提供数据库用户密码,有该选项mysql就会提示你输入密码。输入的密码以星号显示,以确保安全。也可直接在-p后写上密码(-p和密码间不能有空格),但这不安全,不推荐。
连接成功后,mysql数据库服务器会显示一些欢迎信息。接着就可用mysql>use database_name命令打开指定的数据库。
$ ./mysql -h host_name -u user_name -p database_name命令可直接打开指定数据库。 |
8.2. 更新用户密码
mysql>update user set password=passowrd('your passowrd') where host='%';
刷新权限设置:mysql>flush privileges;
8.3. MySQL读取配置文件的顺序
my.cnf是MySQL数据库的配置文件,它存在多个地方,在/etc目录,数据目录和用户主目录都有。放在不同位置,里面的选项有不同的作用范围,下面是MySQL读取配置文件的顺序和作用。
mysql 读取配置文件的顺序:
/etc/my.cnf Global options.
DATADIR/my.cnf Server-specific options.
defaults-extra-file The file specified with the --defaults-extra-file option.
~/.my.cnf User-specific options.
8.4. 重设置MySQL管理员密码的方法
有时我们会因为设置原因或时间长了忘记了数据库管理员的密码,使得我们被关在MySQL服务器外。MySQL服务器提供了一种方法可使我们在服务器上重设密码。在windows和linux/unix平台上操作稍有不同,下面分别介绍:
-
Linux/Unix平台下:
用 % kill -TERM PID关闭服务器,用-TERM信息可使服务器在关闭前把内存中的数据写入磁盘。如果服务器没有响应,我们可用% kill -9 PID来强制删除进程,但不建议这样做。这时内存中的数据不会写入磁盘,造成数据不完整。如果你是用mysql_safe脚本启动MySQL服务器的,这个脚本会监控服务器的运行情况并在它被终止时重启服务器,所以如需关闭服务器,要先终止该进程,然后再真正终止mysqld进程。
-
使用--skip-grant-tables参数启动MySQL Server,这时MySQL服务器将不使用权限表对连接操作进行验证。你就可在不提供root密码的情况下连接上服务器,并获得root的权限。
% mysqld_safe --skip-grant-tables &
-
用以下命令登录服务器,并重设密码:
% mysql -u root #不用密码就可连接到服务器
mysql> use mysql
mysql> set password for 'root'@'localhost' = password('password');修改MySQL服务器帐户密码有三种方式,你可参考本笔记中数据库日常管理一章中的相关内容。在这种环境下,使用mysaladmin修改密码好象不行,还是提示要输入密码。 关闭服务器,再用正常方式启动服务器。
-
windows平台下:
用管理员帐号登录服务器,关闭MySQL数据库服务器。
-
使用--skip-grant-tables参数启动服务器:
c:\mysql\bin>mysqld-nt --skip-grant-tables
-
重新打开一个console窗口,用mysql命令登录服务器设置root的新密码:
c:\mysql\bin>mysql
mysql> use mysql
mysql> set password for 'root'@'localhost' = password('password'); 关闭服务器,再用正常方式启动服务器。
8.5. NULL值
NULL是空值,代表什么也没有。它不能与值进行比较操作和算术操作,也不能和NULL进行比较,因为两个空值比较是没有意义的。我们可用“is NULL” 或 “is not NULL”来判断是不空值。如:
mysql> select * from test where mytest is NULL;
mysql> select * from test where mytest is not NULL;
在MySQL3.23以后的版本有一个新的比较操作符“<=>”,它可对NULL值进行相等比较。如:
mysql> select * from test where mytest <=> UNLL;
mysql> select * from test where not (mytest <=>);
如果查询后排序中的数据中包含NULL,则从MySQL4.0.2开始,有NULL值的数据行总是出现在查询结果的开头,即使设置的desc参数。4.0.2以前版本,如果设置了asc,则出在查询结果的开头,如果设置了desc,则出现在查询结果的结尾。
8.6. 使用SQL变量
MySQL3.23.6以后的版本允许通过查询结果来设置变量,设置好的变量可在以后使用。变量用@name定义,赋值方式用@name:=value。下面是一个在查询语句中进行赋值和使用变量的例子:
mysql> select @name:=id from test where mytest="test";
mysql> select * from test where mytest=@name
8.7. 改变默认提示符
用mysql登录进数据库后,MySQL数据的默认提示符是“mysql”,我们可设置它根据用户打开的数据库名而变化,如:
mysql>prompt \d>\_
none>use test
test>use mysql
mysql>
prompt为设置命令,\d代表当前数据库,\_代表一个空格。
8.8. 非优化的全数据表DELETE操作
为了清空数据表,又需知道删除的行数和保持AUTO_INCREMENT序列的值,需用以下的删除语句:
# delete from table_name where 1;
8.9. MySQL事务处理示例
MYSQL高级特性 -- 事务处理下面以两个银行账户之间的转账为例子进行演示。要使用MySQL中的事务处理,首先需要创建使用事务表类型(如BDB = Berkeley DB或InnoDB)的表。
CREATE TABLE account (
account_id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
balance DOUBLE
) TYPE = InnoDB; 要在事务表上使用事务处理,必须要首先关闭自动提交: SET AUTOCOMMIT = 0; 事务处理以BEGIN命令开始: BEGIN; 现在mysql客户处在于服务器相关的事物上下文中。任何对事务表所做的改变在提交之前不会成为永久性的改变。 UPDATE ACCOUNT SET balance = 50.25 WHERE account_id = 1;
UPDATE ACCOUNT SET balance = 100.25 WHERE account_id = 2; 在做出所有的改变之后,使用COMMIT命令完成事务处理: COMMIT; 当然,事务处理的真正优点是在执行第二条语句发生错误时体现出来的,若在提交前终止整个事务,可以进行回滚操作: ROLLBACK; 下面是另一个例子,通过MYSQL直接进行数学运算: SELECT @first := balance FROM account WHERE account_id = 1;
SELECT @second := balance FROM account WHERE account_id = 2;
UPDATE account SET balance = @first - 25.00 WHERE account_id = 1;
UPDATE account SET balance = @second + 25.00 WHERE account_id = 2; 除了COMMIT命令外,下列命令也会自动结束当前事务: ALTER TABLE
BEGIN
CREATE INDEX
DROP DATABASE
DROP TABLE
LOCK TABLES
RENAME TABLE
TRUNCATE
UNLOCK TABLES