本文档包含 MySQL 使用的各个方面,包括帮助的使用、存储引擎选择、数据类型选择、字符集、索引设计、锁机制、事务控制、安全问题及优化等内容。它详细介绍了开发、优化和管理维护 MySQL 的实践指南,并涵盖了安装、备份恢复及应急处理等重要主题。文档还提供了相关的 SQL 技巧和常用命令,适合数据库开发者和管理员使用。
8. www.163.com
25.3 同一台机器运行多个 mysql:..................................................................................... 108
25.4 查看用户权限:............................................................................................................ 109
25.5 修改用户密码:............................................................................................................ 110
25.6 怎样灵活的指定连接的主机:.................................................................................... 111
25.7 到底匹配哪个符合条件的用户:................................................................................ 111
25.8 不进入 mysql,怎样运行 sql 语句?.......................................................................... 112
25.9 客户端怎么访问内网数据库?.................................................................................... 113
第一篇 开发篇
第 1 章 帮助的使用
在不同的 mysql 版本中,很多特性和语法有可能是不一样的,我们怎么样才能知道当前版本
的语法是什么样呢?最好的办法是学会使用 mysql 的帮助。方法很简单:
1.1 按照层次看帮助
如果不知道帮助能够提供些什么,可以一层一层往下看:
命令如下:
mysql> ? contents
You asked for help about help category: "Contents"
For more information, type 'help <item>', where <item> is one of the following
categories:
Account Management
Administration
Data Definition
Data Manipulation
Data Types
Functions
网易技术部 8
9. www.163.com
Functions and Modifiers for Use with GROUP BY
Geographic Features
Language Structure
Plugins
Storage Engines
Stored Routines
Table Maintenance
Transactions
Triggers
对于列出的分类,可以进行看自己感兴趣的部分,例如:
mysql> ? data types
You asked for help about help category: "Data Types"
For more information, type 'help <item>', where <item> is one of the following
topics:
AUTO_INCREMENT
BIGINT
BINARY
BIT
BLOB
BLOB DATA TYPE
BOOL EAN
。。。。。。
对于列出的具体数据类型,可以进一步看详细情况:
mysql> ? int
Name: 'INT'
Description:
INT[(M)] [UNSIGNED] [ZEROFILL]
网易技术部 9
10. www.163.com
A normal-size integer. The signed range is -2147483648 to 2147483647.
The unsigned range is 0 to 4294967295.
1.2 快速查阅帮助
实际当中,如果我们需要快速查阅某项语法时,可以使用关键字进行快速查询。例如,我想
知道 show 命令都能看些什么东西,可以用如下命令:
mysql> ? show
Name: 'SHOW'
Description:
SHOW has many forms that provide information about databases, tables,
columns, or status information about the server. This section describes
those following:
SHOW AUTHORS
SHOW CHARACTER SET [LIKE 'pattern']
SHOW COLLATION [LIKE 'pattern']
SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']
SHOW CONTRIBUTORS
SHOW CREATE DATABASE db_name
SHOW CREATE EVENT event_name
SHOW CREATE FUNCTION funcname
。。。。。。
我想知道 create table 的语法,可以命令如下:
mysql> ? create table
Name: 'CREATE TABLE'
Description:
Syntax:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
(create_definition,...)
网易技术部 10
35. www.163.com
第 9 章 常用 SQL 技巧
9.1 检索包含最大/最小值的行
MIN([DISTINCT] expr), MAX([DISTINCT] expr)
返回 expr 的最小值和最大值。 MIN() 和 MAX() 的取值可以是一个字符串参数;在这
些情况下, 它们返回最小或最大字符串值。DISTINCT 关键词可以被用来查找 expr 的不同
值的最小或最大值,然而,这产生的结果与省略 DISTINCT 的结果相同。
若找不到匹配的行,MIN()和 MAX()返回 NULL 。
mysql> SELECT student_name, MIN(test_score), MAX(test_score)
-> FROM student
-> GROUP BY student_name;
9.2 巧用 rand()/rand(n)提取随机行
可按照如下的随机顺序检索数据行,如下:
mysql> SELECT * FROM tbl_name ORDER BY RAND();
ORDER BY RAND()同 LIMIT 的结合可以从一组列中选择随机样本,如下:
mysql> SELECT * FROM table1, table2 WHERE a=b AND c<d
ORDER BY RAND() LIMIT 1000;
9.3 利用 group by 的 with rollup 子句做统计
create table sales
(
year int not null,
country varchar(20) not null,
product varchar(32) not null,
profit int
网易技术部 35
36. www.163.com
);
select year, sum(profit) from sales group by year;
select year, sum(profit) from sales group by year with rollup;
select year, country, product, sum(profit)
from sales
group by year, country, product;
select year, country, product, sum(profit)
from sales
group by year, country, product with rollup;
insert into sales values(2004,'china','tnt2004',2001);
insert into sales values(2004,'china','tnt2004',2002);
insert into sales values(2004,'china','tnt2004',2003);
insert into sales values(2005,'china','tnt2005',2004);
insert into sales values(2005,'china','tnt2005',2005);
insert into sales values(2005,'china','tnt2005',2006);
insert into sales values(2005,'china','tnt2005',2007);
insert into sales values(2005,'china','tnt2005',2008);
insert into sales values(2005,'china','tnt2005',2009);
insert into sales values(2006,'china','tnt2006',2010);
insert into sales values(2006,'china','tnt2006',2011);
insert into sales values(2006,'china','tnt2006',2012);
select year, country, product, sum(profit)
from sales
group by year, country, product;
select year, country, product, sum(profit)
from sales
group by year, country, product with rollup;
网易技术部 36
37. www.163.com
SELECT year, country, product, SUM(profit)
FROM sales
GROUP BY year, country, product WITH ROLLUP
LIMIT 5;
当你使用 ROLLUP时, 你不能同时使用 ORDER BY子句进行结果排序。换言之, ROLLUP
和ORDER BY 是互相排斥的
LIMIT 用在 ROLLUP 后面
9.4 用 bit group functions 做统计
Group by 统计语句的一般用法:
SELECT student_name, AVG([DISTINCT] expr)
-> FROM student
-> GROUP BY student_name;
在本小节,主要介绍 group by 语句和 bit_and ,bit_or 函数共同使用完成统计工作,先来
了解一下 bit_and 和 bit_or 函数,举例如下:
mysql> CREATE TABLE `ta` (
-> `id` smallint(5) unsigned NOT NULL default '0',
-> KEY `id` (`id`)
-> ) TYPE=MyISAM;
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO `ta` VALUES("1"),("2"),("3"),("4");
Query OK, 8 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT BIT_OR(id) from ta;
+------------+
| BIT_OR(id) |
+------------+
| 7|
网易技术部 37
38. www.163.com
+------------+
1 row in set (0.00 sec)
# ..0001
# ..0010
# ..0011
# ..0100
# OR ..0000
# ---------
# ..0111
mysql> SELECT BIT_AND(id) from ta;
+-------------+
| BIT_AND(id) |
+-------------+
| 0|
+-------------+
1 row in set (0.00 sec)
# ..0001
# ..0010
# ..0011
# ..0100
# AND ..1111
# ----------
# ..0000
熟悉了 bit_and 和 bit_or 后我们一起来学习一下 bit_and ,bit_or 和 group by 函
数共同使用进行统计工作.
针对 上面的表 ta 我们增加字段 cust_type 并按这个字段的值进行分类统计
alter table ta add column cust_type varchar(100);
update ta set cust_type ='2' where id>3;
update ta set cust_type ='1' where cust_type is null;
mysql> SELECT cust_type,BIT_OR(id) from ta group by cust_type;
网易技术部 38
39. www.163.com
+-----------+------------+
| cust_type | BIT_OR(id) |
+-----------+------------+
|1 | 3|
|2 | 4|
+-----------+------------+
2 rows in set (0.00 sec)
mysql> SELECT cust_type,BIT_and(id) from ta group by cust_type;
+-----------+-------------+
| cust_type | BIT_and(id) |
+-----------+-------------+
|1 | 0|
|2 | 4|
+-----------+-------------+
2 rows in set (0.00 sec)
BIT_AND(expr)
返回 expr 中所有比特的 bitwise AND 。计算执行的精确度为 64 比特(BIGINT) 。
若找不到匹配的行,则这个函数返回 18446744073709551615 。(这是无符号 BIGINT 值 ,
所有比特被设置为 1)。
BIT_OR(expr)
返回 expr 中所有比特的 bitwise OR。计算执行的精确度为 64 比特(BIGINT) 。
若找不到匹配的行,则函数返回 0 。
BIT_XOR(expr)
网易技术部 39
40. www.163.com
返回 expr 中所有比特的 bitwise XOR。计算执行的精确度为 64 比特(BIGINT) 。
若找不到匹配的行,则函数返回 0 。
第 10 章 其他需注意的问题
10.1 数据库名、表名大小写问题
在 MySQL 中,数据库对应数据目录中的目录。数据库中的每个表至少对应数据库目录
中的一个文件(也可能是多个,取决于存储引擎)。因此,所使用操作系统的大小写敏感性决
定了数据库名和表名的大小写敏感性。这说明在大多数 Unix 中数据库名和表名对大小写敏
感,而在 Windows 中对大小写不敏感。一个显著的例外情况是 Mac OS X,它基于 Unix 但使
用默认文件系统类型(HFS+),对大小写不敏感。然而,Mac OS X 也支持 UFS 卷,该卷对大
小写敏感,就像 Unix 一样。
注释:尽管在某些平台中数据库名和表名对大小写不敏感,不应在同一查询中使用不同的大
小写来引用给定的数据库或表。下面的查询不会工作,因为它同时引用了表 my_tables 和 as
MY_tables:
mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;
列、索引、存储子程序和触发器名在任何平台上对大小写不敏感,列的别名也不敏感 。
默认情况,表别名在 Unix 中对大小写敏感,但在 Windows 或 Mac OS X 中对大小写不敏感。
下面的查询在 Unix 中不会工作,因为它同时引用了别名 a 和 A:
mysql> SELECT col_name FROM tbl_name AS a
-> WHERE a. col_name = 1 OR A. col_name = 2;
然而,该查询在 Windows 中是可以的。要想避免出现差别,最好采用一致的转换,例
如总是用小写创建并引用数据库名和表名。在大多数移植和使用中建议使用该转换。
网易技术部 40
41. www.163.com
在 MySQL 中如何在硬盘上保存和使用表名和数据库名由 lower_case_tables_name 系
统变量确定,可以在启动 mysqld 时设置。lower_case_tables_name 可以采用下面的任一值 :
值 含义
使用 CREATE TABLE 或 CREATE DATABASE 语句指定的大写和小写在硬盘上保存表名和数据
库名。名称比较对大小写敏感。在 Unix 系统中的默认设置即如此。请注意如果在大小写
0
不敏感的文件系统上用--lower-case-table-names=0 强制设为 0,并且使用不同的大小
写访问 MyISAM 表名,会导致索引破坏。
表名在硬盘上以小写保存,名称比较对大小写敏感。MySQL 将所有表名转换为小写以便存
1 储和查找。该行为也适合数据库名和表的别名。该值为 Windows 和 Mac OS X 系统中的默
认值。
表名和数据库名在硬盘上使用 CREATE TABLE 或 CREATE DATABASE 语句指定的大小写进行
保存,但 MySQL 将它们转换为小写以便查找。名称比较对大小写敏感。注释:只在对大
2
小写不敏感的文件系统上适用! InnoDB 表名以小写保存,例如
lower_case_tables_name=1。
在 Windows 和 Mac OS X 中,lower_case_tables_name 的 默认值是 1。
如果只在一个平台上使用 MySQL,通常不需要更改 lower_case_tables_name 变 量 。
然而,如果你想要在对大小写敏感不同的文件系统的平台之间转移表,会遇到困难。例如,
在 Unix 中,my_tables 和 MY_tables 是两个不同的表,但在 Windows 中,这两个表名相同。
要想避免由于数据库或表名的大小写造成的数据转移问题,可使用两个选项:
在任何系统中可以使用 lower_case_tables_name=1。使用该选项的不利之处是当使用 SHOW
TABLES 或 SHOW DATABASES 时,看不出名字原来是用大写还是小写。
在 Unix 中使用 lower_case_tables_name=0,在 Windows 中使用 lower_case_tables_name=2。
这样了可以保留数据库名和表名的大小写。不利之处是必须确保在 Windows 中查询总是
用正确大小写引用数据库名和表名。如果将查询转移到 Unix 中,由于在 Unix 中大小写
很重要,如果大小写不正确,它们不工作。
网易技术部 41
42. www.163.com
例外:如果你正使用 InnoDB 表,在任何平台上均应将 lower_case_tables_name 设置为 1,
以强制将名转换为小写。
请注意在 Unix 中将 lower_case_tables_name 设置为 1 之前,重启 mysqld 之前,必
须先将旧的数据库名和表名转换为小写
10.2 使用外键需注意的地方
在 MySQL 中,InnoDB 表支持对外部关键字约束条件的检查。
对于除 InnoDB 类型的表,当使用 REFERENCES tbl_name(col_name)子句定义列时可
以使用外部关键字,该子句没有实际的效果,只作为备忘录或注释来提醒,你目前正定义的
列指向另一个表中的一个列。执行该语句时,实现下面很重要:
MySQL 不执行表 tbl_name 中的动作,例如作为你正定义的表中的行的动作的响应而删除行;
换句话说,该句法不会致使 ON DELETE 或 ON UPDATE 行为(如果你在 REFERENCES 子句
中写入 ON DELETE 或 ON UPDATE 子句,将被忽略)。
该句法可以创建一个 column;但不创建任何索引或关键字。
如果用该句法定义 InnoDB 表,将会导致错误。
你可以使用作为联接列创建的列,如下所示:
CREATE TABLE person (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
name CHAR(60) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE shirt (
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
网易技术部 42
43. www.163.com
color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
PRIMARY KEY (id)
);
INSERT INTO person VALUES (NULL, 'Antonio Paz');
SELECT @last := LAST_INSERT_ID();
INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', @last),
(NULL, 'dress', 'white', @last),
(NULL, 't-shirt', 'blue', @last);
INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');
SELECT @last := LAST_INSERT_ID();
INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', @last),
(NULL, 'polo', 'red', @last),
(NULL, 'dress', 'blue', @last),
(NULL, 't-shirt', 'white', @last);
SELECT * FROM person;
+----+---------------------+
| id | name |
+----+---------------------+
| 1 | Antonio Paz |
| 2 | Lilliana Angelovska |
网易技术部 43
44. www.163.com
+----+---------------------+
SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style | color | owner |
+----+---------+--------+-------+
| 1 | polo | blue | 1|
| 2 | dress | white | 1|
| 3 | t-shirt | blue | 1|
| 4 | dress | orange | 2|
| 5 | polo | red | 2|
| 6 | dress | blue | 2|
| 7 | t-shirt | white | 2|
+----+---------+--------+-------+
SELECT s.* FROM person p, shirt s
WHERE p.name LIKE 'Lilliana%'
AND s.owner = p.id
AND s.color <> 'white';
+----+-------+--------+-------+
| id | style | color | owner |
+----+-------+--------+-------+
| 4 | dress | orange | 2|
| 5 | polo | red | 2|
| 6 | dress | blue | 2|
+----+-------+--------+-------+
按照这种方式使用,REFERENCES 子句不会显示在 SHOW CREATE TABLE 或 DESCRIBE 的
输出中:
网易技术部 44
52. www.163.com
VARCHAR, BLOB 或 TEXT 列的表)进行了很多更改,则应使用 OPTIMIZE TABLE。被删
除的记录被保持在链接清单中,后续的 INSERT 操作会重新使用旧的记录位置。您可
以使用 OPTIMIZE TABLE 来重新利用未使用的空间,并整理数据文件的碎片。
OPTIMIZE TABLE 只对 MyISAM, BDB 和 InnoDB 表起作用。
11.4 常用 SQL 的优化
11.4.1 大批量插入数据:
1. 对于 Myisam 类型的表,可以通过以下方式快速的导入大量的数据。
ALTER TABLE tblname DISABLE KEYS;
loading the data
ALTER TABLE tblname ENABLE KEYS;
这两个命令用来打开或者关闭 Myisam 表非唯一索引的更新。在导入大量的数据到一
个非空的 Myisam 表时,通过设置这两个命令,可以提高导入的效率。对于导入大量
数据到一个空的 Myisam 表,默认就是先导入数据然后才创建索引的,所以不用进行
设置。
2. 而对于 Innodb 类型的表,这种方式并不能提高导入数据的效率。对于 Innodb 类型
的表,我们有以下几种方式可以提高导入的效率:
a. 因为 Innodb 类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺
序排列,可以有效的提高导入数据的效率。如果 Innodb 表没有主键,那么系统会默认
创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这个优势提高
导入数据的效率。
b. 在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行 SET
UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
c. 如果应用使用自动提交的方式,建议在导入前执行 SET AUTOCOMMIT=0,关闭自动
提交,导入结束后再执行 SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率。
11.4.2 优化 insert 语句:
3. 如果你同时从同一客户插入很多行,使用多个值表的 INSERT 语句。这比使用分开
网易技术部 52
53. www.163.com
INSERT 语句快(在一些情况中几倍)。
Insert into test values(1,2),(1,3),(1,4)…
4. 如果你从不同客户插入很多行,能通过使用 INSERT DELAYED 语句得到更高的速度。
Delayed 的含义是让 insert 语句马上执行,其实数据都被放在内存的队列中,并
没有真正写入磁盘;这比每条语句分别插入要快的多;LOW_PRIORITY 刚好相反,
在所有其他用户对表的读写完后才进行插入;
5. 将索引文件和数据文件分在不同的磁盘上存放(利用建表中的选项);
6. 如果进行批量插入,可以增加 bulk_insert_buffer_size 变量值的方法来提高速
度,但是,这只能对 myisam 表使用;
7. 当从一个文本文件装载一个表时,使用 LOAD DATA INFILE。这通常比使用很多
INSERT 语句快 20 倍;
8. 根据应用情况使用 replace 语句代替 insert;
9. 根据应用情况使用 ignore 关键字忽略重复记录。
11.4.3 优化 group by 语句:
默认情况下,MySQL 排序所有 GROUP BY col1,col2,....。查询的方法如同在查询
中指定 ORDER BY col1,col2,...。如果显式包括一个包含相同的列的 ORDER BY
子句,MySQL 可以毫不减速地对它进行优化,尽管仍然进行排序。
如果查询包括 GROUP BY 但你想要避免排序结果的消耗,你可以指定 ORDER BY NULL
禁止排序。
例如:
INSERT INTO foo
SELECT a, COUNT(*) FROM bar GROUP BY a ORDER BY NULL;
11.4.4 优化 order by 语句:
在某些情况中,MySQL 可以使用一个索引来满足 ORDER BY 子句,而不需要额外的排
序。where 条件和 order by 使用相同的索引,并且 order by 的顺序和索引顺序相同 ,
并且 order by 的字段都是升序或者都是降序。
例如:下列 sql 可以使用索引。
网易技术部 53
54. www.163.com
SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2
DESC;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
但是以下情况不使用索引:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
--order by 的字段混合 ASC 和 DESC
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
--用于查询行的关键字与 ORDER BY 中所使用的不相同
SELECT * FROM t1 ORDER BY key1, key2;
--对不同的关键字使用 ORDER BY:
11.4.5 优化 join 语句:
Mysql4.1 开始支持 SQL 的子查询。这个技术可以使用 SELECT 语句来创建一个单列的
查询结果,然后把这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性
的完成很多逻辑上需要多个步骤才能完成的 SQL 操作,同时也可以避免事务或者表锁
死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)..
替代。
假设我们要将所有没有订单记录的用户取出来,可以用下面这个查询完成:
SELECT * FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID
FROM salesinfo )
如果使用连接(JOIN).. 来完成这个查询工作,速度将会快很多。尤其是当 salesinfo
表中对 CustomerID 建有索引的话,性能将会更好,查询如下:
SELECT * FROM customerinfo
LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.CustomerID
WHERE salesinfo.CustomerID IS NULL
连接(JOIN).. 之所以更有效率一些,是因为 MySQL 不需要在内存中创建临时表来完
网易技术部 54
55. www.163.com
成这个逻辑上的需要两个步骤的查询工作。
11.4.6 mysql 如何优化 or 条件:
对于 or 子句,如果要利用索引,则 or 之间的每个条件列都必须用到索引;如果
没有索引,则应该考虑增加索引。
11.4.7 查询优先还是更新(insert update delete
insert、update delete)优先 :
insert update、delete
MySQL 还允许改变语句调度的优先级,它可以使来自多个客户端的查询更好地协
作,这样单个客户端就不会由于锁定而等待很长时间。改变优先级还可以确保特定类
型的查询被处理得更快。
我们首先应该确定应用的类型,判断应用是以查询为主还是以更新为主的,是确
保查询效率还是确保更新的效率,决定是查询优先还是更新优先。
下面我们提到的改变调度策略的方法主要是针对 Myisam 存储引擎的,对于
Innodb 存储引擎,语句的执行是由获得行锁的顺序决定的。
MySQL 的默认的调度策略可用总结如下:
1. 写入操作优先于读取操作。
2. 对某张数据表的写入操作某一时刻只能发生一次,写入请求按照它们到达的次序来
处理。
3. 对某张数据表的多个读取操作可以同时地进行。
MySQL 提供了几个语句调节符,允许你修改它的调度策略:
1. LOW_PRIORITY关键字应用于DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。
2. HIGH_PRIORITY关键字应用于SELECT和INSERT语句。
3. DELAYED关键字应用于INSERT和REPLACE语句。
如果写入操作是一个 LOW_PRIORITY(低优先级)请求,那么系统就不会认为它的优
先级高于读取操作。在这种情况下,如果写入者在等待的时候,第二个读取者到达了,那么
就允许第二个读取者插到写入者之前。只有在没有其它的读取者的时候,才允许写入者开始
网易技术部 55
56. www.163.com
操作。这种调度修改可能存在 LOW_PRIORITY 写入操作永远被阻塞的情况。
SELECT 查询的 HIGH_PRIORITY(高优先级)关键字也类似。它允许 SELECT 插入正
在等待的写入操作之前,即使在正常情况下写入操作的优先级更高。另外一种影响是,高优
先级的 SELECT 在正常的 SELECT 语句之前执行,因为这些语句会被写入操作阻塞。
如果你希望所有支持 LOW_PRIORITY 选项的语句都默认地按照低优先级来处理,那么
请使用--low-priority-updates 选项来启动服务器。通过使用 INSERT HIGH_PRIORITY 来把
INSERT 语句提高到正常的写入优先级,可以消除该选项对单个 INSERT 语句的影响。
11.4.8 使用 SQL 提示:
SELECT SQL_BUFFER_RESULTS ...
将强制 MySQL 生成一个临时结果集。只要所有临时结果集生成后,所有表上的锁定均
被释放。这能在遇到表锁定问题时或要花很长时间将结果传给客户端时有所帮助。
当处 理 一 个 会 让 客 户 端 耗 费 点 时 间 才 能 处 理 的 大 结 果 集 时 , 可 以 考 虑 使 用
SQL_BUFFER_RESULT 提示字。这样可以告诉 MySQL 将结果集保存在一个临时表中,这
样可以尽早的释放各种锁。
� USE INDEX
在你查询语句中表名的后面,添加 USE INDEX 来提供你希望 MySQ 去参考的索引列
表,就可以让 MySQL 不再考虑其他可用的索引。
Eg:SELECT * FROM mytable USE INDEX (mod_time, name) ...
� IGNORE INDEX
如果你只是单纯的想让 MySQL 忽略一个或者多个索引,可以使用 IGNORE INDEX 作
为 Hint。
Eg:SELECT * FROM mytale IGNORE INDEX (priority) ...
� FORCE INDEX
为强制 MySQL 使用一个特定的索引,可在查询中使用 FORCE INDEX 作为 Hint。
Eg:SELECT * FROM mytable FORCE INDEX (mod_time) ...
11.5 其他优化措施
1. 使用持久的连接数据库以避免连接开销。
网易技术部 56
87. www.163.com
drop user ''@'localhost';
drop user ''@' localhost.localdomain’;
20.4 给 mysql root 帐号设置口令:
Mysql 安装完毕后,root 默认口令为空,需要马上修改 root 口令:
[zzx@localhost data]$ mysql –uroot
mysql> set password=password('123');
Query OK, 0 rows affected (0.00 sec)
20.5 设置安全密码并定期修改:
尽量使用安全密码,建议使用 6 位以上字母、数字、下画线和一些特殊字符组合而
成的字符串
20.6 只授予帐号必须的权限:
只需要赋予普通用户必须的权限,比如:
Grant select,insert,update,delete on tablename to
‘username’@’hostname’;
20.7 除 root 外,任何用户不应有 mysql 库 user 表的存取权限:
如果拥有 mysql 库中 user 表的存取权限(select、update、insert、delete) 就
,
可以轻易的增加、修改、删除其他的用户权限,造成系统的安全隐患。
20.8 不要把 FILE、PROCESS 或 SUPER 权限授予管理员以外的帐号:
FILE 权限可以被滥用于将服务器主机上 MySQL 能读取的任何文件读入到数据库表中。
包括任何人可读的文件和服务器数据目录中的文件。可以使用 SELECT 访问数据库表,
然后将其内容传输到客户端上。
网易技术部 87
88. www.163.com
不要向非管理用户授予 FILE 权限。有这权限的任何用户能在拥有 mysqld 守护进程权
限的文件系统那里写一个文件!为了更加安全,由 SELECT ... INTO OUTFILE 生成的
所有文件对每个人是可写的,并且你不能覆盖已经存在的文件。
file 权限也可以被用来读取任何作为运行服务器的 Unix 用户可读取或访问的文件。
使用该权限,你可以将任何文件读入数据库表。这可能被滥用,例如,通过使用 LOAD
DATA 装载“/etc/passwd”进一个数据库表,然后能用 SELECT 显示它。
PROCESS 权限能被用来察看当前执行的查询的明文文本,包括设定或改变密码的查
询。
SUPER 权限能用来终止其它用户或更改服务器的操作方式。比如 kill 进程
不要将 PROCESS 或 SUPER 权限授给非管理用户。mysqladmin processlist 的输出显
示出当前执行的查询正文,如果另外的用户发出一个 UPDATE user SET
password=PASSWORD('not_secure')查询,被允许执行那个命令的任何用户可能看得
到
20.9 load data local 带来的安全问题:
由 MySQL 服务器启动文件从客户端向服务器主机的传输。理论上,打过补丁的
服务器可以告诉客户端程序传输服务器选择的文件,而不是客户用 LOAD DATA 语句
指定的文件。这样服务器可以访问客户端上客户有读访问权限的任何文件。
在 Web 环境中,客户从 Web 服务器连接,用户可以使用 LOAD DATA LOCAL 来读
取 Web 服务器进程有读访问权限的任何文件(假定用户可以运行 SQL 服务器的任何命
令)。在这种环境中,MySQL 服务器的客户实际上是 Web 服务器,而不是连接 Web 服
务器的用户运行的程序。
解决方法:
可以用--local-infile=0 选项启动 mysqld 从服务器端禁用所有 LOAD DATA
LOCAL 命令。
网易技术部 88
89. www.163.com
对于 mysql 命令行客户端,可以通过指定--local-infile[=1]选项启用 LOAD
DATA LOCAL,或通过--local-infile=0 选项禁用。类似地,对于 mysqlimport,--
local or -L 选项启用本地数据文件装载。在任何情况下,成功进行本地装载需要
服务器启用相关选项。
20.10 尽量避免通过 symlinks 访问表:
不要允许使用表的符号链接。(可以用--skip-symbolic-links 选项禁用)。如果 你
用 root 运行 mysqld 则特别重要,因为任何对服务器的数据目录有写访问权限的人
则能够删除系统中的任何文件!
20.11 使用 merge 存储引擎潜藏的安全漏洞:
Merge 表在某些版本中可能存在以下安全漏洞:
用户 A 赋予表 T 的权限给用户 B
用户 B 创建一个包含 T 的 merge 表,做各种操作
用户 A 收回对 T 的权限
安全隐患:用户 B 通过 merge 表仍然可以访问表 A 中的数据
20.12 防止 DNS 欺骗:
如果你不信任你的 DNS,你应该在授权表中使用 IP 数字而不是主机名。在任何情
况下,你应该非常小心地使用包含通配符的主机名来创建 授权表条目!
20.13 drop table 命令并不收回以前的相关访问授权:
drop 表的时候,其他用户对此表的权限并没有被收回,这样导致重新创建同名的
表时,以前其他用户对此表的权限会自动赋予,导致权限外流。
因此,要在删除表时,同时取消其他用户在此表上的相应权限。
20.14 使用 SSL:
下面列出了规定 SSL、证书文件和密钥文件使用的选项。它们可以位于命令行中或
选项文件中。
网易技术部 89
100. www.163.com
22.4.2 Cluster 的关闭
shell> ndb_mgm -e shutdown
22.5 数据备份和恢复:
备份步骤:
启动管理服务器(ndb_mgm)
执行命令:start backup
管理服务器回复“备份 backup_id 开始”,其中,backup_id 是该备份的唯一 ID(如果未
作其他配置,该 ID 还将保存在簇日志中)。
管理服务器发出消息“备份 backup_id 完成”,通知备份操作已结束。
备份路径:$MYSQL_HOME/data/BACKUP/BACKUP-备份 ID
恢复步骤:
1. 进入单用户模式(先运行 ndb_mgm)
NDB> ENTER SINGLE USER MODE 5
2. ndb_restore -b 2 -n 2 -c host=192.168.7.187:1186
-m -r /home/zzx2/mysql/data/BACKUP/BACKUP-2
b:备份 id
n:节点 id
m:恢复表定义
r:恢复路径
注意:-m 参数是恢复表定义使用,只需要第一个节点带此参数就可以,否则会报
错:
Table or index with given name already exists
Restore: Failed to restore table: cluster/def/NDB$BLOB_2_3 ... Exiting
3. 退出单用户模式
NDB> EXIT SINGLE USER MODE
网易技术部 100
101. www.163.com
第 23 章 Oracle 向 Mysql 数据迁移:
23.1 数据类型的差异:
在迁移 oracle 数据到 mysql 数据库时,首先要清楚 2 个数据类型的差异,并且在
迁移前确定 oracle 中的数据类型在 mysql 数据库中使用什么样的数据类型来替换最
为合适,在转换时对一些不确定的数据类型可以通过必要的测试来进行检测和确认.
这里给出了常用的几种数据类型的对照:
Oracle 数据类型 mysql 数据类型
Date datetime
Char char
varchar2 varchar
Clob text
最大长度为65,535(216–1)字符的TEXT列。
Number MEDIUMINT
或 INT
或DECIMAL--针对带有浮点数的数据
另外,可以通过 Mysql Migration Toolkit 工具,将 oracle 的数据类型转换为
mysql 数据类型。
这个工具在 mysql 网站上提供下载.但是此工具目前只有 windows 版本。
直接使用 Mysql Migration Toolkit 工具 将 oracle 数据导入到 mysql 数据
库,会出现很多问题 ,建议对存在大量 clob 字段的数据最好不要使用此工具进行数
据的导入。
23.2 利用导出文本迁移:
23.2.1 导出为 insert sql 文本
生成 sql 文件,直接使用 mysql 命令进行导入.
网易技术部 101
102. www.163.com
例如:
使用 oracle 的 select 语句生成 sql 文件
SQL>spool test.sql
set head off
set pagesize 0
set recsep OFF
set wrap off
set feedback off
set linesize 200
set termout off
set trimspool on
select 'insert into test values(' ||id||');' from test;
spool off;
传输要导入的 sql 文件到 mysql 服务器
执行下列命令导入:
mysql -u root test <test.sql
23.2.2 导出为固定格式文本
将导入数据生成一定格式的文本文件 (利用 spool 或者一些工具,例如 golden),
然后使用 LOAD DATA INFILE 语句,高速地从文件中读取行,并装入指定表中。文件名称
必须为一个文字字符串。
例如:
mysql> USE test;
mysql>LOAD DATA INFILE '/home/bjguan/tt.txt' INTO TABLE test.tt FIELDS
TERMINATED BY 't' ;
或
mysql -e "LOAD DATA INFILE '/home/bjguan/tt.txt' INTO TABLE tt FIELDS
TERMINATED BY 't' " test -u root
网易技术部 102
107. www.163.com
方法二:
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE
tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]
24.4 MyISAM 表超过 4G 无法访问:
mysql5.0 以前的中的 myisam 存储引擎默认的表大小只支持到 4G,如果大于 4G,可
以执行以下命令来扩大表的存储能力:
alter table weblogentry MAX_ROWS=1000000000 AVG_ROW_LENGTH=15000;
执行以下命令可以查看更改前后的表状态:
myisamchk -dv tablename
其中:
Max datafile length: 4294967294 Max keyfile length: 4398046510079
表明了本表实际支持的最大 MYD size 和最大 MYI size
24.5 数据目录磁盘空间不足怎么办?
如果建表前时候预测到 data 目录下的空间不足,则在建表时用如下选项指定数据目
录和索引目录到磁盘充足的空间:
DATA DIRECTORY = 'absolute path to directory'
INDEX DIRECTORY = 'absolute path to directory'
如果表已经创建,则可以将表的数据文件和索引文件 mv 到磁盘充足的分区上,然后
在原文件处创建符号链接即可。当然,mv 前最好停机或者将表锁定,以防止表的更
改。
网易技术部 107
108. www.163.com
24.6 如何禁止 DNS 反向解析?
show processlist 命令出现了非常多个进程,但是这些进程很奇怪,类似于:
unauthenticated user | 192.168.5.71:57857 | NULL | Connect | NULL | login
| NULL
这些并不是我们正常的进程,原来这是 mysql 的一个 bug,是由于反复解析 ip 和 dns
造成的,启动的时候加上--skip-name-resolve 选项就可以避免
第 25 章 Mysql 管理中一些常用的命令和技巧:
25.1 参数设置方法:
1) 如果对服务器参数不熟悉,建议从 $MYSQL_HOME/support-files 下面按照需要 cp
合适的配置文件为数据库配置文件,例如:
cp my-large.cnf /etc/my.cnf
2) session 级修改(只对本 session 有 效 ):
set para_name=value;
3) 全局级修改(对所有新的连接都有效,但是数据库重启后失效)
set global para_name=value;
4) 永久修改
将参数在 my.cnf 中增加或者修改
25.2 mysql.sock 丢失后怎么连接数据库?
请注意,如果你指定 localhost 作为一个主机名, mysqladmin 默认使用 Unix
套接字文件连接,而不是 TCP/IP。从 MySQL 4.1 开始,通过 --protocol= TCP |
SOCKET | PIPE | MEMORY}选项,你可以显示地指定连接协议 ,举例如下:
socket 连接:
[zzx@zzx mysql]$ mysql -uroot
ERROR 2002 (HY000): Can't connect to local MySQL server through socket
'/home/zzx/mysql/mysql.sock' (2)
tcp 连接:
网易技术部 108
109. www.163.com
[zzx@zzx mysql]$ mysql --protocol=TCP -uroot -p -P3307 -hlocalhost
Enter password:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 73 to server version: 5.0.15-standard
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql>
25.3 同一台机器运行多个 mysql:
最简单的方法,将每个 mysql 安装在不同的用户下面,例如 mysql1 和 mysql2,每
个用户下面,分别执行如下操作:
export MYSQL_HOME=/home/mysql1/mysql
shell> groupadd mysql
shell> useradd -g mysql mysql1
shell> cd /home/mysql1
shell>tar -xzvf /home/mysql1/mysql-VERSION-OS.tar.gz
shell> ln -s mysql-VERSION-OS.tar.gz mysql
shell> cd mysql
cp support-files/my-large.cnf(根据实际情况选择) ./my.cnf
vi my.cnf ,主要修改[client]和[mysqld]下面的 port 和 socket,并指定字符集,
例如:
[client]
port = 3307
socket = /home/mysql1/mysql/data/mysql.sock
# The MySQL server
[mysqld]
default-character-set = utf8
port = 3307
socket = /home/mysql1/mysql/data/mysql.sock
。。。。。。
shell> scripts/mysql_install_db --user=mysql1
网易技术部 109
110. www.163.com
shell> chown -R root:mysql .
shell> chown -R mysql1:mysql data
shell> bin/mysqld_safe --user=mysql &
mysql2 用户执行的和 mysql1 类似,不同的是指定不同的 MYSQL_HOME,不同的 port、
socket 即可
25.4 查看用户权限:
怎么样查看用户权限,最简单的方法,通过如下语句:
mysql> show grants for 'test1'@'localhost';
如果要通过权限表来查看,比较复杂:
在 5.0 以下,按照以下顺序来查看:
user->db->tables_priv->columns_priv,权限范围依次递减。和参数的设置不同,
权限设置的原则是:
全局权限覆盖局部权限
首先,从 user 表中查看 user 和 host 对应的那些权限值,比如:
select_priv="Y"
说明此用户组具有对所有数据库的所有表的 select 权限,此时,再单独对某个数据
库设置 select 权限已经没有意义
如果 user 表中的 select_priv="N",则接着查看 db 表中对应用户组的权限,如果
存在一条记录如下:
Host | Db | User | Select_priv | Insert_priv |
Update_priv | Delete_priv | Create_priv | Drop_priv | Grant_priv |
References_priv | Index_priv | Alter_priv | Create_tmp_table_priv |
Lock_tables_priv |
+-----------+--------+-----------+-------------+-------------+----------
---+-------------+-------------+-----------+------------+---------------
--+------------+------------+-----------------------+------------------+
| localhost | test2 | test1 | Y | Y | Y
| Y | Y | Y | N | Y |
Y | Y | Y | Y |
网易技术部 110
111. www.163.com
则表示 test1@localhost 用户组对 test2 数据库中的所有表具有所有权限(除了
grant),此时单独对此数据库内的表进行权限设置已经没有意义;如果没有此记录
或者对应权限不是“N”,则接着查询 tables_priv 表,此表中的记录决定了对数据
库中实际表的权限;如果 tables_priv 内记录的权限都是 Y,则对表内的任何列单
独设置权限已经没有意义,如果 tables_priv 没有对应表的记录或者对应权限不是
“N”,则接着查询 columnss_priv 表的记录。
一步一般类推,最后得出某个用户组的权限。
在 mysql 5.0 以后,多了一个数据字典库 information_schema,通过这个库里面的
USER_PRIVILEGES、 SCHEMA_PRIVILEGES、TABLE_PRIVILEGES 、COLUMN_PRIVILEGES
表可以得到同样的结论。
25.5 修改用户密码:
方法 1:
可以用 mysqladmin 命令在命令行指定密码:
shell> mysqladmin -u user_name -h host_name password "newpwd"
方法 2:
为账户赋予密码的另一种方法是执行 SET PASSWORD 语句:
mysql> SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit');
如果是更改自己的密码,可以省略 for 语句:
mysql> SET PASSWORD = PASSWORD('biscuit');
方法 3:
你还可以在全局级别使用 GRANT USAGE 语句(在*.*)来指定某个账户的密码而不影
响账户当前的权限:
mysql> GRANT USAGE ON *.* TO 'jeffrey'@'%' IDENTIFIED BY 'biscuit';
方法 4:
直接更改数据库的 user 表:
shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
-> VALUES('%','jeffrey',PASSWORD('biscuit'));
mysql> FLUSH PRIVILEGES;
网易技术部 111
112. www.163.com
shell> mysql -u root mysql
mysql> UPDATE user SET Password = PASSWORD('bagel')
-> WHERE Host = '%' AND User = 'francis';
mysql> FLUSH PRIVILEGES;
注意:更改密码时候一定要使用 password 函数(mysqladmin 和 grant 两种方式不
用写,会自动加上)
25.6 怎样灵活的指定连接的主机:
在 user 表 Host 值的指定方法:
� Host 值可以是主机名或 IP 号,或'localhost'指出本地主机。
� 你可以在 Host 列值使用通配符字符“%”和“_”。
Host 值'%'匹配任何主机名,空 Host 值等价于'%'。它们的含义与 LIKE 操作符的模
式匹配操作相同。例如,'%'的 Host 值与所有主机名匹配,而'%.mysql.com'匹配
mysql.com 域的所有主机。
25.7 到底匹配哪个符合条件的用户:
例如以下两个用户:
'thomas.loc.gov' 'fred' fred, 从 thomas.loc.gov 连接
'%' 'fred' fred, 从任何主机连接
当从主机 thomas.loc.gov 进行连接的时候,上面两个用户显然都满足条件,该选
择哪个呢?
如果有多个匹配,服务器必须选择使用哪个条目。按照下述方法解决问题:
服务器在启动时读入 user 表后进行排序。
然后当用户试图连接时,以排序的顺序浏览条目
服务器使用与客户端和用户名匹配的第一行。
当服务器读取表时,它首先以最具体的 Host 值排序。主机名和 IP 号是最具体
的。'%'意味着“任何主机”并且是最不特定的。有相同 Host 值的条目首先以最具
体的 User 值排序(空 User 值意味着“任何用户”并且是最不特定的)。例如下例是
网易技术部 112
113. www.163.com
排序前和排序后的结果:
+-----------+----------+-
| Host | User | …
+-----------+----------+-
| % | root | …
| % | jeffrey | …
| localhost | root | …
| localhost | | …
+-----------+----------+-
排序前
+-----------+----------+-
| Host | User | …
+-----------+----------+-
| localhost | root | … ...
| localhost | | … ...
| % | jeffrey | … ...
| % | root | … ...
+-----------+----------+-
排序后
·记住:明确指定用户名的用户不一定是被匹配的用户
25.8 不进入 mysql,怎样运行 sql 语句?
使用--execute(-e)选项:
mysql -u root -p -e "SELECT User, Host FROM User" mysql
可以按这种方式传递多个 SQL 语句,用分号隔开:
shell> mysql -u root -p -e "SELECT Name FROM Country WHERE Name LIKE
'AU%';SELECT COUNT(*) FROM City" world
Enter password: ******
+-----------+
网易技术部 113
114. www.163.com
| Name |
+-----------+
| Australia |
| Austria |
+-----------+
+----------+
| COUNT(*) |
+----------+
| 4079 |
+----------+
请注意长形式(--execute)后面必须紧跟一个等号(=)。
25.9 客户端怎么访问内网数据库?
oracle 的客户端可以通过 cman 来访问内网中的 oralce 数据库,mysql 能实现
类似功能吗?可以,假设服务器如下:
中转服务器 ip:202.108.15.160(192.168.161.38)
内网服务器 ip:192.168.161.39,在端口 3306 上起着 mysql 服务
客户端:windows,secureCRT
� 在中转服务器上增加 ssh turnal,具体操作如下:
1. 点击 session 的属性
2. 点击 connection->port_forwarding
3. 点击 add 按钮:name 中随便起个名字;local 下的 ip 写上 127.0.0.1,port 随便
起一个未使用的 port, 如 9999;remote 下面的的 hostname 写上 192.168.161.39,
例
端口写上 3306;点击 ok 设置成功
� 在 192.168.161.39 的 mysql 内增加一个用户 test,host 设置为 192.168.161.38
� grant select on dbname.* to test@192.168.161.38 identified by '123';
客户端执行 mysql -h127.0.0.1 -P3306 -utest -p123,连接成功
网易技术部 114