🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 第5章:数据库管理 **目录** [ 5.1. MySQL服务器和服务器启动脚本](#)[ 5.1.1. 服务器端脚本和实用工具概述](#)[ 5.1.2. mysq**ld-max扩展My**SQL服务器](#)[ 5.1.3. mysqld_safe:MySQL服务器启动脚本](#)[ 5.1.4. mysql.server:MySQL服务器启动脚本](#)[ 5.1.5. mysqld_multi:管理多个MySQL服务器的程序](#)[ 5.2. mysqlmanager:MySQL实例管理器](#)[ 5.2.1. 用MySQL实例管理器启动MySQL服务器](#)[ 5.2.2. 连接到MySQL实例管理器并创建用户账户](#)[ 5.2.3. MySQL实例管理器命令行选项](#)[ 5.2.4. MySQL实例管理器配置文件](#)[ 5.2.5. MySQL实例管理器识别的命令](#)[ 5.3. mysqld:MySQL服务器](#)[5.3.1. ** mysqld**命令行选项](#)[ 5.3.2. SQL服务器模式](#)[ 5.3.3. 服务器系统变量](#)[ 5.3.4. 服务器状态变量](#)[ 5.4. mysql_fix_privilege_tables:升级MySQL系统表](#)[ 5.5. MySQL服务器关机进程](#)[ 5.6. 一般安全问题](#)[ 5.6.1. 通用安全指南](#)[ 5.6.2. 使MySQL在攻击者面前保持安全](#)[ 5.6.3. Mysqld安全相关启动选项****](#)[ 5.6.4. LOAD DATA LOCAL安全问题``](#)[ 5.7. MySQL访问权限系统](#)[ 5.7.1. 权限系统的作用](#)[ 5.7.2. 权限系统工作原理](#)[ 5.7.3. MySQL提供的权限](#)[ 5.7.4. 与MySQL服务器连接](#)[ 5.7.5. 访问控制, 阶段1:连接核实](#)[ 5.7.6. 访问控制, 阶段2:请求核实](#)[ 5.7.7. 权限更改何时生效](#)[ 5.7.8. 拒绝访问错误的原因``](#)[ 5.7.9. MySQL 4.1中的密码哈希处理](#)[ 5.8. MySQL用户账户管理](#)[ 5.8.1. MySQL用户名和密码](#)[ 5.8.2. 向MySQL增加新用户账户](#)[ 5.8.3. 从MySQL删除用户账户](#)[ 5.8.4. 限制账户资源](#)[ 5.8.5. 设置账户密码](#)[ 5.8.6. 使你的密码安全](#)[ 5.8.7. 使用安全连接](#)[ 5.9. 备份与恢复](#)[ 5.9.1. 数据库备份](#)[ 5.9.2. 示例用备份与恢复策略](#)[ 5.9.3. 自动恢复](#)[ 5.9.4. 表维护和崩溃恢复](#)[ 5.9.5. myisamchk:MyISAM表维护实用工具](#)[ 5.9.6. 建立表维护计划](#)[ 5.9.7. 获取关于表的信息](#)[ 5.10. MySQL本地化和国际应用](#)[ 5.10.1. 数据和排序用字符集](#)[ 5.10.2. 设置错误消息语言](#)[ 5.10.3. 添加新的字符集](#)[ 5.10.4. 字符定义数组](#)[ 5.10.5. 字符串比较支持](#)[ 5.10.6. 多字节字符支持](#)[ 5.10.7. 字符集问题](#)[ 5.10.8. MySQL服务器时区支持](#)[ 5.11. MySQL日志文件](#)[ 5.11.1. 错误日志](#)[ 5.11.2. 通用查询日志](#)[ 5.11.3. 二进制日志](#)[ 5.11.4. 慢速查询日志](#)[ 5.11.5. 日志文件维护](#)[ 5.12. 在同一台机器上运行多个MySQL服务器](#)[ 5.12.1. 在Windows下运行多个服务器](#)[ 5.12.2. 在Unix中运行多个服务器](#)[ 5.12.3. 在多服务器环境中使用客户端程序](#)[ 5.13. MySQL查询高速缓冲](#)[ 5.13.1. 查询高速缓冲如何工作](#)[ 5.13.2. 查询高速缓冲SELECT选项](#)[ 5.13.3. 查询高速缓冲配置](#)[ 5.13.4. 查询高速缓冲状态和维护](#) 本章涵盖了MySQL安装管理主题,例如配置服务器、管理用户账户和备份。 ### 5.1. MySQL服务器和服务器启动脚本 [ 5.1.1. 服务器端脚本和实用工具概述](#)[ 5.1.2. mysq**ld-max扩展My**SQL服务器](#)[ 5.1.3. mysqld_safe:MySQL服务器启动脚本](#)[ 5.1.4. mysql.server:MySQL服务器启动脚本](#)[ 5.1.5. mysqld_multi:管理多个MySQL服务器的程序](#) MySQL服务器,即**mysqld**,是在MySQL安装中负责大部分工作的主程序。服务器随附了几个相关脚本,当你安装MySQL时它们可以执行设置操作,或者是帮助你启动和停止服务器的帮助程序。 本节提供了服务器和相关程序的概述,以及服务器启动脚本相关信息。关于配置服务器的信息参见[5.3节,“mysqld:MySQL服务器”](# "5.3. mysqld — The MySQL Server")。 ### 5.1.1. 服务器端脚本和实用工具概述 MySQL程序采用各种不同的选项。但每个MySQL程序提供一个--help选项,你可以用来查阅程序选项相关说明。例如,你可以试试**mysqld --help**。 你可以在命令行中或在选项文件中指定选项来替换所有标准程序中的默认选项。参见[4.3节,“指定程序选项”](# "4.3. Specifying Program Options")。 下面简单描述了MySQL服务器和服务器相关程序: ·         **mysqld** SQL后台程序(即MySQL服务器)。要想使用客户端程序,该程序必须运行,因为客户端通过连接服务器来访问数据库。参见[5.3节,“mysqld:MySQL服务器”](# "5.3. mysqld — The MySQL Server")。 ·         mysqld-max 包括更多特性的一个服务器版本。参见[5.1.2节,“mysq**ld-max扩展My**SQL服务器”](# "5.1.2. The mysqld-max Extended MySQL Server") ·         mysqld_safe 服务器启动脚本。如果**mysqld-max**存在,**mysqld_safe**试图启动它,否则启动**mysqld**。参见[5.1.3节,“mysqld_safe:MySQL服务器启动脚本”](# "5.1.3. mysqld_safe — MySQL Server Startup Script")。 ·         mysql.server 服务器启动脚本。该脚本用于使用包含为特定级别的运行启动服务的脚本的运行目录的系统。它调用**mysqld_safe**来启动MySQL服务器。参见[5.1.4节,“mysql.server:MySQL服务器启动脚本”](# "5.1.4. mysql.server — MySQL Server Startup Script")。 ·         mysqld_multi 服务器启动脚本,可以启动或停止系统上安装的多个服务器。参见[5.1.5节,“mysqld_multi:管理多个MySQL服务器的程序”](# "5.1.5. mysqld_multi — Program for Managing Multiple MySQL Servers") ·         mysql_install_db 该脚本用默认权限创建MySQL授权表。通常只是在系统上首次安装MySQL时执行一次。参见[2.9.2节,“Unix下安装后的过程”](# "2.9.2. Unix Post-Installation Procedures")。 ·         ** mysql_fix_**** privilege_tables** 在升级安装后,如果新版本MySQL中的 授权表有更改,则使用该脚本来更改授权表。参见[2.10.2节,“升级授权表”](# "2.10.2. Upgrading the Grant Tables")。 服务器主机上还运行其它几个程序: ·         myisamchk 用来描述、检查、优化和维护MyISAM表的实用工具。在[5.9.5节,“myisamchk:MyISAM表维护实用工具”](# "5.9.5. myisamchk — MyISAM Table-Maintenance Utility")中描述了**myisamchk**。 ·         make_binary_distribution 该程序可以生成编译过的MySQL的二进制版本。可以通过FTP上传到ftp.mysql.com的/pub/mysql/upload/,供其它MySQL用户使用。 ·         mysqlbug MySQL 缺陷报告脚本。它可以用来向MySQL邮件系统发送缺陷报告。(你也可以访问[http://bugs.mysql.com/](http://bugs.mysql.com/)在线创建缺陷报告文件。参见[1.7.1.3节,“如何通报缺陷和问题”](# "1.7.1.3. How to Report Bugs or Problems"))。 ### 5.1.2. mysq**ld-max扩展My**SQL服务器 MySQL-Max服务器是**mysqld** MySQL服务器的一个版本,包含了更多的特性。 该分发版的使用取决于你的平台: ·         对于Windows,MySQL二进制分发版包括标准服务器 (mysqld.exe)和MySQL-Max服务器(**mysqld-max.exe**),因此你不再需要专用分发版。只需要使用一个常规Windows分发版,可以从[http://dev.mysql.com/downloads/](http://dev.mysql.com/downloads/)获得。参见[2.3节,“在Windows上安装MySQL”](# "2.3. Installing MySQL on Windows")。 ·         对于Linux,如果你使用RPM分发版安装MySQL,首先使用常规MySQL-server RPM来安装标准**mysqld**服务器。然后使用MySQL-Max RPM来安装**mysqld-max**服务器。MySQL-Max RPM假定你已经安装了常规服务器RPM。关于Linux RPM软件包的详细信息,参见[2.4节,“在Linux下安装MySQL”](# "2.4. Installing MySQL on Linux")。 ·         所有其它MySQL-Max分发版包含一个**mysqld**服务器,但具有更多的特性。 你可以从MySQL AB网址[http://dev.mysql.com/downloads/](http://dev.mysql.com/downloads/)找到MySQL-Max二进制版本。 MySQL AB使用下面的**configure**选项构建MySQL-Max服务器: ·         --with-server-suffix=-max 该选项为**mysqld**版本字符串添加一个-max后缀。 ·         --with-innodb 该选项启用InnoDB存储引擎支持。MySQL-Max服务器包括InnoDB支持。在MySQL 4.0及以上版本中,默认InnoDB包括在所有二进制分发版中,因此你不需要用MySQL-Max服务器只是用来获取InnoDB支持。 ·         --with-bdb 该选项启用Berkeley DB (BDB)存储引擎支持。 ·         --with-blackhole-storage-engine 该选项启用BLACKHOLE存储引擎支持。 ·         USE_SYMDIR 启用该定义来为Windows打开数据库符号链接支持。符号链接支持适用于所有Windows服务器,因此Max服务器不需要支持该特性。 ·         --with-ndbcluster 该选项启用NDB Cluster存储引擎支持。目前(5.1.2-alpha)只有Linux、Solaris和Mac OS X支持Cluster。已有一些用户报告在BSD 操作系统上成功使用了从源码构建的MySQL Cluster,但目前还没有得到官方支持。 MySQL-Max二进制分发版对于想要安装预编译程序的用户很方便。如果你使用源码分发版构建MySQL,你可以通过在配置时启用MySQL-Max二进制分发版构建所用的相同的特性来构建你自己的Max-like服务器。 MySQL-Max服务器包括BerkeleyDB (BDB)存储引擎,但并非所有平台支持BDB。 Solaris、Mac OS X和Linux(在大多数平台上)的MySQL-Max服务器包括NDB CLUSTER存储引擎支持。请注意必须用ndbcluster选项启动服务器,以便使服务器做为MySQL Cluster的一部分来运行。(详细信息参见[17.4节,“MySQL簇的配置”](# "17.4. MySQL Cluster Configuration"))。 下面的表显示了MySQL-Max二进制在哪个平台上包括BDB和/或NDB CLUSTER支持: <table border="1" cellpadding="0" id="table1"><tr><td> <p><strong><span>系统</span></strong></p></td> <td> <p><strong> <span>BDB</span><span>支持</span></strong></p></td> <td> <p><strong> <span>NDB</span><span>支持</span></strong></p></td> </tr><tr><td> <p><span>AIX 4.3</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>HP-UX 11.0</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>Linux-Alpha</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>Y</span></p></td> </tr><tr><td> <p><span>Linux-IA-64</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>Linux-Intel</span></p></td> <td> <p><span>Y</span></p></td> <td> <p><span>Y</span></p></td> </tr><tr><td> <p><span>Mac OS X</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>NetWare</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>SCO OSR5</span></p></td> <td> <p><span>Y</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>Solaris-SPARC</span></p></td> <td> <p><span>Y</span></p></td> <td> <p><span>Y</span></p></td> </tr><tr><td> <p><span>Solaris-Intel</span></p></td> <td> <p><span>N</span></p></td> <td> <p><span>Y</span></p></td> </tr><tr><td> <p><span>UnixWare</span></p></td> <td> <p><span>Y</span></p></td> <td> <p><span>N</span></p></td> </tr><tr><td> <p><span>Windows NT/2000/XP</span></p></td> <td> <p><span>Y</span></p></td> <td> <p><span>N</span></p></td> </tr></table> 要想找出你的服务器支持哪个存储引擎,执行下面的语句: ~~~ mysql> SHOW ENGINES; ~~~ ~~~ +------------+---------+----------------------------------------------------------------+ ~~~ ~~~ | Engine     | Support | Comment                                                        | ~~~ ~~~ +------------+---------+----------------------------------------------------------------+ ~~~ ~~~ | MyISAM     | DEFAULT | Default engine as of MySQL 3.23 with great performance         | ~~~ ~~~ | MEMORY     | YES     | Hash based, stored in memory, useful for temporary tables      | ~~~ ~~~ | HEAP       | YES     | Alias for MEMORY                                               | ~~~ ~~~ | MERGE      | YES     | Collection of identical MyISAM tables                          | ~~~ ~~~ | MRG_MYISAM | YES     | Alias for MERGE                                                | ~~~ ~~~ | ISAM       | NO      | Obsolete storage engine, now replaced by MyISAM                | ~~~ ~~~ | MRG_ISAM   | NO      | Obsolete storage engine, now replaced by MERGE                 | ~~~ ~~~ | InnoDB     | YES     | Supports transactions, row-level locking, and foreign keys     | ~~~ ~~~ | INNOBASE   | YES     | Alias for INNODB                                               | ~~~ ~~~ | BDB        | YES     | Supports transactions and page-level locking                   | ~~~ ~~~ | BERKELEYDB | YES     | Alias for BDB                                                  | ~~~ ~~~ | NDBCLUSTER | NO      | Clustered, fault-tolerant, memory-based tables                 | ~~~ ~~~ | NDB        | NO      | Alias for NDBCLUSTER                                           | ~~~ ~~~ | EXAMPLE    | NO      | Example storage engine                                         | ~~~ ~~~ | ARCHIVE    | YES     | Archive storage engine                                         | ~~~ ~~~ | CSV        | NO      | CSV storage engine                                             | ~~~ ~~~ | FEDERATED  | YES     | Federated MySQL storage engine                                 | ~~~ ~~~ | BLACKHOLE  | YES     | /dev/null storage engine (anything you write to it disappears) | ~~~ ~~~ +------------+---------+----------------------------------------------------------------+ ~~~ ~~~ 18 rows in set (0.00 sec) ~~~ (另参见[13.5.4.8节,“SHOW ENGINES语法”](# "13.5.4.8. SHOW ENGINES Syntax"))。 你还可以使用下面的语句代替SHOW ENGINES,并检查你感兴趣的存储引擎的变量值: ~~~ mysql> SHOW VARIABLES LIKE 'have%'; ~~~ ~~~ +-----------------------+----------+ ~~~ ~~~ | Variable_name         | Value    | ~~~ ~~~ +-----------------------+----------+ ~~~ ~~~ | have_archive          | YES      | ~~~ ~~~ | have_bdb              | NO       | ~~~ ~~~ | have_blackhole_engine | YES      | ~~~ ~~~ | have_compress         | YES      | ~~~ ~~~ | have_crypt            | YES      | ~~~ ~~~ | have_csv              | YES      | ~~~ ~~~ | have_example_engine   | NO       | ~~~ ~~~ | have_federated_engine | NO       | ~~~ ~~~ | have_geometry         | YES      | ~~~ ~~~ | have_innodb           | YES      | ~~~ ~~~ | have_isam             | NO       | ~~~ ~~~ | have_ndbcluster       | DISABLED | ~~~ ~~~ | have_openssl          | NO       | ~~~ ~~~ | have_partition_engine | YES      | ~~~ ~~~ | have_query_cache      | YES      | ~~~ ~~~ | have_raid             | NO       | ~~~ ~~~ | have_rtree_keys       | YES      | ~~~ ~~~ | have_symlink          | YES      | ~~~ ~~~ +-----------------------+----------+ ~~~ ~~~ 18 rows in set (0.01 sec) ~~~ SHOW命令的精确输出随使用的MySQL版本(和启用的特性)的不同而有变化。第2列的值表示各特性支持的服务器级别,如下所示: <table border="1" cellpadding="0" id="table2"><tr><td> <p><strong><span>值</span></strong></p></td> <td> <p><strong><span>含义</span></strong></p></td> </tr><tr><td> <p> <span>YES</span></p></td> <td> <p><span> </span>支持该特性并已经激活。</p></td> </tr><tr><td> <p> <span>NO</span></p></td> <td> <p><span> </span>不支持该特性。</p></td> </tr><tr><td> <p> <span>DISABLED</span></p></td> <td> <p><span> </span>支持该特性但被禁用。</p></td> </tr></table> NO值表示编译的服务器不支持该特性,因此在运行时不能激活。 出现DISABLED值是因为服务器启动时该特性被禁用,或没有给出启用它的所有选项。在后一种情况,*host_名.err*错误日志文件应包含该选项被禁用的原因。 如果服务器支持InnoDB或BDB存储引擎,你还可以看见DISABLED,但在运行启动时使用了--skip-innodb或--skip-bdb选项。对于NDB CLUSTER存储引擎,DISABLED表示服务器支持MySQL Cluster,但启动时未启用--ndb-cluster选项。 所有MySQL服务器支持MyISAM表,因为MyISAM是 默认存储引擎。 ### 5.1.3. mysqld_safe:MySQL服务器启动脚本 在Unix和NetWare中推荐使用**mysqld_safe**来启动**mysqld服务器**。**mysqld_safe**增加了一些安全特性,例如当出现错误时重启服务器并向错误日志文件写入运行时间信息。本节后面列出了NetWare的特定行为。 **注**释:为了保持同旧版本MySQL的向后兼容性,MySQL二进制分发版仍然包括**safe_mysqld**作为**mysqld_safe**的符号链接。但是,你不应再依赖它,因为再将来将删掉它。 默认情况下,**mysqld_safe**尝试启动可执行**mysqld-max**(如果存在),否则启动**mysqld**。该行为的含义是: ·         在Linux中,MySQL-Max RPM依赖该**mysqld_safe**的行为。RPM安装可执行**mysqld-max**,使**mysqld_safe**从该点起自动使用可执行命令。 ·         如果你安装包括**mysqld-max**服务器的MySQL-Max分发版,后面升级到非-Max的MySQL版本,**mysqld_safe**仍然试图运行旧的 **mysqld-max服务器**。升级时,你应手动删除旧的**mysqld-max服务器**以确保**mysqld_safe**运行新的**mysqld服务器**。 要想越过默认行为并显式指定你想要运行哪个服务器,为**mysqld_safe**指定--mysqld或--mysqld-version选项。 **mysqld_safe**的许多选项与**mysqld**的相同的。参见[5.3.1节,“**mysqld**命令行选项”](# "5.3.1. mysqld Command-Line Options")。 所有在命令行中为**mysqld_safe**指定的选项被传递给**mysqld。**如果你想要使用**mysqld**不支持的**mysqld_safe的**选项,不要在命令行中指定。相反,在选项文件的[mysqld_safe]组内将它们列出来。参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。 **mysqld_safe**从选项文件的[mysqld]、[server]和[mysqld_safe]部分读取所有选项。为了保证向后兼容性,它还读取 [safe_mysqld]部分,尽管在MySQL 5.1安装中你应将这部分重新命名为[mysqld_safe]。 **mysqld_safe**支持下面的选项: ·         --help 显示帮助消息并退出。 ·         --autoclose (只在NetWare中)在NetWare中,**mysqld_safe**可以保持窗口。当你关掉**mysqld_safe** NLM时,窗口不按默认设置消失。相反,它提示用户输入: ~~~ *<NLM has terminated; Press any key to close the screen>* ~~~ 如果你想让NetWare自动关闭窗口,在**mysqld_safe**中使用--autoclose选项。 ·         --basedir=*path* MySQL安装目录的路径。 ·         --core-file-size=*size* **mysqld**能够创建的内核文件的大小。选项值传递给**ulimit -c**。 ·         --datadir=*path* 数据目录的路径。 ·           --defaults-extra-file=*path* 除了通用选项文件所读取的选项文件名。如果给出,必须首选该选项。 ·         --defaults-file=*path* 读取的代替通用选项文件的选项文件名。如果给出,必须首选该选项。 ·         --ledir=*path* 包含**mysqld**程序的目录的路径。使用该选项来显式表示服务器位置。 ·         --log-error=*path* 将错误日志写入给定的文件。参见[5.11.1节,“错误日志”](# "5.11.1. The Error Log")。 ·         --mysqld=*prog_**name* 想要启动的服务器程序名(在ledir目录)。如果你使用MySQL二进制分发版但有二进制分发版之外的数据目录需要该选项。 ·         --mysqld-version =*suffix* 该选项类似--mysqld选项,但你只指定服务器程序名的后缀。基本名假定为**mysqld。**例如,如果你使用--mysqld-version =max,**mysqld_safe**启动ledir目录中的**mysqld-max**程序。如果--mysqld-version的参数为空,**mysqld_safe**使用目录中的**mysqld**。 ·         --nice=*priority* 使用nice程序根据给定值来设置服务器的调度优先级。 ·         --no-defaults 不要读任何选项文件。如果给出,必须首选该选项。 ·         --open-files-limit=*count* **mysqld**能够打开的文件的数量。选项值传递给 **ulimit -n**。请注意你需要用root启动**mysqld_safe**来保证正确工作! ·         --pid-file=path 进程ID文件的路径。 ·         --port=*port_num*  用来帧听TCP/IP连接的端口号。端口号必须为1024或更大值,除非MySQL以root系统用户运行。 ·         --skip-character-set-client-handshake 忽略客户端发送的字符集信息,使用服务器的默认字符集。(选择该选项,MySQL的动作与MySQL 4.0相同)。 ·         --socket=path 用于本地连接的Unix套接字文件。 ·         --timezone=*zone* 为给定的选项值设置TZ时区环境变量。从操作系统文档查阅合法的时区规定格式。 ·         --user={*user_name* | *user_id*} 以用户名*user_name*或数字用户ID* user_id*运行**mysqld服务器**。(本文中的“用户”指系统登录账户,而不是 授权表中的MySQL用户)。 执行**mysqld_safe**时,必须先给出--defaults-file或--defaults-extra-option,或不使用选项文件。例如,该命令将不使用选项文件: ~~~ mysqld_safe --port=port_num --defaults-file=file_name ~~~ 相反,使用下面的命令: ~~~ mysqld_safe --defaults-file=file_name --port=port_num ~~~ 一般情况**mysqld_safe**脚本可以启动从源码或二进制MySQL分发版安装的服务器,即使这些分发版将服务器安装到稍微不同的位置。(参见[2.1.5节,“安装布局”](# "2.1.5. Installation Layouts"))。 ** mysqld_safe**期望下面的其中一个条件是真的: ·         可以根据调用**mysqld_safe**的目录找到服务器和数据库。在二进制分发版中,**mysqld_safe**看上去在bin和data目录的工作目录下。对于源码分发版,为libexec和var目录。如果你从MySQL安装目录执行**mysqld_safe**应满足该条件(例如,二进制分发版为/usr/local/mysql)。 ·         如果不能根据工作目录找到服务器和数据库,**mysqld_safe**试图通过绝对路径对它们定位。典型位置为/usr/local/libexec和/usr/local/var。实际位置由构建分发版时配置的值确定如果MySQL安装到配置时指定的位置,它们应该是正确的。 因为**mysqld_safe**试图通过工作目录找到服务器和数据库,只要你从MySQL安装目录运行**mysqld_safe****,**可以将MySQL二进制分发版安装到其它位置: ~~~ shell> cd mysql_installation_directory ~~~ ~~~ shell> bin/mysqld_safe & ~~~ 如果**mysqld_safe**失败,即使从MySQL安装目录调用仍然失败,你可以指定--ledir和--datadir选项来指示服务器和数据库在你的系统中的安装目录。 一般情况,你不应编辑**mysqld_safe**脚本。相反,应使用命令行选项或my.cnf选项文件的[mysqld_safe]部分的选项来配置**mysqld_safe**。一般不需要编辑**mysqld_safe**来正确启动服务器。但是,如果你编辑,将来升级MySQL后会覆盖你修改的**mysqld_safe**版本,因此你应对你修改的版本进行备份以便将来重装。 在NetWare中,**mysqld_safe**是一个NetWare Loadable Module (NLM),从原Unix shell脚本移植。它执行: 1.    检查系统和选项。 2.    检查MyISAM表。 3.    保持MySQL服务器窗口。 4.    启动并监视**mysqld**,如果因错误终止则重启。 5.    **将mysqld的**错误消息发送到数据目录中的*host_name.err *文件。 6.    将**mysqld_safe**的屏幕输出发送到数据目录中的*host_name.safe*文件。 ### 5.1.4. mysql.server:MySQL服务器启动脚本 在Unix中的MySQL分发版包括**mysql.server**脚本。它可以用于使用System V-style运行目录来启动和停止系统服务的系统,例如Linux和Solaris。它还用于MySQL的Mac OS X Startup Item。 **mysql.server**位于MySQL源码树MySQL安装目录下的support-files目录中。 如果你使用Linux 服务器RPM软件包(MySQL-server-VERSION.rpm),**mysql.server**脚本将安装到/etc/init.d目录下,名为mysql。你不需要 手动安装。关于Linux RPM软件包的详细信息参见[2.4节,“在Linux下安装MySQL”](# "2.4. Installing MySQL on Linux")。 一些卖方提供的RPM软件包安装的启动脚本用其它名,例如**mysqld。** 如果你从不自动安装**mysql.server**的源码分发版或二进制分发版格式安装MySQL,也可以手动安装。相关说明参见[2.9.2.2节,“自动启动和停止MySQL”](# "2.9.2.2. Starting and Stopping MySQL Automatically")。 **mysql.server**从 [mysql.server]和选项文件的[mysqld]部分读取选项。(为了保证向后兼容性,它还读取 [safe_mysqld]部分,尽管在MySQL 5.1安装中你应将这部分重新命名为[mysqld_safe])。 ### 5.1.5. mysqld_multi:管理多个MySQL服务器的程序 **mysqld_multi**可以管理多个帧听不同Unix套接字文件和TCP/IP端口的连接的**mysqld**进程。它可以启动或停止服务器,或报告它们的当前状态。 程序寻找my.cnf中的[mysqld*N*]组(或--config-file选项指定的文件)。*N*可以为任何正整数。在下面的讨论中该数字指选项组号,或*GNR*。组号区别各选项组,并用作**mysqld_multi**的参数来指定想要启动、停止哪个服务器或获取哪个服务器的状态报告。这些组中的选项与将用来启动**mysqld**的[mysqld]组中的相同。(例如,参见[2.9.2.2节,“自动启动和停止MySQL”](# "2.9.2.2. Starting and Stopping MySQL Automatically"))。但是,当使用多个服务器时,需要每个服务器使用自己的选项值,例如Unix套接字文件和TCP/IP端口号。关于在多服务器环境中,每个服务器对应唯一选项的详细信息,参见[5.12节,“在同一台机器上运行多个MySQL服务器”](# "5.12. Running Multiple MySQL Servers on the Same Machine")。 要想调用**mysqld_multi**,使用下面的语法: ~~~ shell> mysqld_multi [options] {start|stop|report} [GNR[,GNR] ...] ~~~ start、stop和report表示你想要执行的操作。你可以在单个服务器或多个服务器上执行指定的操作,取决于选项名后面的*GNR*列。如果没有该列,**mysqld_multi**为选项文件中的所有服务器执行该操作。 每个*GNR*值代表一个选项组号或组号范围。*GNR*值应为选项文件中组名末尾的号。例如,组[mysqld17]的*GNR*为17。要想指定组号的范围,用破折号间隔开第1个和最后1个号。*GNR*值10-13代表组[mysqld10]到[mysqld13]。可以在命令行中指定多个组或组范围,用逗号间隔开。*GNR*列不能有空格字符(空格或tab);空格字符后面的内容将被忽略掉。 该命令使用选项组[mysqld17]启动单个服务器: ~~~ shell> mysqld_multi start 17 ~~~ 该命令停止多个服务器,使用选项组[mysql8]和[mysqld10]至[mysqld13]: ~~~ shell> mysqld_multi stop 8,10-13 ~~~ 使用该命令列出设置选项文件的示例: ~~~ shell> mysqld_multi --example ~~~ **mysqld_multi**支持下面的选项: ·         --config-file=*name* 指定选项文件名。这关系到**mysqld_multi**从哪里寻找[mysqld*N*]选项组。没有该选项,从通用my.cnf文件读所有选项。选项不影响 **mysqld_multi**从哪里读取自己的选项,总是从通用my.cnf文件的[mysqld_multi]组读取。 ·         --example 显示示例选项文件。 ·         --help 显示帮助消息并退出。 ·         --log=*name* 指定日志文件名。如果该文件存在,后面为日志输出。 ·         --mysqladmin=*prog_name* 用来停止服务器的**mysqladmin**二进制。 ·         --mysqld=*prog_name* 可用的**mysqld**二进制。请注意你还可以将该选项的值指定为**mysqld_safe**。选项被传递给 **mysqld。**确保在PATH环境变量设定值或**mysqld_safe**中有**mysqld**所在目录。 ·         --no-log 按照标准输出打印日志信息,不要写入日志文件。默认情况下,输出写入日志文件。 ·         --password=*password* 调用**mysqladmin**时使用的MySQL账户的密码。请注意该密码值不是可选项,不象其它MySQL程序。 ·         --silent 禁用警告。 ·         --tcp-ip 通过TCP/IP端口而不是Unix套接字文件来连接每个MySQL服务器。(如果找不到套接字文件, 服务器仍然可以运行,但只能通过 TCP/IP端口访问)。默认情况下,使用Unix套接字文件进行连接。该选项影响stop和report操作。 ·         --user=*user_name* 调用**mysqladmin**时使用的MySQL账户的用户名。 ·         --verbose 更详细。 ·         --version 显示版本信息并退出。 关于**mysqld_multi**的一些注解: ·         确保停止**mysqld服务器**(用**mysqladmin**程序)的MySQL账户在各个服务器中的用户名和密码相同。并且应确保账户具有SHUTDOWN权限。如果你想要管理的服务器的管理账户有许多不同的用户名或密码,你需要在每个服务器上创建一个账户,并具有相同的用户名和密码。例如,你可以执行下面的命令为每个服务器设置一个普通multi_admin账户: ~~~ ·                shell> mysql -u root -S /tmp/mysql.sock -proot_password ~~~ ~~~ ·                mysql> GRANT SHUTDOWN ON *.* ~~~ ~~~ ·                    -> TO 'multi_admin'@'localhost' IDENTIFIED BY 'multipass'; ~~~ 参见[5.7.2节,“权限系统工作原理”](# "5.7.2. How the Privilege System Works")。你必须为每个**mysqld服务器执行该操作**。当连接时适当更改连接参数。请注意账户名的主机部分必须允许你用multi_admin从你想要运行**mysqld_multi**的主机进行连接。 ·         如果你使用**mysqld_safe**来启动**mysqld**(例如,--mysqld=mysqld_safe),--pid-file选项很重要。每个**mysqld**应有自己的进程ID文件。使用**mysqld_safe**而不使用**mysqld**的好处是**mysqld_safe**“守护”其**mysqld**进程,如果用kill –9发送的信号或由于其它原因(例如分段故障)进程终止,则重启进程。请注意**mysqld_safe**脚本需要你从某个位置启动它。这说明运行**mysqld_multi**前你必须进入某个目录。如果启动时有问题,请参见**mysqld_safe**脚本。特别是要检查下列行: ~~~ ·                ---------------------------------------------------------------- ~~~ ~~~ ·                MY_PWD=`pwd` ~~~ ~~~ ·                # Check if we are starting this relative (for the binary release) ~~~ ~~~ ·                if test -d $MY_PWD/data/mysql -a -f ./share/mysql/english/errmsg.sys -a \ ~~~ ~~~ ·                -x ./bin/mysqld ~~~ ~~~ ·                ---------------------------------------------------------------- ~~~ 参见[5.1.3节,“mysqld_safe:MySQL服务器启动脚本”](# "5.1.3. mysqld_safe — MySQL Server Startup Script")。上述行执行的测试应成功,否则你可能遇到了问题。 ·         每个**mysqld**的Unix套接字文件和TCP/IP端口号必须不同。 ·         你可能想要为**mysqld**使用--user选项,但为此你需要用Unix root用户运行**mysqld_multi**脚本。选项文件中有选项不要紧;如果你不是超级用户,并且你用自己的Unix账户重启**mysqld**进程,你只会得到警告。 ·         **重要**:确保**mysqld**进程启动所用Unix账户可以完全访问数据目录。*不要*使用Unix root账户,除非你*知道*你在做什么。 ·         **非常重要**:使用**mysqld_multi**前,确保理解传递给**mysqld服务器的**选项的含义以及你*为什么*想要独立的**mysqld**进程。应清楚 在相同的数据目录下使用多个**mysqld服务器**的危险。使用单独的数据目录,除非你*知道*你在做什么。在线程系统中,在相同的数据目录下启动多个服务器不会得到超性能。参见[5.12节,“在同一台机器上运行多个MySQL服务器”](# "5.12. Running Multiple MySQL Servers on the Same Machine")。 下面的示例显示了你如何设置选项文件来使用**mysqld_multi**。专门省去第1个和第5个[mysqld*N*]组来说明你的选项文件可以稍有不同。这样给你更大的灵活性。**mysqld**程序重启或停止的顺序由它们在选项文件中的顺序决定。 ~~~ # This file should probably be in your home dir (~/.my.cnf) ~~~ ~~~ # or /etc/my.cnf ~~~ ~~~ # Version 2.1 by Jani Tolonen ~~~ ~~~   ~~~ ~~~ [mysqld_multi] ~~~ ~~~ mysqld     = /usr/local/bin/mysqld_safe ~~~ ~~~ mysqladmin = /usr/local/bin/mysqladmin ~~~ ~~~ user       = multi_admin ~~~ ~~~ password   = multipass ~~~ ~~~   ~~~ ~~~ [mysqld2] ~~~ ~~~ socket     = /tmp/mysql.sock2 ~~~ ~~~ port       = 3307 ~~~ ~~~ pid-file   = /usr/local/mysql/var2/hostname.pid2 ~~~ ~~~ datadir    = /usr/local/mysql/var2 ~~~ ~~~ language   = /usr/local/share/mysql/english ~~~ ~~~ user       = john ~~~ ~~~   ~~~ ~~~ [mysqld3] ~~~ ~~~ socket     = /tmp/mysql.sock3 ~~~ ~~~ port       = 3308 ~~~ ~~~ pid-file   = /usr/local/mysql/var3/hostname.pid3 ~~~ ~~~ datadir    = /usr/local/mysql/var3 ~~~ ~~~ language   = /usr/local/share/mysql/swedish ~~~ ~~~ user       = monty ~~~ ~~~   ~~~ ~~~ [mysqld4] ~~~ ~~~ socket     = /tmp/mysql.sock4 ~~~ ~~~ port       = 3309 ~~~ ~~~ pid-file   = /usr/local/mysql/var4/hostname.pid4 ~~~ ~~~ datadir    = /usr/local/mysql/var4 ~~~ ~~~ language   = /usr/local/share/mysql/estonia ~~~ ~~~ user       = tonu ~~~ ~~~   ~~~ ~~~ [mysqld6] ~~~ ~~~ socket     = /tmp/mysql.sock6 ~~~ ~~~ port       = 3311 ~~~ ~~~ pid-file   = /usr/local/mysql/var6/hostname.pid6 ~~~ ~~~ datadir    = /usr/local/mysql/var6 ~~~ ~~~ language   = /usr/local/share/mysql/japanese ~~~ ~~~ user       = jani ~~~ 参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。 ### 5.2. mysqlmanager:MySQL实例管理器 [ 5.2.1. 用MySQL实例管理器启动MySQL服务器](#)[ 5.2.2. 连接到MySQL实例管理器并创建用户账户](#)[ 5.2.3. MySQL实例管理器命令行选项](#)[ 5.2.4. MySQL实例管理器配置文件](#)[ 5.2.5. MySQL实例管理器识别的命令](#) MySQL实例管理器(IM)是通过TCP/IP端口运行的后台程序,用来监视和管理MySQL数据库服务器实例。MySQL实例管理器 适合Unix-类操作系统和Windows。 可以在mysqld_safe脚本使用MySQL实例管理器来启动和停止MySQL服务器,**甚至可以从一个远程主机**。MySQL实例管理器还执行**mysqld_multi**脚本的功能(和大多数语法)。下面为MySQL实例管理器的详细描述。 ### 5.2.1. 用MySQL实例管理器启动MySQL服务器 一般情况,用**mysql.server**脚本启动MySQL Database Server(MySQL数据库服务器),通常驻留在/etc/init.d/文件夹。默认情况下该脚本调用**mysqld_safe**脚本。但是,你可以在脚本中将use_mysqld_safe变量设置为0(零)以便使用MySQL实例管理器来启动服务器。 在这种情况下,Instance Manager的行为取决于MySQL配置文件中的选项。如果没有配置文件,MySQL实例管理器创建mysqld实例并试图用默认(编译嵌入的)配置来启动。这说明如果**mysqld没有**安装到 默认位置,IM不能猜出它的位置。如果你已经在非标准位置安装了MySQL服务器,你应使用配置文件。参见[2.1.5节,“安装布局”](# "2.1.5. Installation Layouts")。 如果有配置文件,IM将分析配置文件搜索[mysqld]部分(例如[mysqld]、[mysqld1]、[mysqld2]等)。每个部分指定一个实例。启动时IM将启动所有找到的实例。IM关闭时默认停止所有实例。 请注意有一个特殊选项mysqld-path(mysqld-path = *path-to-mysqld- binary*),只能用IM识别。使用该变量让IM知道**mysqld**二进制驻留在哪儿。你还应该为服务器设置basedir和datadir选项。 启用MySQL实例管理器的典型MySQL服务器启动/关闭循环为: ·          用**/etc/init.d/mysql**脚本启动MySQL实例管理器。 ·          MySQL实例管理器启动所有实例并监视它们。 ·         如果某个服务器实例失败,MySQL实例管理器重启它。 ·         如果MySQL实例管理器被关闭(例如用**/etc/init.d/mysql stop**命令),所有实例被MySQL实例管理器关闭。 ### 5.2.2. 连接到MySQL实例管理器并创建用户账户 使用MySQL客户端-服务器协议来处理同MySQL实例管理器之间的通信。你不能使用标准**mysql**客户端程序和MySQL C API来连接IM。IM支持客户端工具和mysql-4.1或以后的版本所分发的库所用的MySQL客户端-服务器协议版本。 IM将用户信息保存到密码文件中。密码文件的默认位置为/etc/mysqlmanager.passwd。 密码应类似于: ~~~ petr:*35110DC9B4D8140F5DE667E28C72DD2597B5C848 ~~~ 要想生成密码用**--passwd**选项调用IM。则输出可以重定向到/etc/mysqlmanager.passwd文件以添加新用户。下面为示例命令。 ~~~ ./mysqlmanager --passwd >> /etc/mysqlmanager.passwd ~~~ ~~~ Creating record for new user. ~~~ ~~~ Enter user name: mike ~~~ ~~~ Enter password: <password> ~~~ ~~~ Re-type password: <password> ~~~ 下面的行将加到/etc/mysqlmanager.passwd: ~~~ mike:*00A51F3F48415C7D4E8908980D443C29C69B60C9 ~~~ 如果/etc/mysqlmanager.passwd文件中没有该条,则不能连接IM。 ### 5.2.3. MySQL实例管理器命令行选项 MySQL实例管理器支持许多命令行选项。执行**./mysqlmanager --help**命令可以简单列出。有下面的选项: ·         --help,-? 显示帮助消息并退出。 ·         --bind-address=*name* 绑定地址用于连接。 ·         --default-mysqld-path=*name* 在Unix中,如果实例部分没有路径,则为寻找MySQL服务器二进制的地点。例如:default-mysqld-path = /usr/sbin/mysqld ·         --defaults-file=*file_name* 从给定文件读Instance Manager和MySQL服务器设定值。所有Instance Manager更改的配置将加入该文件。只能用于Instance Manager的第一选项。 ·         --install 在Windows中,将Instance Manager安装为Windows服务。 ·         --log=*name* IM日志文件的路径。结合**--run-as-service**选项使用。 ·         --monitoring-interval=*Seconds* 监视实例的间隔,单位为秒。Instance Manager将尝试连接每个监视的实例来检查它们是否是活动的/没有挂起。出现故障,IM将重启几次(实际上是多次)实例。可以用nonguarded选项为特定实例禁用该行为。如果未给定任何值, 默认使用20秒。 ·         --passwd,-P 编写passwd文件并退出。 ·         --password-file=*name* 从该文件中寻找Instance Manager用户和密码。默认文件是/etc/mysqlmanager.passwd。 ·         --pid-file=*name* 使用的进程ID文件。默认情况下,该文件文件名为mysqlmanager.pid。 ·         -- port=*port_num* 用于连接的端口号。(IANA分配的 默认端口号为2273)。 ·         --print-defaults 打印当前的默认值并退出。只能用作Instance Manager的第一选项。 ·         --remove 在Windows中,删掉Instance Manager Windows服务。假定前面已经用--install运行了Instance Manager。 ·         --run-as-service 使完善进程变为后台程序并启动。完善进程很简单,不易崩溃。出现故障后它将自己重启IM。 ·         --socket=*name* Unix中用于连接的套接字文件。默认情况下,文件名为/tmp/mysqlmanager.sock。 ·         --standalone 在Windows中以单机模式运行Instance Manager。 ·         --user=*name* 启动并运行**mysqlmanager**的用户名。建议使用运行**mysqld服务器**的用户账户来运行**mysqlmanager**。 ·         --version, -V 输出版本信息并退出。 ### 5.2.4. MySQL实例管理器配置文件 Instance Manager使用标准my.cnf文件。它使用[manager]部分为自己读取选项并读取[mysqld]部分来创建实例。[manager]部分包含上述列出的选项。下面为[manager]部分示例: ~~~ # MySQL Instance Manager options section ~~~ ~~~ [manager] ~~~ ~~~ default-mysqld-path = /usr/local/mysql/libexec/mysqld ~~~ ~~~ socket=/tmp/manager.sock ~~~ ~~~ pid-file=/tmp/manager.pid ~~~ ~~~ password-file = /home/cps/.mysqlmanager.passwd ~~~ ~~~ monitoring-interval = 2 ~~~ ~~~ port = 1999 ~~~ ~~~ bind-address = 192.168.1.5 ~~~ MySQL实例管理器只在Unix中读取并管理/etc/my.cnf文件。在Windows中,MySQL实例管理器从Instance Manager的安装目录读取my.ini文件。用--defaults-file=*file_ name*选项可以更改默认选项文件的位置。 实例部分指定启动时给每个实例的选项。这些主要是普通MySQL服务器选项,但有一些IM-专用选项: ·         mysqld-path = <path-to-mysqld-binary> **mysqld服务器**二进制的路径。 ·         shutdown-delay = * Seconds* IM应等待实例关闭的秒数。 默认为35秒。超过延迟时间后,IM假定实例正挂起并试图“kill –9”它。如果你使用带large表的InnoDB,你应当增加该值。 ·         nonguarded 如果你想要为某个实例禁用IM监视功能,应设置该选项。 下面给出了几个实例示例。 ~~~ [mysqld] ~~~ ~~~ mysqld-path=/usr/local/mysql/libexec/mysqld ~~~ ~~~ socket=/tmp/mysql.sock ~~~ ~~~ port=3307 ~~~ ~~~ server_id=1 ~~~ ~~~ skip-stack-trace ~~~ ~~~ core-file ~~~ ~~~ skip-bdb ~~~ ~~~ log-bin ~~~ ~~~ log-error ~~~ ~~~ log=mylog ~~~ ~~~ log-slow-queries ~~~ ~~~   ~~~ ~~~ [mysqld2] ~~~ ~~~ nonguarded ~~~ ~~~ port=3308 ~~~ ~~~ server_id=2 ~~~ ~~~ mysqld-path= /home/cps/mysql/trees/mysql-5.1/sql/mysqld ~~~ ~~~ socket     = /tmp/mysql.sock5 ~~~ ~~~ pid-file   = /tmp/hostname.pid5 ~~~ ~~~ datadir= /home/cps/mysql_data/data_dir1 ~~~ ~~~ language=/home/cps/mysql/trees/mysql-5.1/sql/share/english ~~~ ~~~ log-bin ~~~ log=/tmp/fordel.log ### 5.2.5. MySQL实例管理器识别的命令 一旦你已经为MySQL实例管理器设置了一个密码文件并且IM正在运行,你可以连接它。你可以使用**mysql**客户端工具通过标准MySQL API来连接。以下是MySQL实例管理器目前可以接收的命令的清单和例子。 ·         START INSTANCE <instance_name> 该命令将试图启动一个实例: ~~~ mysql> START INSTANCE mysqld4; ~~~ ~~~ Query OK, 0 rows affected (0,00 sec) ~~~ ·         STOP INSTANCE <instance_name> 将试图停止一个实例: ~~~ mysql> STOP INSTANCE mysqld4; ~~~ ~~~ Query OK, 0 rows affected (0,00 sec) ~~~ ·         SHOW INSTANCES 显示所有载入的实例名: ~~~ mysql> show instances; ~~~ ~~~ +---------------+---------+ ~~~ ~~~ | instance_name | status  | ~~~ ~~~ +---------------+---------+ ~~~ ~~~ | mysqld3       | offline | ~~~ ~~~ | mysqld4       | online  | ~~~ ~~~ | mysqld2       | offline | ~~~ ~~~ +---------------+---------+ ~~~ ~~~ 3 rows in set (0,04 sec) ~~~ ·         SHOW INSTANCE STATUS <instance_name> 显示选定的实例的状态和版本信息: ~~~ mysql> SHOW INSTANCE STATUS mysqld3; ~~~ ~~~ +---------------+--------+---------+ ~~~ ~~~ | instance_name | status | version | ~~~ ~~~ +---------------+--------+---------+ ~~~ ~~~ | mysqld3       | online | unknown | ~~~ ~~~ +---------------+--------+---------+ ~~~ ~~~ 1 row in set (0.00 sec) ~~~ ·         SHOW INSTANCE OPTIONS <instance_name> 显示实例使用的选项: ~~~ mysql> SHOW INSTANCE OPTIONS mysqld3; ~~~ ~~~ +---------------+---------------------------------------------------+ ~~~ ~~~ | option_name   | value                                             | ~~~ ~~~ +---------------+---------------------------------------------------+ ~~~ ~~~ | instance_name | mysqld3                                           | ~~~ ~~~ | mysqld-path   | /home/cps/mysql/trees/mysql-4.1/sql/mysqld        | ~~~ ~~~ | port          | 3309                                              | ~~~ ~~~ | socket        | /tmp/mysql.sock3                                  | ~~~ ~~~ | pid-file      | hostname.pid3                                     | ~~~ ~~~ | datadir       | /home/cps/mysql_data/data_dir1/                   | ~~~ ~~~ | language      | /home/cps/mysql/trees/mysql-4.1/sql/share/english | ~~~ ~~~ +---------------+---------------------------------------------------+ ~~~ ~~~ 7 rows in set (0.01 sec) ~~~ ·         SHOW <instance_name> LOG FILES 该命令提供实例使用的所有日志文件。结果包含日志文件的路径和日志文件的大小。如果没有在配置文件中指定日志文件的路径 (例如log=/var/mysql.log),IM试图猜出它的位置。如果IM不能猜出日志文件的位置,你应明确指定日志文件的位置。 ~~~ mysql> SHOW mysqld LOG FILES; ~~~ ~~~ +-------------+------------------------------------+----------+ ~~~ ~~~ | Logfile     | Path                               | Filesize | ~~~ ~~~ +-------------+------------------------------------+----------+ ~~~ ~~~ | ERROR LOG   | /home/cps/var/mysql/owlet.err      | 9186     | ~~~ ~~~ | GENERAL LOG | /home/cps/var/mysql/owlet.log      | 471503   | ~~~ ~~~ | SLOW LOG    | /home/cps/var/mysql/owlet-slow.log | 4463     | ~~~ ~~~ +-------------+------------------------------------+----------+ ~~~ ~~~ 3 rows in set (0.01 sec) ~~~ ·         SHOW <instance_name> LOG {ERROR | SLOW | GENERAL} size[,offset_from_end] 该命令查找指定的日志文件的一部分。因为大多数用户关注最新的日志消息,用size参数定义你想要从日志末尾开始索取的字节数。你可以指定可选offset_from_end参数从日志文件中部索取数据。下面的示例可以索取21个字节的数据,从日志文件末尾开始23个字节,2个字节用于结束: ~~~ mysql> SHOW mysqld LOG GENERAL 21, 2; ~~~ ~~~ +---------------------+ ~~~ ~~~ | Log                 | ~~~ ~~~ +---------------------+ ~~~ ~~~ | using password: YES | ~~~ ~~~ +---------------------+ ~~~ ~~~ 1 row in set (0.00 sec) ~~~ ·         SET instance_name.option_name=option_value 该命令编辑指定的实例的配置文件以更改/增加实例选项。IM假定配置文件位于/etc/my.cnf。你应检查文件是否存在,并具有合适的权限。 ~~~ mysql> SET mysqld2.port=3322; ~~~ ~~~ Query OK, 0 rows affected (0.00 sec) ~~~ 在MySQL服务器重启前,对配置文件进行的更改不会生效。并且,执行FLUSH INSTANCES命令后,才会将这些更改保存到Instance Manager的实例设定值的本地缓存中。 ·         UNSET instance_name.option_name 该命令从实例的配置文件删除一个选项。 ~~~ mysql> UNSET mysqld2.port; ~~~ ~~~ Query OK, 0 rows affected (0.00 sec) ~~~ 在MySQL服务器重启前,对配置文件进行的更改不会生效。并且,执行FLUSH INSTANCES命令后,才会将这些更改保存到Instance Manager的实例设定值的本地缓存中。 ·         FLUSH INSTANCES 该命令强制IM重读配置文件并清空内部结构。编辑配置文件后应执行该命令。该命令不重启实例: ~~~ mysql> FLUSH INSTANCES; ~~~ ~~~ Query OK, 0 rows affected (0.04 sec) ~~~ ### 5.3. mysqld:MySQL服务器 [5.3.1. ** mysqld**命令行选项](#)[ 5.3.2. SQL服务器模式](#)[ 5.3.3. 服务器系统变量](#)[ 5.3.4. 服务器状态变量](#) **mysqld**是MySQL服务器。下面讨论MySQL服务器的配置: ·         服务器支持的启动选项 ·         如何设置服务器SQL模式 ·         服务器系统变量 ·         服务器状态变量 ### 5.3.1. **mysqld**命令行选项 当启动**mysqld服务器**时,你可以使用[4.3节,“指定程序选项”](# "4.3. Specifying Program Options")中描述的方法指定程序选项。最常用的方法是在选项文件中或在命令行提供选项。但是,在大多数情况下,希望服务器每次运行时使用相同的选项。最好的方法是确保将它们列在选项文件中。参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。 **mysqld**从[mysqld]和[server]组读取选项。**mysqld_safe**从[mysqld]、[server]、[mysqld_safe]和[safe_mysqld]组读取选项。**mysql.server**从 [mysqld]和[mysql.server]组读取选项。嵌入式MySQL服务器通常从[server]、[embedded]和[*xxxxx_SERVER*]组读取选项,其中*xxxxx*是服务器嵌入的应用程序名。 **mysqld**接受许多命令行选项。执行**mysqld --help**可以简单列出来。要想看全部列表列,使用命令**mysqld --verbose --help**。 下面列出了一些最常用的服务器选项。其它的选项在其它地方描述: ·         影响安全的选项:参见[5.6.3节,“Mysqld安全相关启动选项****”](# "5.6.3. Startup Options for mysqld Concerning Security")。 ·         SSL-相关选项:参见[5.8.7.6节,“SSL命令行选项”](# "5.8.7.6. SSL Command-Line Options")。 ·         二进制日志控制选项:参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。 ·         复制相关选项:参见[6.8节,“复制启动选项”](# "6.8. Replication Startup Options")。 ·         特定存储引擎相关选项:参见[15.1.1节,“MyISAM启动选项”](# "15.1.1. MyISAM Startup Options")、[15.5.3节,“BDB启动选项”](# "15.5.3. BDB Startup Options")和[15.2.4节,“InnoDB启动选项”](# "15.2.4. InnoDB Startup Options")。 你还可以将变量名作为一个选项,设置服务器系统变量的值,如本节后面所述。 ·         --help,-? 显示简短的帮助消息并退出。使用--verbose和--help选项来看全部内容。 ·         --allow-suspicious-udfs 该选项控制是否用户定义的函数只有一个xxx符,用作可载入的主函数。默认情况下,该选项被关闭,只有至少有一个附属符的UDF  可以载入。这样可以防止从未包含合法UDF的共享文件装载函数。参见[27.2.3.6节,“用户定义函数安全注意事项”](# "27.2.3.6. User-Defined Function Security Precautions")。 ·         --ansi 使用标准(ANSI)SQL语法代替MySQL语法。参见[1.8.3节,“在ANSI模式下运行MySQL”](# "1.8.3. Running MySQL in ANSI Mode")。使用--sql-mode选项可以更精确控制服务器SQL模式。 ·         --basedir=*path*, -b *path* MySQL安装目录的路径。通常所有路径根据该路径来解析。 ·         --bind-address=*IP* 待绑定的IP地址。 ·         --bootstrap **mysql_install_db**脚本使用该选项来创建MySQL授权表,不需要启动MySQL服务器。 ·         --console 将错误日志消息写入stderr和stdout,即使指定了--log-error。在Windows中,如果使用该选项,**mysqld**不关闭控制台窗口。 ·         --character-sets-dir=*path* 字符集安装的目录。参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。 ·         --chroot=path 通过chroot()系统调用在启动过程中将**mysqld**服务器放入一个封闭环境中。这是推荐的一个安全措施。请注意使用该选项可以 限制LOAD DATA INFILE和SELECT ... INTO OUTFILE。 ·         --character-set-server=*charset* 使用*charset*作为 默认服务器字符集。参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。 ·         --core-file 如果**mysqld**终止,写内核文件。在某些系统中,你还必须为**mysqld_safe**指定--core-file-size 选项。参见[5.1.3节,“mysqld_safe:MySQL服务器启动脚本”](# "5.1.3. mysqld_safe — MySQL Server Startup Script")。请注意对于一些系统,例如Solaris,如果你使用--user选项不会获得内核文件。 ·         --collation-server=*collation* 使用*collation*作为 默认服务器校对规则。参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。 ·         --datadir=*path*, -h *path* 数据目录的路径。 ·         --debug[=*debug_options*], -# [*debug_options*] 如果MySQL配置了--with-debug,你可以使用该选项来获得一个跟踪文件,跟踪**mysqld**正进行的操作。*debug_options*字符串通常为'd:t:o,*file_name*'。参见[E.1.2节,“创建跟踪文件”](# "E.1.2. Creating Trace Files")。 ·         (*DEPRECATED*) --default-character-set=*charset* 使用*char设置*作为 默认字符集。由于--character-set-server,反对使用该选项。参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。 ·         --default-collation=*collation* 使用*collation*作为默认校对规则。由于--collation-server,反对使用该选项。参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。 ·         --default-storage-engine=*type* 该选项为--default-table-type的同义词。 ·         --default-table-type=*type* 设置表的默认类型。参见[第15章:](#)[*存储引擎和表类型*](# "Chapter 15. Storage Engines and Table Types")。 ·         --default-time-zone=*type* 设置默认服务器时区。该选项设置全局time_zone系统变量。如果未给出该选项, 默认时区与系统时区相同(用system_time_zone系统变量值给定)。 ·         --delay-key-write[= OFF | ON | ALL] 如何使用DELAYED KEYS选项。键写入延迟会造成再次写MyISAM表时键缓冲区不能被清空。OFF禁用延迟的键写入。ON启用用DELAYED KEYS选项创建的表的延迟的键写入。ALL延迟所有MyISAM表的键写入。参见[7.5.2节,“调节服务器参数”](# "7.5.2. Tuning Server Parameters")。参见[15.1.1节,“MyISAM启动选项”](# "15.1.1. MyISAM Startup Options")。 **注**释:如果你将该变量设置为ALL,你不应从另一个正使用MyISAM表的程序中使用MyISAM表(例如从另一个MySQL服务器或用**myisamchk**)。这样操作会导致索引破坏。 ·         --des-key-file=*file_name* 从该文件读DES_ENCRYPT()和DES_DECRYPT()使用的 默认键。 ·         --enable-named-pipe 启用命名管道支持。该选项只适用Windows NT、2000、XP和2003系统,并且只适用支持命名管道连接的**mysqld-nt**和**mysqld-max-nt**服务器。   ·         --exit-info[=*flags*], -T [*flags*] 这是不同标志的一个位掩码,你可以用来调试**mysqld服务器**。不要使用该选项,除非你*确切*知道它在做什么! ·         --external-locking 启用系统锁定。请注意如果你在lockd不能完全工作的系统上使用该选项(例如在Linux中),**mysqld**容易死锁。该选项以前叫--enable-locking。 **注**释:如果你在许多MySQL进程中使用该选项来更新MyISAM表,你必须确保满足下述条件: o        使用正被另一个进程更新的表的查询的缓存不可使用。 o        不应在共享表中使用--delay-key-write=ALL或DELAY_KEY_WRITE=1。 最简单的方法是结合使用--external-locking和--delay-key-write=OFF --query-cache-size=0。 (默认不能实现,因为在许多设置中,结合使用上述选项很有用)。 ·         --flush 执行SQL语句后向硬盘上清空更改。一般情况执行SQL语句后 MySQL向硬盘写入所有更改,让操作系统处理与硬盘的同步。参见[A.4.2节,“如果MySQL依然崩溃,应作些什么”](# "A.4.2. What to Do If MySQL Keeps Crashing")。 ·         --init-file=*file* 启动时从该文件读SQL语句。每个语句必须在同一行中并且不应包括注释。 ·         --language=*lang_name*, -L *lang_name* 用给定语言给出客户端错误消息。*lang_name*可以为语言名或语言文件安装目录的全路径名。参见[5.10.2节,“设置错误消息语言”](# "5.10.2. Setting the Error Message Language")。 ·         --large-pages 一些硬件/操作系统架构支持大于 默认值(通常4 KB)的内存页。实际支持取决于使用的硬件和OS。大量访问内存的应用程序通过使用较大的页,降低了Translation Lookaside Buffer (TLB)损失,可以改善性能。 目前,MySQL只在Linux中支持大页面(在Linux中被称作HugeTLB)。我们已经计划将该支持扩展到FreeBSD、Solaris和其它可能的平台。 在Linux中可以使用大页面前,需要配置HugeTLB内存池。参考Linux内核源码中的hugetlbpage.txt文件。 默认情况下该选项被禁用。 ·         ---log[=*file*], -l [*file*] 日志连接和对文件的查询。参见[5.11.2节,“通用查询日志”](# "5.11.2. The General Query Log")。如果你不指定文件名,MySQL使用*host_name*.log作为文件名。 ·         --log-bin=[*file*] 二进制日志文件。将更改数据的所有查询记入该文件。用于备份和复制。参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。建议指定一个文件名(原因参见[A.8.1节,“MySQL中的打开事宜”](# "A.8.1. Open Issues in MySQL")),否则MySQL使用*host_name*-bin作为日志文件基本名。 ·         --log-bin-index[=*file*] 二进制日志文件名的索引文件。参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。如果你不指定文件名,并且如果你没有在--log-bin中指定,MySQL使用*host_name*-bin.index作为文件名。 ·         --log-bin-trust-routine-creators[={0|1}] 没有参数或参数为1,该选项将系统变量log_bin_trust_routine_creators设置为1。为参数 0时,该选项将系统变量设置为0。log_bin_trust_routine_creators影响MySQL如何对保存的程序的创建强加限制。参见[20.4节,“存储子程序和触发程序的二进制日志功能”](# "20.4. Binary Logging of Stored Routines and Triggers")。 ·         --log-error[=*file*] 该文件的日志错误和启动消息。参见[5.11.1节,“错误日志”](# "5.11.1. The Error Log")。如果你不指定文件名,MySQL使用*host_name.err*作为文件名。如果文件名没有扩展名,则加上.err扩展名。 ·         --log-isam[=*file*] 将所有MyISAM更改记入该文件(只有调试MyISAM时才使用)。 ·         (*DEPRECATED*) --log-long-format 记录激活的更新日志、二进制更新日志、和慢查询日志的大量信息。例如,所有查询的用户名和时间戳将记录下来。不赞成选用该选项,因为它现在代表 默认记录行为。(参见--log-short-format描述)。--log-queries-not-using-indexes选项适合将未使用索引的查询记录到慢查询日志中。 ·         --log-queries-not-using-indexes 如果你结合--log-slow-queries使用该选项,未使用索引的查询也被记录到慢查询日志中。参见[5.11.4节,“慢速查询日志”](# "5.11.4. The Slow Query Log")。 ·         --log-short-format 记录激活的更新日志、二进制更新日志、和慢查询日志的少量信息。例如,用户名和时间戳不记录下来。 ·         ---log-slow-admin-statements 将慢管理语句例如OPTIMIZE TABLE、ANALYZE TABLE和ALTER TABLE记入慢查询日志。 ·         --log-slow-queries[=*file*] 将所有执行时间超过long_query_time秒的查询记入该文件。参见[5.11.4节,“慢速查询日志”](# "5.11.4. The Slow Query Log")。详细信息参见--log-long-format和--log-short-format选项描述。   ·         --log-warnings, -W 将警告例如Aborted connection...打印到错误日志。建议启用该选项,例如,如果你使用复制 (你可以得到关于所发生事情的详细信息,例如关于网络故障和重新连接的消息)。默认情况下启用该选项;要想禁用它,使用--skip-log-warnings。中断的连接不会记入错误日志,除非值大于1。参见[A.2.10节,“通信错误和失效连接”](# "A.2.10. Communication Errors and Aborted Connections")。 ·         --low-priority-updates 表修改(INSERT, REPLACE, DELETE, UPDATE)比选择的优先级要低。也可以通过{INSERT | REPLACE | DELETE | UPDATE} LOW_PRIORITY ...来降低某个查询的优先级来实现,或通过SET LOW_PRIORITY_UPDATES=1来更改一个线程的优先级。参见[7.3.2节,“表锁定事宜”](# "7.3.2. Table Locking Issues")。 ·          --memlock **将mysqld**进程锁定在内存中。在支持mlockall()系统调用的系统上有效,例如Solaris。如果操作系统使**mysqld**在硬盘上交换时出现问题,可以为你提供帮助。请注意使用该选项时需要以root运行服务器,但从安全考虑并不是一个好注意。 ·         --myisam-recover [=*option*[,*option*...]]] 将存储引擎MyISAM设置为恢复模式。该选项值是DEFAULT、BACKUP、FORCE或QUICK值的任何组合。如果你指定多个值,用逗号间隔开。你还可以使用""值来禁用该选项。使用如果该选项,当**mysqld**打开MyISAM表时,检查是否表标记为崩溃或没有正确关闭。(只有用--skip-external-lockingare运行时,最后的选项才工作)。 如果是这种情况,**mysqld**则检查 表。如果表被破坏,**mysqld**试图维护它。 下面的选项影响维护工作: <table border="1" cellpadding="0" id="table3"><tr><td width="68" style="width:51.35pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>选项</span></strong></p></td> <td width="789" style="width:591.4pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>描述</span></strong></p></td> </tr><tr><td width="68" style="width:51.35pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>DEFAULT</span></p></td> <td width="789" style="width:591.4pt;padding:.75pt .75pt .75pt .75pt"> <p>与没有使用<span>--myisam-recover</span>选项相同。</p></td> </tr><tr><td width="68" style="width:51.35pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>BACKUP</span></p></td> <td width="789" style="width:591.4pt;padding:.75pt .75pt .75pt .75pt"> <p>如果在恢复过程中,数据文件被更改了,将<span><i><span>tbl_name</span></i><span>.MYD</span></span>文件备份为<span><i><span>tbl_name-datetime</span></i><span>.BAK</span></span>。</p></td> </tr><tr><td width="68" style="width:51.35pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>FORCE</span></p></td> <td width="789" style="width:591.4pt;padding:.75pt .75pt .75pt .75pt"> <p>即使<span>.MYD</span>文件将丢掉多个行也进行恢复。</p></td> </tr><tr><td width="68" style="width:51.35pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>QUICK</span></p></td> <td width="789" style="width:591.4pt;padding:.75pt .75pt .75pt .75pt"> <p>如果没有删除块,不要检查表中的行。</p></td> </tr></table> 在表自动修复前,MySQL错误日志添加一条注解。如果你不想用户干涉干涉大多数问题,你应使用BACKUP,FORCE选项。该选项强制维护表,即使一些行将会被删除也不例外,但它保持旧的数据文件做为备份,以便你可以在后来进行检查。 ·         --ndb-connectstring=*connect_string* 当使用NDB存储引擎时,可以指出通过设置连接字符串选项来分发群集配置的管理服务器。相关语法参见[17.4.4.2节,“MySQL簇连接字符串”](# "17.4.4.2. The MySQL Cluster connectstring")。 ·         --ndbcluster 如果二进制支持NDB CLUSTER存储引擎,使用该选项可以代替禁用MySQL Cluster支持的 默认设置。参见[第17章:](#)[*MySQL簇*](# "Chapter 17. MySQL Cluster")。 ·         --old-passwords 强制服务器为新密码生成短(4.1前)密码哈希。如果服务器必须支持旧客户端程序,为保证兼容性这很有用。参见[5.7.9节,“MySQL 4.1中的密码哈希处理”](# "5.7.9. Password Hashing in MySQL 4.1")。 ·         --one-thread 只使用一个线程(用于在Linux中调试)。只有服务器启用了调试,该选项才可用。参见[E.1节,“调试MySQL服务器”](# "E.1. Debugging a MySQL Server")。 ·         --open-files-limit=*count* 用来更改**mysqld**文件描述符的数量。如果没有设置或设置为0,则**mysqld**通过setrlimit()使用该值来保存文件描述符。如果该值为0,则**mysqld**保存max_connections*5或max_connections + table_cache*2(取较大者)个文件。如果**mysqld**给出你错误"打开的文件太多。",你应试试增加该值。 ·         --pid-file=path **mysqld_safe**使用的进程ID文件的路径。 ·         --port=*port_num*, -P *port_num* 帧听TCP/IP连接时使用的端口号。 ·         --safe-mode 跳过一些优化阶段。 ·         (*DEPRECATED*) --safe-show-database 参见[5.7.3节,“MySQL提供的权限”](# "5.7.3. Privileges Provided by MySQL")。 ·         --safe-user-create 启用后如果用户没有mysql.user表或表中列的INSERT权限,则用户不能用GRANT语句创建新用户。 ·         --secure-auth 不允许使用旧(4.1之前)密码的账户进行鉴定。 ·         --shared-memory 启用本地客户端的共享内存连接。该选项只用于Windows。 ·         --shared-memory-base-name=*name* 共享内存连接名。该选项只用于Windows。 ·         --skip-bdb 禁用BDB存储引擎。这样可以节省内存,并可能加速某些操作。如果你需要BDB表则不要使用该选项。 ·         --skip-concurrent-insert 关闭在同一时间在MyISAM表中选择和插入的能力。(只有你发现缺陷时才使用该选项)。 ·         --skip-external-locking 不要使用系统锁定。要想使用**myisamchk**,你必须关闭服务器。(参见[1.4.3节,“MySQL稳定性”](# "1.4.3. MySQL Stability"))。 要避免该需求,使用MySQL Monitor中的CHECK TABLE和REPAIR TABLE来检查并维护MyISAM表。 ·         --skip-grant-tables 该选项使服务器不使用权限系统。该权限允许访问服务器的用户*不受限制地访问*所有*数据库*。你可以从系统外壳命令行执行**mysqladmin flush-privileges**或**mysqladmin reload**命令,或执行MySQL FLUSH PRIVILEGES语句让运行的服务器重新开始使用 授权表。 ·         --skip-host-cache 为了更快地在名称-IP之间进行解析,不要使用内部主机名缓存。相反,每次客户端连接时查询DNS服务器。参见[7.5.6节,“MySQL如何使用DNS”](# "7.5.6. How MySQL Uses DNS")。 ·         --skip-innodb 禁用InnoDB存储引擎。这样可以节省内存,并可能加速某些操作。如果你需要BDB表则不要使用该选项。 ·         --skip-name-resolve 不要解析正检查客户端连接的主机名。只使用IP号。如果你使用该项, 授权表中的所有Host列值必须为IP号或localhost。参见[7.5.6节,“MySQL如何使用DNS”](# "7.5.6. How MySQL Uses DNS")。 ·         --skip-ndbcluster 禁用NDB CLUSTER存储引擎。这是支持NDB CLUSTER存储引擎的二进制的默认设置,说明只有用--ndbcluster选项显式覆盖--skip-ndbcluster选项时,系统才为该存储引擎分配内存和其它资源。使用示例参见[17.4.3节,“MySQL簇的快速测试设置”](# "17.4.3. Quick Test Setup of MySQL Cluster")。 ·         --skip-networking 不帧听TCP/IP连接。必须通过命名管道或共享内存(在Windows中)或Unix套接字文件(在Unix中)完成**mysqld**的相互操作。对于只允许本地客户端的系统,大力推荐该选项。参见[7.5.6节,“MySQL如何使用DNS”](# "7.5.6. How MySQL Uses DNS")。 ·         --standalone 只适合基于Windows-NT的系统;指导MySQL服务器不做为服务来运行。 ·         --symbolic-links, --skip-symbolic-links 启用或禁用符号链接支持。在Windows和Unix中,该选项的作用是不同的: o        在Windows中,启用符号链接,你可以通过创建包含实际目录路径的directory.sym文件来建立数据库目录的符号链接。参见[7.6.1.3节,“在Windows平台上使用关于数据库的符号链接”](# "7.6.1.3. Using Symbolic Links for Databases on Windows")。 在Unix中,启用符号链接表示你可以用CREATE TABLE语句的INDEX DIRECTORY或DATA DIRECTORY选项将MyISAM索引文件或数据文件链接到另一个目录。如果你删除或重新命名表,符号链接所指的文件也被删除或重新命名。参见[13.1.5节,“CREATE TABLE语法”](# "13.1.5. CREATE TABLE Syntax")。 ·         --skip-safemalloc 如果MySQL配置了--with-debug=full,所有MySQL程序在内存分配和释放时检查内存是否溢出。检查很慢,因此如果你不需要你可以用--skip-safemalloc选项来避免。 ·         --skip-show-database 使用该选项,只允许具有SHOW DATABASES权限的用户执行SHOW DATABASES语句,该语句显示所有数据库名。不使用该选项,允许所有用户执行SHOW DATABASES,但只向具有SHOW DATABASES权限或部分数据库权限的用户显示每个数据库名。请注意全局权限为数据库的一种权限。 ·         --skip-stack-trace 不跟踪写堆栈。当调试运行**mysqld**时该选项有用。在一些系统中,你还必须使用该选项来获得内核文件。参见[E.1节,“调试MySQL服务器”](# "E.1. Debugging a MySQL Server")。 ·         --skip-thread-priority 在快速响应中禁用线程优先级。 ·         --socket=path 在Unix中,该选项指定用于本地连接的Unix套接字文件。 默认值是/tmp/mysql.sock。在Windows中,该选项指定本地连接所使用的管道名。 默认值是MySQL。 ·         --sql-mode=*value*[,*value*[,*value*...]] 将MySQL设置为SQL模式。参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 ·         --temp-pool 该选项使服务器创建的大多数临时文件使用一系列文件名,而不是每个新文件使用唯一的文件名。这样解决了在Linux内核中用 不同的名创建许多新文件的问题。在以前,Linux似乎“泄漏”内存,因为它被直接分配到directory entry缓存而不是硬盘缓存。 ·         --transaction-isolation=*level* 设置默认事务隔离级别,可以READ-UNCOMMITTED、READ-COMMITTEE、REPEATABLE-READ或SERIALIZABLE。参见[13.4.6节,“SET TRANSACTION语法”](# "13.4.6. SET TRANSACTION Syntax")。 ·         --tmpdir=*path*, -t *path* 创建临时文件的目录路径。默认/tmp目录在太小不能容纳临时表的分区时该选项很有用。该选项接受round-robin模式的几个路径。在Unix中路径应用冒号(‘:’) 间隔开,在Windows、NetWare和OS/2中用分号(‘;’) 间隔开。如果MySQL服务器为复制从机,你不应让--tmpdir指向基于内存的文件系统中的目录或服务器主机重启时会清除的目录。复制从机需要临时文件,机器重启时可以复制临时表或执行LOAD DATA INFILE操作。如果服务器重启时临时文件目录中的文件丢失,复制失败。 ·         --user={*user_name* | *user_id*}, -u {*user_name* | *user_id*} 用*user_name*或数字用户ID* user_id*运行**mysqld服务器**。(“用户”指系统登录账户,而不是 授权表中所列的MySQL用户)。 用root启动**mysqld时*强制*使用**该选项。服务器在启动序列中更改用户ID,让它做为具体用户而不是root运行。参见[5.6.1节,“通用安全指南”](# "5.6.1. General Security Guidelines")。 要避免用户在my.cnf文件中添加--user=root选项(使服务器用root运行)时可能出现的安全漏洞,**mysqld**只使用指定的第1个--user选项,如果有多个--user选项则会出现警告。在命令行选项前处理/etc/my.cnf和$MYSQL_HOME/my.cnf中的选项,因此建议你在/etc/my.cnf中放一个--user选项,并指定root之外的其它值。在其它--user选项前先找到/etc/my.cnf中的选项,确保服务器用其它用户运行,如果找到其它--user选项则会出现警告。 ·         --version, -V 显示版本信息并退出。 你可以使用--*var_name*=*value*形式的选项为服务器系统变量。例如,--key_buffer_size=32M将变量key_buffer_size设为32MB。 请注意设置变量时,MySQL可以自动将它纠正到某个给定范围内,或如果只允许某个值,则将设置值调节到最接近允许的值。 还可以通过--set-variable=*var_name*=*value*或-O *var_name*=*value*语法来设置变量。但是,现在不赞成使用该语法。 [ 5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")完全描述了全部系统变量。调节服务器参数部分包括如何对他们进行优化。参见[7.5.2节,“调节服务器参数”](# "7.5.2. Tuning Server Parameters")。 你可以用SET语句更改大多数服务器系统变量的值。参见[13.5.3节,“SET语法”](# "13.5.3. SET Syntax")。 如果你想用SET 限制启动项可设的最大值,你可以使用--maximum-var_name命令行选项来定义。 ### 5.3.2. SQL服务器模式 MySQL服务器可以以不同的SQL模式来操作,并且可以为不同客户端应用不同模式。这样每个应用程序可以根据自己的需求来定制服务器的操作模式。 模式定义MySQL应支持哪些SQL语法,以及应执行哪种数据验证检查。这样可以更容易地在不同的环境中使用MySQL,并结合其它数据库服务器使用MySQL。 你可以用--sql-mode="*modes*"选项启动**mysqld来**设置默认SQL模式。如果你想要重设,该值还可以为空(--sql-mode ="")。 你还可以在启动后用SET [SESSION|GLOBAL] sql_mode='*modes*'语句设置sql_mode变量来更改SQL模式。设置 GLOBAL变量时需要拥有SUPER权限,并且会影响从那时起连接的所有客户端的操作。设置SESSION变量只影响当前的客户端。任何客户端可以随时更改自己的会话 sql_mode值。 *Modes*is是用逗号(‘,’)间隔开的一系列不同的模式。你可以用SELECT @@sql_mode语句查询当前的模式。默认值是空(没有设置任何模式)。 主要重要sql_mode值为: ·         ANSI 更改语法和行为,使其更符合标准SQL。 ·         STRICT_TRANS_TABLES 如果不能将给定的值插入到事务表中,则放弃该语句。对于非事务表,如果值出现在单行语句或多行语句的第1行,则放弃该语句。本节后面给出了更详细的描述。 ·         TRADITIONAL Make MySQL的行为象“传统”SQL数据库系统。该模式的简单描述是当在列中插入不正确的值时“给出错误而不是警告”。**注**释:一旦发现错误立即放弃INSERT/UPDATE。如果你使用非事务存储引擎,这种方式不是你想要的,因为出现错误前进行的数据更改不会“滚动”,结果是更新“只进行了一部分”。 本手册指“严格模式”,表示至少STRICT _TRANS_TABLES或STRICT _ALL_TABLES被启用的模式。 下面描述了支持的所有模式: ·         ALLOW_INVALID_DATES 在严格模式下不要检查全部日期。只检查1到12之间的月份和1到31之间的日。这在Web应用程序中,当你从三个不同的字段获取年、月、日,并且想要确切保存用户插入的内容(不进行日期验证)时很重要。该模式适用于DATE和DATETIME列。不适合TIMESTAMP列,TIMESTAMP列需要验证日期。 启用严格模式后,服务器需要合法的月和日,不仅仅是分别在1到12和1到31范围内。例如,禁用严格模式时'2004-04-31'是合法的,但启用严格模式后是非法的。要想在严格模式允许遮掩固定日期,还应启用ALLOW_INVALID_DATES。 ·         ANSI_QUOTES 将‘"’视为识别符引号(‘`’引号字符),不要视为字符串的引号字符。在ANSI模式,你可以仍然使用‘`’来引用识别符。启用ANSI_QUOTES后,你不能用双引号来引用字符串,因为它被解释为识别符。 ·         ERROR_FOR_DIVISION_BY_ZERO 在严格模式,在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时MySQL返回NULL。如果用到INSERT IGNORE或UPDATE IGNORE中,MySQL生成被零除警告,但操作结果为NULL。 ·         HIGH_NOT_PRECEDENCE NOT操作符的优先顺序是表达式例如NOT a BETWEEN b AND c被解释为NOT (a BETWEEN b AND c)。在一些旧版本MySQL中, 表达式被解释为(NOT a) BETWEEN b AND c。启用HIGH_NOT_PRECEDENCESQL模式,可以获得以前的更高优先级的结果。 ~~~ mysql> SET sql_mode = ''; ~~~ ~~~ mysql> SELECT NOT 1 BETWEEN -5 AND 5; ~~~ ~~~         -> 0 ~~~ ~~~ mysql> SET sql_mode = 'broken_not'; ~~~ ~~~ mysql> SELECT NOT 1 BETWEEN -5 AND 5; ~~~ ~~~         -> 1 ~~~ ·         IGNORE_SPACE 允许函数名和‘(’之间有空格。强制将所有函数名视为保存的字。结果是,如果你想要访问保存为字的数据库、表或列名,你必须引用它。例如,因为有USER()函数,mysql数据库中的user表名和该表内的User列被保存下来,因此你必须引用它们: ~~~ SELECT "User" FROM mysql."user"; ~~~ ·         NO_AUTO_CREATE_USER 防止GRANT自动创建新用户,除非还指定了密码。 ·         NO_AUTO_VALUE_ON_ZERO NO_AUTO_VALUE_ON_ZERO影响AUTO_INCREMENT列的处理。一般情况,你可以向该列插入NULL或0生成下一个序列号。NO_AUTO_VALUE_ON_ZERO禁用0,因此只有NULL可以生成下一个序列号。 如果将0保存到表的AUTO_INCREMENT列,该模式会很有用。(不推荐采用该惯例)。例如,如果你用**mysqldump**转储表并重载,MySQL遇到0值一般会生成新的序列号,生成的表的内容与转储的表不同。重载转储文件前启用NO_AUTO_VALUE_ON_ZERO可以解决该问题。**mysqldump**在输出中自动包括启用NO_AUTO_VALUE_ON_ZERO的语句。 ·         NO_BACKSLASH_ESCAPES 禁用反斜线字符(‘\’)做为字符串内的退出字符。启用该模式,反斜线则成为普通字符。 ·         NO_DIR_IN_CREATE 创建表时,忽视所有INDEX DIRECTORY和DATA DIRECTORY指令。该选项对从复制服务器有用。 ·         NO_ENGINE_SUBSTITUTION 如果需要的存储引擎被禁用或未编译,可以防止自动替换存储引擎。 ·         NO_FIELD_OPTIONS 不要在SHOW CREATE TABLE的输出中打印MySQL专用列选项。该模式在可移植模式(portability mode)下用于**mysqldump**。 ·         NO_KEY_OPTIONS 不要在SHOW CREATE TABLE的输出中打印MySQL专用索引选项。该模式在可移植模式(portability mode)下用于**mysqldump**。 ·         NO_TABLE_OPTIONS 不要在SHOW CREATE TABLE的输出中打印MySQL专用表选项(例如ENGINE)。该模式在可移植模式(portability mode)下用于**mysqldump**。 ·         NO_UNSIGNED_SUBTRACTION 在减运算中,如果某个操作数没有符号,不要将结果标记为UNSIGNED。请注意这样使UNSIGNED BIGINT不能100%用于上下文中。参见[12.8节,“Cast函数和操作符”](# "12.8. Cast Functions and Operators")。   ·         NO_ZERO_DATE 在严格模式,不要将 '0000-00-00'做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告。 ·         NO_ZERO_IN_DATE 在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入'0000-00-00'。在非严格模式,可以接受该日期,但会生成警告。 ·         ONLY_FULL_GROUP_BY 不要让GROUP BY部分中的查询指向未选择的列。 ·         PIPES_AS_CONCAT 将||视为字符串连接操作符(+)(同CONCAT()),而不视为OR。 ·         REAL_AS_FLOAT 将REAL视为FLOAT的同义词,而不是DOUBLE的同义词。 ·         STRICT_TRANS_TABLES 为所有存储引擎启用严格模式。非法数据值被拒绝。后面有详细说明。 ·         STRICT_TRANS_TABLES 为事务存储引擎启用严格模式,也可能为非事务存储引擎启用严格模式。后面有详细说明。 严格模式控制MySQL如何处理非法或丢失的输入值。有几种原因可以使一个值为非法。例如,数据类型错误,不适合列,或超出范围。当新插入的行不包含某列的没有显示定义DEFAULT子句的值,则该值被丢失。 对于事务表,当启用STRICT_ALL_TABLES或STRICT_TRANS_TABLES模式时,如果语句中有非法或丢失值,则会出现错误。语句被放弃并滚动。 对于非事务表,如果插入或更新的第1行出现坏值,两种模式的行为相同。语句被放弃,表保持不变。如果语句插入或修改多行,并且坏值出现在第2或后面的行,结果取决于启用了哪个严格选项: ·         对于STRICT_ALL_TABLES,MySQL返回错误并忽视剩余的行。但是,在这种情况下,前面的行已经被插入或更新。这说明你可以部分更新,这可能不是你想要的。要避免这点,最好使用单行语句,因为这样可以不更改表即可以放弃。 ·         对于STRICT_TRANS_TABLES,MySQL将非法值转换为最接近该列的合法值并插入调整后的值。如果值丢失,MySQL在列中插入隐式 默认值。在任何情况下,MySQL都会生成警告而不是给出错误并继续执行语句。[13.1.5节,“CREATE TABLE语法”](# "13.1.5. CREATE TABLE Syntax")描述了隐式默认值。 严格模式不允许非法日期,例如'2004-04-31'。它不允许禁止日期使用“零”部分,例如'2004-04-00'或“零”日期。要想禁止,应在严格模式基础上,启用NO_ZERO_IN_DATE和NO_ZERO_DATE SQL模式。 如果你不使用严格模式(即不启用STRICT_TRANS_TABLES或STRICT_ALL_TABLES模式),对于非法或丢失的值,MySQL将插入调整后的值并给出警告。在严格模式,你可以通过INSERT IGNORE或UPDATE IGNORE来实现。参见[13.5.4.22节,“SHOW WARNINGS语法”](# "13.5.4.22. SHOW WARNINGS Syntax")。 下面的特殊模式快速组合了前面所列的模式。 其中包括大多数最新版本MySQL中的所有模式值。旧版本中,组合模式不包括新版本中没有的不适用的具体模式值。 ·         ANSI 等同REAL_AS_FLOAT、PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE。参见[1.8.3节,“在ANSI模式下运行MySQL”](# "1.8.3. Running MySQL in ANSI Mode")。 ·         DB2 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS。 ·         MAXDB 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、 NO_AUTO_CREATE_USER。 ·         MSSQL 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、 NO_FIELD_OPTIONS。 ·         MYSQL323 等同NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE。 ·         MYSQL40 等同NO_FIELD_OPTIONS、HIGH_NOT_PRECEDENCE。 ·         ORACLE 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS、NO_AUTO_CREATE_USER。 ·         POSTGRESQL 等同PIPES_AS_CONCAT、ANSI_QUOTES、IGNORE_SPACE、NO_KEY_OPTIONS、NO_TABLE_OPTIONS、NO_FIELD_OPTIONS。 ·         TRADITIONAL 等同STRICT_TRANS_TABLES、STRICT_ALL_TABLES、NO_ZERO_IN_DATE、NO_ZERO_DATE、ERROR_FOR_DIVISION_BY_ZERO、NO_AUTO_CREATE_USER。 ### 5.3.3. 服务器系统变量 [ 5.3.3.1. 动态系统变量](#) 服务器将维护许多表示其配置的系统变量。所有变量均有默认值。可以在命令行中或选项文件设置选项在服务器启动时对它们进行设置。大多数可以在运行时使用SET语句来设置。 **mysqld服务器**维护两种变量。全局变量影响服务器的全局操作。会话变量影响具体客户端连接相关操作。 服务器启动时,将所有全局变量初始化为默认值。可以在选项文件或命令行中指定的选项来更改这些默认值。服务器启动后,通过连接服务器并执行SET GLOBAL *var_name*语句可以更改动态全局变量。要想更改全局变量,必须具有SUPER权限。 服务器还为每个客户端连接维护会话变量。连接时使用相应全局变量的当前值对客户端会话变量进行初始化。客户可以通过SET SESSION *var_name*语句来更改动态会话变量。设置会话变量不需要特殊权限,但客户可以只更改自己的会话变量,而不更改其它客户的会话变量。 任何访问全局变量的客户端都可以看见对全局变量的更改。但是,它只影响在更改后连接的从该全局变量初始化相应会话变量的客户端。它不会影响已经连接上的客户端的会话变量(甚至是执行SET GLOBAL语句的客户端)。 当使用启动选项设置变量时,变量值可以使用后缀K、M或G分别表示千字节、兆字节或gigabytes。例如,下面的命令启动服务器时的键值缓冲区大小为16 megabytes: ~~~ mysqld --key_buffer_size=16M ~~~ 后缀的大小写美关系;16M和16m是同样的。 运行时,使用SET语句来设置系统变量。此时,不能使用后缀,但值可以采取下列表达式: ~~~ mysql> SET sort_buffer_size = 10 * 1024 * 1024; ~~~ 要想显式指定是否设置全局或会话变量,使用GLOBAL或SESSION选项: ~~~ mysql> SET GLOBAL sort_buffer_size = 10 * 1024 * 1024; ~~~ ~~~ mysql> SET SESSION sort_buffer_size = 10 * 1024 * 1024; ~~~ 两个选项均没有,则语句设置会话变量。 [ 5.3.3.1节,“动态系统变量”](# "5.3.3.1. Dynamic System Variables")中列出了可以在运行时设置的变量。 如果你想用SET语句限制系统变量可设的最大值,可以在服务器启动时通过--maximum-*var_name*形式的选项来指定。例如,要想防止query_cache_size的值运行时超过32MB,使用选项--maximum-query_cache_size=32M。 你可以通过SHOW VARIABLES语句查看系统变量及其值。详细信息参见[9.4节,“系统变量”](# "9.4. System Variables")。 ~~~ mysql> SHOW VARIABLES; +---------------------------------+-------------------------------------------+ | Variable_name | Value | +---------------------------------+-------------------------------------------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | | automatic_sp_privileges | ON | | back_log | 50 | | basedir | /home/jon/bin/mysql/ | | binlog_cache_size | 32768 | | bulk_insert_buffer_size | 8388608 | | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /home/jon/bin/mysql/share/mysql/charsets/ | | collation_connection | latin1_swedish_ci | | collation_database | latin1_swedish_ci | | collation_server | latin1_swedish_ci | | completion_type | 0 | | concurrent_insert | 1 | | connect_timeout | 5 | | datadir | /home/jon/bin/mysql/var/ | | date_format | %Y-%m-%d | | datetime_format | %Y-%m-%d %H:%i:%s | | default_week_format | 0 | | delay_key_write | ON | | delayed_insert_limit | 100 | | delayed_insert_timeout | 300 | | delayed_queue_size | 1000 | | div_precision_increment | 4 | | engine_condition_pushdown | OFF | | expire_logs_days | 0 | | flush | OFF | | flush_time | 0 | | ft_boolean_syntax | + -><()~*:""&| | | ft_max_word_len | 84 | | ft_min_word_len | 4 | | ft_query_expansion_limit | 20 | | ft_stopword_file | (built-in) | | group_concat_max_len | 1024 | | have_archive | YES | | have_bdb | NO | | have_blackhole_engine | YES | | have_compress | YES | | have_crypt | YES | | have_csv | YES | | have_example_engine | NO | | have_federated_engine | NO | | have_geometry | YES | | have_innodb | YES | | have_isam | NO | | have_ndbcluster | DISABLED | | have_openssl | NO | | have_partition_engine | YES | | have_query_cache | YES | | have_raid | NO | | have_rtree_keys | YES | | have_symlink | YES | | init_connect | | | init_file | | | init_slave | | | innodb_additional_mem_pool_size | 1048576 | | innodb_autoextend_increment | 8 | | innodb_buffer_pool_awe_mem_mb | 0 | | innodb_buffer_pool_size | 8388608 | | innodb_checksums | ON | | innodb_commit_concurrency | 0 | | innodb_concurrency_tickets | 500 | | innodb_data_file_path | ibdata1:10M:autoextend | | innodb_data_home_dir | | | innodb_doublewrite | ON | | innodb_fast_shutdown | 1 | | innodb_file_io_threads | 4 | | innodb_file_per_table | OFF | | innodb_flush_log_at_trx_commit | 1 | | innodb_flush_method | | | innodb_force_recovery | 0 | | innodb_lock_wait_timeout | 50 | | innodb_locks_unsafe_for_binlog | OFF | | innodb_log_arch_dir | | | innodb_log_archive | OFF | | innodb_log_buffer_size | 1048576 | | innodb_log_file_size | 5242880 | | innodb_log_files_in_group | 2 | | innodb_log_group_home_dir | ./ | | innodb_max_dirty_pages_pct | 90 | | innodb_max_purge_lag | 0 | | innodb_mirrored_log_groups | 1 | | innodb_open_files | 300 | | innodb_support_xa | ON | | innodb_sync_spin_loops | 20 | | innodb_table_locks | ON | | innodb_thread_concurrency | 20 | | innodb_thread_sleep_delay | 10000 | | interactive_timeout | 28800 | | join_buffer_size | 131072 | | key_buffer_size | 8388600 | | key_cache_age_threshold | 300 | | key_cache_block_size | 1024 | | key_cache_division_limit | 100 | | language | /home/jon/bin/mysql/share/mysql/english/ | | large_files_support | ON | | large_page_size | 0 | | large_pages | OFF | | license | GPL | | local_infile | ON | | locked_in_memory | OFF | | log | ON | | log_bin | ON | | log_bin_trust_routine_creators | OFF | | log_error | /home/jon/bin/mysql/var/master1.err | | log_slave_updates | OFF | | log_slow_queries | OFF | | log_warnings | 1 | | long_query_time | 10 | | low_priority_updates | OFF | | lower_case_file_system | OFF | | lower_case_table_names | 0 | | max_allowed_packet | 1048576 | | max_binlog_cache_size | 4294967295 | | max_binlog_size | 1073741824 | | max_connect_errors | 10 | | max_connections | 100 | | max_delayed_threads | 20 | | max_error_count | 64 | | max_heap_table_size | 16777216 | | max_insert_delayed_threads | 20 | | max_join_size | 4294967295 | | max_length_for_sort_data | 1024 | | max_relay_log_size | 0 | | max_seeks_for_key | 4294967295 | | max_sort_length | 1024 | | max_tmp_tables | 32 | | max_user_connections | 0 | | max_write_lock_count | 4294967295 | | multi_range_count | 256 | | myisam_data_pointer_size | 6 | | myisam_max_sort_file_size | 2147483647 | | myisam_recover_options | OFF | | myisam_repair_threads | 1 | | myisam_sort_buffer_size | 8388608 | | ndb_autoincrement_prefetch_sz | 32 | | ndb_cache_check_time | 0 | | ndb_force_send | ON | | ndb_index_stat_cache_entries | 32 | | ndb_index_stat_enable | ON | | ndb_index_stat_update_freq | 20 | | ndb_use_exact_count | ON | | ndb_use_transactions | ON | | net_buffer_length | 16384 | | net_read_timeout | 30 | | net_retry_count | 10 | | net_write_timeout | 60 | | new | OFF | | old_alter_table | OFF | | old_passwords | OFF | | open_files_limit | 1024 | | optimizer_prune_level | 1 | | optimizer_search_depth | 62 | | pid_file | /home/jon/bin/mysql/var/hostname.pid1 | | port | 3306 | | preload_buffer_size | 32768 | | protocol_version | 10 | | query_alloc_block_size | 8192 | | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 0 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | | query_prealloc_size | 8192 | | range_alloc_block_size | 2048 | | read_buffer_size | 131072 | | read_only | OFF | | read_rnd_buffer_size | 262144 | | relay_log_purge | ON | | relay_log_space_limit | 0 | | rpl_recovery_rank | 0 | | secure_auth | OFF | | server_id | 1 | | skip_external_locking | ON | | skip_networking | OFF | | skip_show_database | OFF | | slave_compressed_protocol | OFF | | slave_load_tmpdir | /tmp/ | | slave_net_timeout | 3600 | | slave_skip_errors | OFF | | slave_transaction_retries | 10 | | slow_launch_time | 2 | | socket | /tmp/mysql.sock | | sort_buffer_size | 2097144 | | sql_mode | | | sql_notes | ON | | sql_warnings | ON | | storage_engine | MyISAM | | sync_binlog | 0 | | sync_frm | ON | | sync_replication | 0 | | sync_replication_slave_id | 0 | | sync_replication_timeout | 10 | | system_time_zone | EST | | table_cache | 64 | | table_lock_wait_timeout | 50 | | table_type | MyISAM | | thread_cache_size | 0 | | thread_stack | 196608 | | time_format | %H:%i:%s | | time_zone | SYSTEM | | timed_mutexes | OFF | | tmp_table_size | 33554432 | | tmpdir | | | transaction_alloc_block_size | 8192 | | transaction_prealloc_size | 4096 | | tx_isolation | REPEATABLE-READ | | updatable_views_with_limit | YES | | version | 5.1.2-alpha-log | | version_comment | Source distribution | | version_compile_machine | i686 | | version_compile_os | suse-linux | | wait_timeout | 28800 | +---------------------------------+-------------------------------------------+ 218 rows in set (0.03 sec) ~~~ 此处描述了大多数系统变量。没有版本的变量在所有MySQL 5.1 发布中适用。关于其使用历史信息,请参见*MySQL 5.0参考指南*和*MySQL 4.1参考指南*。InnoDB系统变量列于 [ 15.2.4节,“InnoDB启动选项”](# "15.2.4. InnoDB Startup Options")。 若没有另行规定,缓冲区大小、长度和堆栈大小的单位均为字节。 关于这些变量的调节信息参见[7.5.2节,“调节服务器参数”](# "7.5.2. Tuning Server Parameters")。 ·         auto_increment_increment auto_increment_increment和auto_increment_offset用于主服务器-主服务器(master-to-master)复制,并可以用来控制AUTO_INCREMENT列的操作。两个变量均可以设置为全局或局部变量,并且假定每个值都可以为1到65,535之间的整数值。将其中一个变量设置为0会使该变量为1。如果试图将这些变量设置为大于65,535或小于0的值,则会将该值设置为65,535。如果向将auto_increment_increment或auto_increment_offset设置为非整数值,则会给出错误,并且变量的实际值在这种情况下保持不变。 这两个变量影响AUTO_INCREMENT列的方式: o        auto_increment_increment控制列中的值的增量值。例如: ~~~ o                       mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       | Variable_name            | Value | ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       | auto_increment_increment | 1     | ~~~ ~~~ o                       | auto_increment_offset    | 1     | ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       2 rows in set (0.00 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> CREATE TABLE autoinc1 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY); ~~~ ~~~ o                       Query OK, 0 rows affected (0.04 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> SET @auto_increment_increment=10; ~~~ ~~~ o                       Query OK, 0 rows affected (0.00 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       | Variable_name            | Value | ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       | auto_increment_increment | 10    | ~~~ ~~~ o                       | auto_increment_offset    | 1     | ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       2 rows in set (0.01 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL); ~~~ ~~~ o                       Query OK, 4 rows affected (0.00 sec) ~~~ ~~~ o                       Records: 4  Duplicates: 0  Warnings: 0 ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> SELECT col FROM autoinc1; ~~~ ~~~ o                       +-----+ ~~~ ~~~ o                       | col | ~~~ ~~~ o                       +-----+ ~~~ ~~~ o                       |   1 | ~~~ ~~~ o                       |  11 | ~~~ ~~~ o                       |  21 | ~~~ ~~~ o                       |  31 | ~~~ ~~~ o                       +-----+ ~~~ ~~~ o                       4 rows in set (0.00 sec) ~~~ (注明如何使用SHOW VARIABLES来获取这些变量的当前值)。 o        auto_increment_offset确定AUTO_INCREMENT列值的起点。假定在与前面的例子的相同的会话中执行下面的命令: ~~~ o                       mysql> SET @auto_increment_offset=5; ~~~ ~~~ o                       Query OK, 0 rows affected (0.00 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       | Variable_name            | Value | ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       | auto_increment_increment | 10    | ~~~ ~~~ o                       | auto_increment_offset    | 5     | ~~~ ~~~ o                       +--------------------------+-------+ ~~~ ~~~ o                       2 rows in set (0.00 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> CREATE TABLE autoinc2 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY); ~~~ ~~~ o                       Query OK, 0 rows affected (0.06 sec) ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> INSERT INTO autoinc2 VALUES (NULL), (NULL), (NULL), (NULL); ~~~ ~~~ o                       Query OK, 4 rows affected (0.00 sec) ~~~ ~~~ o                       Records: 4  Duplicates: 0  Warnings: 0 ~~~ ~~~ o                       ~~~ ~~~ o                       mysql> SELECT col FROM autoinc2; ~~~ ~~~ o                       +-----+ ~~~ ~~~ o                       | col | ~~~ ~~~ o                       +-----+ ~~~ ~~~ o                       |   5 | ~~~ ~~~ o                       |  15 | ~~~ ~~~ o                       |  25 | ~~~ ~~~ o                       |  35 | ~~~ ~~~ o                       +-----+ ~~~ ~~~ o                       4 rows in set (0.02 sec) ~~~ ~~~ o                       ~~~ 如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值被忽略。 如果其中一个或两个变量被更改了,然后更改插入到包含AUTO_INCREMENT列的表中的新行,结果可能看上去有问题,由于计算AUTO_INCREMENT系列值时没有考虑列内已经存在的值,并且插入的下一个值是列内最小的值,大于AUTO_INCREMENT列内已有的最大值。换句话说,数值的计算方法为: auto_increment_offset+ * N* * auto_increment_increment 其中*N*为系列内的正整数值[1,2,3,...]。例如: ~~~ mysql> SHOW VARIABLES LIKE 'auto_inc%'; ~~~ ~~~ +--------------------------+-------+ ~~~ ~~~ | Variable_name            | Value | ~~~ ~~~ +--------------------------+-------+ ~~~ ~~~ | auto_increment_increment | 10    | ~~~ ~~~ | auto_increment_offset    | 5     | ~~~ ~~~ +--------------------------+-------+ ~~~ ~~~ 2 rows in set (0.00 sec) ~~~ ~~~   ~~~ ~~~ mysql> SELECT col FROM autoinc1; ~~~ ~~~ +-----+ ~~~ ~~~ | col | ~~~ ~~~ +-----+ ~~~ ~~~ |   1 | ~~~ ~~~ |  11 | ~~~ ~~~ |  21 | ~~~ ~~~ |  31 | ~~~ ~~~ +-----+ ~~~ ~~~ 4 rows in set (0.00 sec) ~~~ ~~~   ~~~ ~~~ mysql> INSERT INTO autoinc1 VALUES (NULL), (NULL), (NULL), (NULL); ~~~ ~~~ Query OK, 4 rows affected (0.00 sec) ~~~ ~~~ Records: 4  Duplicates: 0  Warnings: 0 ~~~ ~~~   ~~~ ~~~ mysql> SELECT col FROM autoinc1; ~~~ ~~~ +-----+ ~~~ ~~~ | col | ~~~ ~~~ +-----+ ~~~ ~~~ |   1 | ~~~ ~~~ |  11 | ~~~ ~~~ |  21 | ~~~ ~~~ |  31 | ~~~ ~~~ |  35 | ~~~ ~~~ |  45 | ~~~ ~~~ |  55 | ~~~ ~~~ |  65 | ~~~ ~~~ +-----+ ~~~ ~~~ 8 rows in set (0.00 sec) ~~~ auto_increment_increment和auto_increment_offset所示的值可以生成系列5 + *N* * 10,即,[5,15,25,35,45,...]。在INSERT前col列内最大的值为31,AUTO_INCREMENT数列的下一个值为35,因此col中插入的值从该点开始,结果如SELECT查询所示。 一定要记住不可能将这两个变量的结果限制到一个表中,因此不会替代其它数据库管理系统提供的序列;这些变量控制MySQL服务器上**all**表AUTO_INCREMENT列的所有行为。如果某个变量设为全局变量,则只有通过局部设置将全局值更改和覆盖后或**mysqld**重启后其作用方可改变;如果局部设置,则新值影响所有表的AUTO_INCREMENT列,在这个会话期间当前用户在这些表中插入了新行,除非在会话期间更改了这些值。 auto_increment_increment的 默认值为1。参见[6.12节,“多服务器复制中的Auto-Increment”](# "6.12. Auto-Increment in Multi-Master Replication")。 ·         auto_increment_offset 该变量的默认值为1。详见auto_increment_increment的描述。 ·         back_log MySQL有的主要连接请求的数量。当主MySQL线程在短时间内得到许多连接请求时发挥作用。主线程需要花一些时间(尽管很少)来检查连接并启动一个新线程。back_log值说明MySQL临时停止响应新请求前在短时间内可以堆起多少请求。如果你需要在短时间内允许大量连接,可以增加该数值。 换句话说,该值为“进”TCP/IP连接帧听队列的大小。操作系统有该队列自己的限制值。本手册中Unix listen()系统调用页应有更详细的信息。该变量最大值请查阅OS文档。企图将back_log设置为高于你的操作系统限值是徒劳无益的。 ·         basedir MySQL安装基准目录。可以用--basedir选项设置该变量。 ·         bdb_cache_size 为BDB表缓存索引和行分配的缓冲区的大小。如果你不使用BDB表,你应用--skip-bdb启动**mysqld**以便不浪费该缓存。 ·         bdb_home BDB表基准目录。应与datadir变量的值相同。 ·         bdb_log_buffer_size 为BDB表缓存索引和行分配的缓冲区的大小。如果你不使用BDB表,你应将该值设置为0或用--skip-bdb启动**mysqld**以便不浪费该缓存。 ·         bdb_logdir BDB存储引擎写它日志文件的目录。可以用--bdb-logdir选项设置该变量。 ·         bdb_max_lock 在BDB表下可以激活的最大锁数(默认为10,000)。如果当你执行长事务或当**mysqld**必须检查许多行来计算查询时出现下面的错误,你应增加该值: ~~~ bdb: Lock table is out of available locks ~~~ ~~~ Got error 12 from ... ~~~ ·         bdb_shared_data 如果你正使用--bdb-shared-data应为ON。 ·         bdb_tmpdir --bdb-tmpdir选项的值。   ·         binlog_cache_size 在事务过程中容纳二进制日志SQL语句的缓存大小。二进制日志缓存是服务器支持事务存储引擎并且服务器启用了二进制日志(--log-bin选项)的前提下为每个客户端分配的内存。如果你经常使用大的,多语句事务,你可以增加该值以获得更有的性能。Binlog_cache_use和Binlog_cache_disk_use状态变量可以用来调整该变量的大小。参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。 ·         bulk_insert_buffer_size MyISAM使用专用树状缓存来使INSERT ... SELECT、INSERT ... VALUES (...)、(...)、 ...和LOAD DATA INFILE的大块插入更快。该变量用每线程的字节数限制缓存树的大小。将它设置为0禁用优化。**注**释:只有向非空表添加数据时才使用该缓存。 默认值是8MB。 ·         character_set_client 来自客户端的语句的字符集。 ·         character_set_connection 用于没有字符集导入符的文字和数字-字符串转换。 ·         character_set_database 默认数据库使用的字符集。当默认数据库更改时,服务器则设置该变量。如果没有默认数据库,变量的值同character_set_server。 ·         character_set_results 用于向客户端返回查询结果的字符集。 ·         character_set_ server 服务器的默认字符集。 ·         character_set_system 服务器用来保存识别符的字符集。该值一定是utf8。 ·         character_sets_dir 字符集安装目录。 ·         collation_connection 连接字符集的校对规则。 ·         collation_database 默认数据库使用的校对规则。当默认数据库改变时服务器则设置该变量。如果没有默认数据库,变量的值同collation_server。 ·         collation_server 服务器的默认校对规则。 ·         completion_type 事务结束类型: o        如果该值为0(默认),COMMIT和ROLLBACK不受影响。 o        如果该值为1,COMMIT和ROLLBACK分别等同于COMMIT AND CHAIN和ROLLBACK AND CHAIN。(新事务用刚刚结束的事务相同的间隔等级立即启动)。 o        如果该值为2,COMMIT和ROLLBACK分别等同于COMM它RELEASE和ROLLBACK RELEASE。(事务终止后,服务器断开)。 ·         concurrent_insert 如果为ON(默认值),MySQL允许INSERT和SELECT语句在中间没有空数据块的MyISAM表中并行运行。你可以用--safe或--skip-new启动**mysqld**关闭该选项。 该变量为整数,有3个值: <table border="1" cellpadding="0" id="table4"><tr><td width="44" style="width:33.35pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>值</span></strong></p></td> <td width="866" style="width:649.85pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>描述</span></strong></p></td> </tr><tr><td width="44" style="width:33.35pt;padding:.75pt .75pt .75pt .75pt"> <p><span>0</span></p></td> <td width="866" style="width:649.85pt;padding:.75pt .75pt .75pt .75pt"> <p>关</p></td> </tr><tr><td width="44" style="width:33.35pt;padding:.75pt .75pt .75pt .75pt"> <p><span>1</span></p></td> <td width="866" style="width:649.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>(</span>默认<span>)</span>在没有空数据块的<span>MyISAM</span>表中启用并行插入</p></td> </tr><tr><td width="44" style="width:33.35pt;padding:.75pt .75pt .75pt .75pt"> <p><span>2</span></p></td> <td width="866" style="width:649.85pt;padding:.75pt .75pt .75pt .75pt"> <p>为所有<span>MyISAM</span>表启用并行插入。如果表有空记录或正被另一线程使用,新行将插入到表的最后。如果表未使用,<span>MySQL</span>将进行普通读锁定并将新行插入空记录。</p></td> </tr></table> ·         connect_timeout **mysqld服务器**用Bad handshake响应前等待连接包的秒数。 ·         datadir MySQL数据目录。可以用--datadir选项设置该变量。 ·         date_format 该变量未使用。 ·         datetime_format 该变量未使用。 ·         default_week_format WEEK()函数使用的默认模式。 ·         delay_key_write 该选项只适用MyISAM表。它具有下述值可以影响CREATE TABLE语句使用的DELAY_KEY_WRITE表选项的处理。 <table border="1" cellpadding="0" id="table5"><tr><td> <p><strong><span>选项</span></strong></p></td> <td> <p><strong><span>描述</span></strong></p></td> </tr><tr><td> <p> <span>OFF</span></p></td> <td> <p> <span>DELAY_KEY_WRITE</span>被忽略。</p></td> </tr><tr><td> <p> <span>ON</span></p></td> <td> <p><span>MySQL</span>在<span>CREATE TABLE</span>中用<span>DELAY_KEY_WRITE</span>选项。这是 默认值。</p></td> </tr><tr><td> <p> <span>ALL</span></p></td> <td> <p>用启用<span>DELAY_KEY_WRITE</span>选项创建表的相同方法对所有新打开表的进行处理。</p></td> </tr></table> 如果启用了DELAY_KEY_WRITE,说明使用该项的表的键缓冲区在每次更新索引时不被清空,只有关闭表时才清空。遮掩盖可以大大加快键的写操作,但如果你使用该特性,你应用--myisam-recover选项启动服务器,为所有MyISAM表添加自动检查(例如,--myisam-recover=BACKUP,FORCE)。参见[5.3.1节,“**mysqld**命令行选项”](# "5.3.1. mysqld Command-Line Options")和[15.1.1节,“MyISAM启动选项”](# "15.1.1. MyISAM Startup Options")。 请注意--external-locking不为使用延迟键写入的表提供索引破坏保护。 ·         delayed_insert_limit 插入delayed_insert_limit延迟行后,INSERT DELAYED处理器线程检查是否有挂起的SELECT语句。如果有,在继续插入延迟的行之前,允许它们先执行。 ·         delayed_insert_timeout INSERT DELAYED处理器线程终止前应等待INSERT语句的时间。 ·         delayed_queue_size 这是各个表中处理INSERT DELAYED语句时队列中行的数量限制。如果队列满了,执行INSERT DELAYED语句的客户端应等待直到队列内再有空间。 ·         div_precision_increment 该变量说明用/操作符执行除操作的结果可增加的精确度的位数。 默认值是4。最小和最大值分别为0和30。下面的示例说明了增加 默认值的结果。 ~~~ mysql> SELECT 1/7; ~~~ ~~~ +--------+ ~~~ ~~~ | 1/7    | ~~~ ~~~ +--------+ ~~~ ~~~ | 0.1429 | ~~~ ~~~ +--------+ ~~~ ~~~ mysql> SET div_precision_increment = 12; ~~~ ~~~ mysql> SELECT 1/7; ~~~ ~~~ +----------------+ ~~~ ~~~ | 1/7            | ~~~ ~~~ +----------------+ ~~~ ~~~ | 0.142857142857 | ~~~ ~~~ +----------------+ ~~~ ·         engine_condition_pushdown 该变量适用于NDB。默认值为0(OFF):如果你执行类似查询SELECT * FROM t WHERE mycol = 42,其中mycol为没有索引的列,当满了的表扫描每个NDB节点时,执行该查询。每个节点使用WHERE条件将每一行发送给MySQL服务器。如果engine_condition_pushdown被设置为1(ON),该条件“pushed down”给存储引擎并发送给NDB节点。每个节点都执行扫描,并只向MySQL服务器发送回匹配条件的行。 ·         expire_logs_days 二进制日志自动删除的天数。默认值为0,表示“没有自动删除”。启动时和二进制日志循环时可能删除。 ·         flush 如果用--flush选项启动**mysqld**该值为ON。 ·         flush_time 如果设为非零值,每隔flush_time秒则关闭所有表以释放硬盘资源并同步未清空的数据。我们建议只在Windows 9x或Me,或有最小资源的系统中使用该选项。 ·         ft_boolean_syntax 使用IN BOOLEAN MODE执行的布尔全文搜索支持的操作符系列。参见[12.7.1节,“布尔全文搜索”](# "12.7.1. Boolean Full-Text Searches")。 默认变量值为 '+ -><()~*:""&|'。更改这些值的规则是: o        操作符函数由其在字符串内的位置决定。 o        替换值必须是14个字符。 o        每个字符必须为ASCII码非文字数字字符。 o        第1个或第2个字符必须为空格。 o        除非语句在第11个字符和第12个字符处引用了操作符,否则不允许复制。这两个字符可以不相同,但这是唯一可能的两个。 o        位置10、13和14(默认设置为‘:’、‘&’和‘|’)保留用于将来扩展。 ·         ft_max_word_len FULLTEXT索引中所包含的字的最大长度。 **注**释:更改该变量后必须重建FULLTEXT索引。应使用REPAIR TABLE *tbl_name* QUICK。 ·         ft_min_word_len FULLTEXT索引中所包含的字的最小长度。 **注**释:更改该变量后必须重建FULLTEXT索引。应使用REPAIR TABLE *tbl_name* QUICK。 ·         ft_query_expansion_limit 使用WITH QUERY EXPANSION进行全文搜索的最大匹配数。 ·         ft_stopword_file 用于读取全文搜索的停止字清单的文件。该文件中的所有字都会用到;注释不重要。默认情况下,使用内嵌式停止字清单(如myisam/ft_static.c文件中所定义)。将该变量设置为空字符串('')则禁用停止字过滤。 **注**释:更改该变量或停止字文件的内容后必须重建FULLTEXT索引。应使用REPAIR TABLE *tbl_name* QUICK。 ·         group_concat_max_len 允许的GROUP_CONCAT()函数结果的最大长度。 ·         have_archive 如果**mysqld**支持ARCHIVE表则为YES,否则为NO。 ·         have_bdb 如果**mysqld**支持BDB表则为YES。如果使用--skip-bdb则为DISABLED。 ·         have_blackhole_engine 如果**mysqld**支持BLACKHOLE表则为YES,否则为NO。 ·         have_compress 是否zlib压缩库适合该服务器。如果不适合,不能使用COMPRESS()和UNCOMPRESS()函数。 ·         have_crypt 是否crypt()系统调用适合该服务器。如果不适合,不能使用CRYPT()函数。 ·         have_csv 如果**mysqld**支持ARCHIVE表则为YES,否则为NO。 ·         have_example_engine 如果**mysqld**支持EXAMPLE表则为YES,否则为NO。 have_federated_engine 如果**mysqld**支持FEDERATED表则为YES,否则为NO。 ·         have_geometry 是否服务器支持空间数据类型。 ·         have_innodb 如果**mysqld**支持InnoDB表则为YES。如果使用--skip-innodb则为DISABLED。 ·         have_isam 在MySQL 5.1中,只是为了向后兼容显示该值,并且总是NO,因为不再支持ISAM表。 ·         have_ndbcluster 如果**mysqld**支持NDB CLUSTER表则为YES。如果使用了--skip-ndbcluster则为DISABLED。 ·         have_partition_engine 如果**mysqld**支持分区则为YES。在MySQL 5.1.1中加入。 ·         have_openssl 如果**mysqld**支持客户端/服务器协议的SSL(加密)则为YES。 ·         have_query_cache 如果**mysqld**支持查询缓存则为YES。 ·         have_raid 如果**mysqld**支持RAID选项则为YES。 ·         have_rtree_keys RTREE索引是否可用。(用于MyISAM表的空间索引)。 ·         have_symlink 是否启用符号链接支持。在Unix中需要用于支持DATA DIRECTORY和INDEX DIRECTORY表选项。 ·         init_connect 服务器为每个连接的客户端执行的字符串。字符串由一个或多个SQL语句组成。要想指定多个语句,用分号间隔开。例如,每个客户端开始时默认启用autocommit模式。没有全局服务器变量可以规定autocommit默认情况下应禁用,但可以用init_connect来获得相同的效果: ~~~ SET GLOBAL init_connect='SET AUTOCOMMIT=0'; ~~~ 还可以在命令行或选项文件中设置该变量。要想使用选项文件设置变量,应包括下述行: ~~~ [mysqld] ~~~ ~~~ init_connect='SET AUTOCOMMIT=0' ~~~ 请注意init_connect的内容并不为拥有SUPER权限的用户执行;实际是内容设置错误(包含错误查询,例如语法错误),这样使所有连接失败。不为SUPER用户执行,使SUPER用户可以打开连接并固定init_connect。 ·         init_file 启动服务器时用--init-file选项指定的文件名。文件中包含服务器启动时要执行的SQL语句。每个语句必须在同一行中并且不能包括注释。 ·         init_slave 该变量类似init_connect,但是每次SQL线程启动时从服务器应执行该字符串。该字符串的格式与init_connect变量相同。 ·         innodb_*xxx* InnoDB系统变量列入[15.2.4节,“InnoDB启动选项”](# "15.2.4. InnoDB Startup Options")。 ·         interactive_timeout 服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。又见wait_timeout。 ·         join_buffer_size 用于完全联接的缓冲区的大小(当不使用索引的时候使用联接操作)。一般情况获得快速联接的最好方法是添加索引。当增加索引时不可能通过增加join_buffer_size值来获得快速完全联接。将为两个表之间的每个完全联接分配联接缓冲区。对于多个表之间不使用索引的复杂联接,需要多联接缓冲区。 ·         key_buffer_size MyISAM表的索引块分配了缓冲区,由所有线程共享。key_buffer_size是索引块缓冲区的大小。键值缓冲区即为键值缓存。 key_buffer_size的最大允许设定值为4GB。有效最大值可以更小,取决于可用物理RAM和操作系统或硬件平台强加的每个进程的RAM限制。 增加该值,达到你可以提供的更好的索引处理(所有读和多个写操作)。通常为主要运行MySQL的机器内存的25%。但是,如果你将该值设得过大(例如,大于总内存的50%),系统将转换为页并变得极慢。MySQL依赖操作系统来执行数据读取时的文件系统缓存,因此你必须为文件系统缓存留一些空间。 同时写多行时要想速度更快,应使用LOCK TABLES。参见[13.4.5节,“LOCK TABLES和UNLOCK TABLES语法”](# "13.4.5. LOCK TABLES and UNLOCK TABLES Syntax")。 你可以通过执行SHOW STATUS语句并检查Key_read_requests、Key_reads、Key_write_requests和Key_writes状态变量来检查键值缓冲区的性能。参见[13.5.4节,“SHOW语法”](# "13.5.4. SHOW Syntax")。 Key_reads/Key_read_requests比例一般应小于0.01。如果你使用更新和删除,Key_writes/Key_write_requests比例通常接近1,但如果你更新时会同时影响到多行或如果你正使用DELAY_KEY_WRITE表选项,可能小得多。 用key_buffer_size结合Key_blocks_unused状态变量和缓冲区块大小,可以确定使用的键值缓冲区的比例。从key_cache_block_size服务器变量可以获得缓冲区块大小。使用的缓冲区的比例为: ~~~ 1 - ((Key_blocks_unused * key_cache_block_size) / key_buffer_size) ~~~ 该值为约数,因为键值缓冲区的部分空间被分配用作内部管理结构。 可以创建多个MyISAM键值缓存。4GB限制可以适合每个缓存,而不是一个组。参见[7.4.6节,“MyISAM键高速缓冲”](# "7.4.6. The MyISAM Key Cache")。 ·         key_cache_age_threshold 该值控制将缓冲区从键值缓存热子链(sub-chain)降级到温子链(sub-chain)。如果值更低,则降级更快。最小值为100。 默认值是300。参见[7.4.6节,“MyISAM键高速缓冲”](# "7.4.6. The MyISAM Key Cache")。 ·         key_cache_block_size 键值缓存内块的字节大小。默认值是1024。参见[7.4.6节,“MyISAM键高速缓冲”](# "7.4.6. The MyISAM Key Cache")。 ·         key_cache_division_limit 键值缓存缓冲区链热子链和温子链的划分点。该值为缓冲区链用于温子链的百分比。允许的值的范围为1到100。 默认值是100。参见[7.4.6节,“MyISAM键高速缓冲”](# "7.4.6. The MyISAM Key Cache")。 ·         language 错误消息所用语言。 ·          large_file_support **mysqld**编译时是否使用了大文件支持选项。 ·         large_pages 说明是否启用了大页面支持。 ·         license 服务器的许可类型。 ·         local_infile 是否LOCAL支持LOAD DATA INFILE语句。 ·         locked_in_memory 是否用–memlock将**mysqld**锁在内存中。 ·         log 是否启用将所有查询记录到常规查询日志中。参见[5.11.2节,“通用查询日志”](# "5.11.2. The General Query Log")。 ·         log_bin 是否启用二进制日志。参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。 ·         log_bin_trust_routine_creators 若启用了二进制记录,则该变量适用。它控制是否可以信任保存的程序的作者不会创建向二进制日志写入不安全事件的程序。如果设置为0(默认情况),不允许用户创建或修改保存的程序,除非他们不仅拥有CREATE ROUTINE或ALTER ROUTINE权限还拥有SUPER权限。 设置为0还强制限制,程序必须用DETERMINISTIC特征或用READS SQL DATA或NO SQL特征声明。如果变量设置为1,MySQL不对保存程序的创建强加限制。 参见[20.4节,“存储子程序和触发程序的二进制日志功能”](# "20.4. Binary Logging of Stored Routines and Triggers")。 ·         log_error 错误日志的位置。 ·         log_slave_updates 是否从服务器从主服务器收到的更新应记入从服务器自己的二进制日志。要想生效,必须启用从服务器的二进制记录。参见[6.8节,“复制启动选项”](# "6.8. Replication Startup Options")。 ·         log_slow_queries 是否记录慢查询。用long_query_time变量的值来确定“慢查询”。参见[5.11.4节,“慢速查询日志”](# "5.11.4. The Slow Query Log")。 ·         log_warnings 是否产生其它警告消息。默认情况下启用。放弃的连接不记入错误日志,除非值大于1。 ·         long_query_time 如果查询时间超过该值,则增加Slow_queries状态变量。如果你正使用--log-slow-queries选项,则查询记入慢查询日志文件。用实际时间测量该值,而不是CPU时间,因此低于轻负载系统阈值的查询可能超过重负载系统的阈值。参见[5.11.4节,“慢速查询日志”](# "5.11.4. The Slow Query Log")。 ·         low_priority_updates 如果设置为1,所有INSERT、UPDATE、DELETE和LOCK TABLE WRITE语句将等待直到受影响的表没有挂起的SELECT或LOCK TABLE READ。该变量以前叫做sql_low_priority_updates。 ·         lower_case_file_system 该变量说明是否数据目录所在的文件系统对文件名的大小写敏感。ON说明对文件名的大小写不敏感,OFF表示敏感。 ·           lower_case_table_names 如果设置为1,表名用小写保存到硬盘上,并且表名比较时不对大小写敏感。如果设置为2,按照指定的保存表名,但按照小写来比较。该选项还适合数据库名和表的别名。参见[9.2.2节,“识别符大小写敏感性”](# "9.2.2. Identifier Case Sensitivity")。 如果你正使用InnoDB表,你应在所有平台上将该变量设置为1,强制将名字转换为小写。 如果运行MySQL的系统对文件名的大小写不敏感(例如Windows或Mac OS X),你不应将该变量设置为0。如果启动时没有设置该变量,并且数据目录所在文件系统对文件名的大小写不敏感,MySQL自动将lower_case_table_names设置为2。 ·         max_allowed_packet 包或任何生成的/中间字符串的最大大小。 包消息缓冲区初始化为net_buffer_length字节,但需要时可以增长到max_allowed_packet字节。该值默认很小,以捕获大的(可能是错误的)数据包。 如果你使用大的BLOB列或长字符串,你必须增加该值。应同你想要使用的最大的BLOB一样大。max_allowed_packet的协议限制为1GB。 ·         max_binlog_cache_size 如果多语句事务需要更大的内存,你会得到错误Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage。 ·         max_binlog_size 如果二进制日志写入的内容超出给定值,日志就会发生滚动。你不能将该变量设置为大于1GB或小于4096字节。 默认值是1GB。 请注意如果你正使用事务:事务以一个块写入二进制日志,因此不不能被几个二进制日志拆分。因此,如果你有大的事务,二进制日志可能会大于max_binlog_size。 如果max_relay_log_size为0, max_binlog_size的值也适用于中继日志。 ·         max_connect_errors 如果中断的与主机的连接超过该数目,该主机则阻塞后面的连接。你可以用 FLUSH HOSTS语句解锁锁定的主机。 ·         max_connections 允许的并行客户端连接数目。增大该值则增加**mysqld**需要的文件描述符的数量。关于文件描述符限制的注释参见[7.4.9节,“MySQL如何打开和关闭表”](# "7.4.9. How MySQL Opens and Closes Tables")。还可参见[A.2.6节,“连接数过多”](# "A.2.6. Too many connections")。 ·         max_delayed_threads 不要启动大于该数目的线程来处理INSERT DELAYED语句。如果所有INSERT DELAYED线程已经在使用,你想在新表中插入数据,行 插入时好像未指定DELAYED属性。如果你将该值设置为0,MySQL不会创建线程来处理DELAYED行;其结果是完全禁用了DELAYED。 ·         max_error_count 保存由SHOW ERRORS或SHOW WARNINGS显示的错误、警告和注解的最大数目。 ·         max_heap_table_size 该变量设置MEMORY (HEAP)表可以增长到的最大空间大小。该变量用来计算MEMORY表的MAX_ROWS值。在已有的MEMORY表上设置该变量没有效果,除非用CREATE TABLE或TRUNCATE TABLE等语句重新创建表。 ·         max_insert_delayed_threads 该变量为max_delayed_threads的同义词。 ·         max_join_size 不允许可能需要检查多于max_join_size行(为单个表语句)或行组合(为多个表语句)或可能执行大于max_join_size次硬盘查询的SELECT语句。通过设置该值,你可以捕获键使用不正确并可能花很长时间的SELECT语句。如果用户想要执行没有WHERE子句的花较长时间或返回数百万行的联接,则设置它。 将该变量设置为DEFAULT之外的值,将SQL_BIG_SELECTS的值重设为0。如果你重新设置SQL_BIG_SELECTS值,max_join_size变量被忽略。 如果查询结果位于查询缓存中,则不检查结果大小,因为前面已经计算了结果,不会要求服务器将它发送给客户端。 该变量以前叫做sql_max_join_size。 ·         max_length_for_sort_data 确定使用的filesort算法的索引值大小的限值。参见[7.2.12节,“MySQL如何优化ORDER BY``”](# "7.2.12. How MySQL Optimizes ORDER BY")。 ·         max_relay_log_size 如果复制从服务器写入中继日志时超出给定值,则滚动中继日志。通过该变量你可以对中继日志和二进制日志设置不同的限制。但是,将该变量设置为0,MySQL可以对二进制日志和中继日志使用max_binlog_size。max_relay_log_size必须设置在4096字节和1GB(包括)之间,或为0。 默认值是0。参见[6.3节,“复制实施细节”](# "6.3. Replication Implementation Details")。 ·         max_seeks_for_key 限制根据键值寻找行时的最大搜索数。MySQL优化器假定当用扫描键在表内搜索匹配的行时,不需要超过该数量的键值搜索,而不管键的实际基数是什么(参见[13.5.4.11节,“SHOW INDEX语法”](# "13.5.4.11. SHOW INDEX Syntax"))。将该值设置为较低的值(100?),你可以强制MySQL选择键值而不选择表扫描。 ·         max_sort_length 当排序BLOB或TEXT值时使用的字节数。只使用每个值的前max_sort_length字节;其它的被忽略。 ·         max_tmp_tables 客户端可以同时打开的临时表的最大数。(但该选项还未生效)。 ·         max_user_connections 任何给定的MySQL账户允许的最大同时连接数。0值表示“没有限制”。 该变量具有全局范围和(只读)会话范围。会话变量的的值与全局变量的值相同,除非当前账户具有非零MAX_USER_CONNECTIONS资源限制。在这种情况下,会话值反应了账户限制。 ·         max_write_lock_count 超过写锁定限制后,允许部分读锁定。 ·         myisam_data_pointer_size 默认指针大小,单位是字节,当未指定MAX_ROWS选项时,CREATE TABLE使用该变量创建MyISAM表。该变量不能小于2或大于7。 默认值是6。参见[A.2.11节,“表已满”](# "A.2.11. The table is full")。 ·         (*DEPRECATED*) myisam_max_extra_sort_file_size **注**释:MySQL 5.1不支持该变量。详细信息参见*MySQL 5.0 参考手册*。 ·         myisam_max_sort_file_size 重建MyISAM索引(在REPAIR TABLE、ALTER TABLE或LOAD DATA INFILE过程中)时,允许MySQL使用的临时文件的最大空间大小。如果文件的大小超过该值,则使用键值缓存创建索引,要慢得多。该值的单位为字节。 ·         myisam_recover_options --myisam-recover选项的值。 ·         myisam_repair_threads 如果该值大于1,在Repair by sorting过程中并行创建MyISAM表索引(每个索引在自己的线程内)。 默认值是1。**注**释:多线程维护仍然是*alpha*编码。 ·         myisam_sort_buffer_size 当在REPAIR TABLE或用CREATE INDEX创建索引或ALTER TABLE过程中排序 MyISAM索引分配的缓冲区。 ·         myisam_stats_method 当为MyISAM表搜集关于索引值分发的统计信息时服务器如何处理NULL值。该变量有两个可能的值,nulls_equal和nulls_unequal。对于nulls_equal,认为所有NULL索引值时相等的,并形成一个数值组,其空间大小等于NULL值的数。对于nulls_unequal,NULL值认为是不相等的,每个NULL形成一个数值组,大小为1。 方法用于生成表统计信息,影响优化器如何选择索引来执行查询,详细描述见[7.4.7节,“MyISAM索引统计集合”](# "7.4.7. MyISAM Index Statistics Collection")。 ·         multi_read_range 指定范围选择过程中发送到存储引擎的范围的最大值。默认值是256。向引擎发送多个范围可以大大改进某些选择的性能,特别是对NDBCLUSTER。该引擎需要向所有节点发送范围请求,同时发送许多请求可以大大降低通信成本。 ·         named_pipe (只适用Windows)说明服务器是否支持命名管道连接。 ·         net_buffer_length 在查询之间将通信缓冲区重设为该值。一般情况不应改变,但如果内存很小,可以将它设置为期望的客户端发送的SQL语句的长度。如果语句超出该长度,缓冲区自动扩大,直到max_allowed_packet字节。 ·         net_read_timeout 中断读前等待连接的其它数据的秒数。当服务器从客户端读数时,net_read_timeout指控制何时中断的超时值。当服务器向客户端写时,net_write_timeout指控制何时中断的超时值。又见slave_net_timeout。 ·         net_retry_count 如果某个通信端口的读操作中断了,在放弃前重试多次。在FreeBSD中该值应设得很高,因为内部中断将发送至所有线程。 ·         net_write_timeout 中断写之前等待块写入连接的秒数。又见net_read_timeout。 ·         new 在MySQL 4.0中使用该变量来打开4.1中的一些行为,并用于向后兼容性。在MySQL 5.1中,它的值一直是OFF. ·         old_passwords 是否服务器应为MySQL用户账户使用pre-4.1-style密码。参见[A.2.3节,“客户端不支持鉴定协议”](# "A.2.3. Client does not support authentication protocol")。 ·         one_shot 这不是一个变量,但当设置变量是可以使用它。其描述见[13.5.3节,“SET语法”](# "13.5.3. SET Syntax")。 ·         one_shot 这不是一个变量,但当设置变量是可以使用它。其描述见[13.5.3节,“SET语法”](# "13.5.3. SET Syntax")。 ·         open_files_limit 操作系统允许**mysqld**打开的文件的数量。这是系统允许的实际值,可能与你在启动选项中赋给**mysqld**的值不同。若在系统中MySQL不能更改打开的文件的数量,则该值为0。 ·         optimizer_prune_level 在查询优化从优化器搜索空间裁减低希望局部计划中使用的控制方法。0值禁用该方法,以便优化器进行穷举搜索。值为1使优化器根据中间方案中得出的行数来裁减方案。 ·         optimizer_search_depth 查询优化器进行的搜索的最大深度。如果值大于查询中的关系数则查询方案比较佳,但生成查询执行方案需要的时间更长。值大于查询中的关系数则返回的执行方案更快,但方案远没有优化。如果设置为0, 系统自动选择合理的值。如果设置为查询中使用的表的最大数加2,优化器转换为MySQL 5.0.0(和以前的版本)中使用的算法并搜索。 ·         pid_file 进程ID (PID)文件的路径名。可以用--pid-file选项设置该变量。 ·         plugin_dir 插件目录的路径。在MySQL 5.1.2中加入了该变量。 ·         port 服务器帧听TCP/IP连接所用端口。可以用--port选项设置该变量。 ·         preload_buffer_size 重载索引时分配的缓冲区大小。 ·         protocol_version MySQL服务器使用的客户端/服务器协议的版本。 ·         query_alloc_block_size 为查询分析和执行过程中创建的对象分配的内存块大小。如果内存分段过程中遇到问题,将该变量增加一位会有帮助。 ·         query_cache_limit 不要缓存大于该值的结果。默认值是1048576(1MB)。 ·         query_cache_min_res_unit 查询缓存分配的最小块的大小(字节)。 默认值是4096(4KB)。关于该变量的调节信息参见[5.13.3节,“查询高速缓冲配置”](# "5.13.3. Query Cache Configuration")。 ·         query_cache_size 为缓存查询结果分配的内存的数量。默认值是0,即禁用查询缓存。请注意即使query_cache_type设置为0也将分配此数量的内存。详细信息参见[5.13.3节,“查询高速缓冲配置”](# "5.13.3. Query Cache Configuration")。 ·         query_cache_type 设置查询缓存类型。设置GLOBAL值可以设置后面的所有客户端连接的类型。客户端可以设置SESSION值以影响他们自己对查询缓存的使用。下面的表显示了可能的值: <table border="1" cellpadding="0" id="table6"><tr><td> <p><strong><span>选项</span></strong></p></td> <td> <p><strong><span>描述</span></strong></p></td> </tr><tr><td> <p> <span>0</span>或<span>OFF</span></p></td> <td> <p>不要缓存或查询结果。请注意这样不会取消分配的查询缓存区。要想取消,你应将<span>query_cache_size</span>设置为<span>0</span>。</p></td> </tr><tr><td> <p> <span>1</span>或<span>ON</span></p></td> <td> <p>缓存除了以<span>SELECT SQL_NO_CACHE</span>开头的所有查询结果。</p></td> </tr><tr><td> <p> <span>2</span>或<span>DEMAND</span></p></td> <td> <p>只缓存以<span>SELECT SQL_NO_CACHE</span>开头的查询结果。</p></td> </tr></table> 该变量默认设为ON。 ·         query_cache_wlock_invalidate 一般情况,当客户端对MyISAM表进行WRITE锁定时,如果查询结果位于查询缓存中,则其它客户端未被锁定,可以对该表进行查询。将该变量设置为1,则可以对表进行WRITE锁定,使查询缓存内所有对该表进行的查询变得非法。这样当锁定生效时,可以强制其它试图访问表的客户端来等待。 ·         query_prealloc_size 用于查询分析和执行的固定缓冲区的大小。在查询之间该缓冲区不释放。如果你执行复杂查询,分配更大的query_prealloc_size值可以帮助提高性能,因为它可以降低查询过程中服务器分配内存的需求。 ·         range_alloc_block_size 范围优化时分配的块的大小。 ·         read_buffer_size 每个线程连续扫描时为扫描的每个表分配的缓冲区的大小(字节)。如果进行多次连续扫描,可能需要增加该值, 默认值为131072。 ·         read_only 当变量对复制从服务器设置为ON时,从服务器不允许更新,除非通过从服务器的线程或用户拥有SUPER权限。可以确保从服务器不接受客户端的更新命令。 ·         relay_log_purge 当不再需要中继日志时禁用或启用自动清空中继日志。默认值是1(启用)。 ·         read_rnd_buffer_size 当排序后按排序后的顺序读取行时,则通过该缓冲区读取行,避免搜索硬盘。将该变量设置为较大的值可以大大改进ORDER BY的性能。但是,这是为每个客户端分配的缓冲区,因此你不应将全局变量设置为较大的值。相反,只为需要运行大查询的客户端更改会话变量。 ·         secure_auth 如果用--secure-auth选项启动了MySQL服务器,它将阻塞有旧格式(4.1之前)密码的所有账户所发起的连接。在这种情况下,该变量的值为ON,否则为OFF。 如果你想要防止使用旧格式的密码(致使网络通信不安全),你应启用该选项。 如果启用该选项并且授权表为pre-4.1格式,服务器启动失败并且会出现错误。参见[A.2.3节,“客户端不支持鉴定协议”](# "A.2.3. Client does not support authentication protocol")。 当用于客户端选项时,如果服务器需要该客户端账户的旧格式的密码,则客户端拒绝连接该服务器。 ·         server_id --server-id选项的值。用于主复制服务器和从复制服务器。 ·         shared_memory (只用于Windows)服务器是否允许共享内存连接。 ·         shared_memory_base_name (只用于Windows)说明服务器是否允许共享内存连接,并为共享内存设置识别符。当在单台机器上运行多个MySQL实例时很有用。 ·         skip_external_locking 如果**mysqld**使用外部锁定,该值为OFF。 ·         skip_networking 如果服务器只允许本地(非TCP/IP)连接,该值为ON。在Unix中,本地连接使用Unix套接字文件。在Windows中,本地连接使用命名管道或共享内存。在NetWare中,只支持TCP/IP连接,因此不要将该变量设置为ON。 ·         skip_show_database 防止不具有SHOW DATABASES权限的人们使用SHOW DATABASES语句。如果你担心用户能够看见属于其它用户的数据库,这样设置可以提高安全性。其效果取决于SHOW DATABASES权限:如果变量值为ON,只允许具有SHOW DATABASES权限的人们使用SHOW DATABASES 语句,并且该语句将显示所有数据库名。如果值为OFF,允许所有用户执行SHOW DATABASES,但只显示用户具有SHOW DATABASES或其它权限的数据库的名称。 ·         slave_compressed_protocol 如果主、从服务器均支持,确定是否使用从/主压缩协议。 ·         slave_load_tmpdir 从服务器为复制LOAD DATA INFILE语句创建临时文件的目录名。 ·         slave_net_timeout 放弃读操作前等待主/从连接的更多数据的等待秒数。 ·         slave_skip_errors 从服务器应跳过(忽视)的复制错误。 ·         slave_transaction_retries 如果由于ofInnoDB死锁或超过InnoDB的innodb_lock_wait_timeout或NDBCLUSTER的TransactionDeadlockDetectionTimeout或TransactionInactiveTimeout,复制从服务器SQL线程未能执行事务,在提示错误并停止前它自动重复slave_transaction_retries次。 默认值是10。 ·         slow_launch_time 如果创建线程的时间超过该秒数,服务器增加Slow_launch_threads状态变量。 ·         socket *Unix平台*:用于本地客户端连接的套接字文件。默认为/var/lib/mysql/mysql.sock。 *Windows*:用于本地客户端连接的命名管道名。默认为mysql。 ·         sort_buffer_size 每个排序线程分配的缓冲区的大小。增加该值可以加快ORDER BY或GROUP BY操作。参见[A.4.4节,“MySQL将临时文件储存在哪里”](# "A.4.4. Where MySQL Stores Temporary Files")。 ·         sql_mode 当前的服务器SQL模式,可以动态设置。参见[5.3.2节,“SQL服务器模式”](# "5.3.2. The Server SQL Mode")。 ·         sql_slave_skip_counter 从服务器应跳过的来自主服务器的事件数。 ·         storage_engine 该变量是table_typeis的同义词。在MySQL 5.1中,首选storage_engine。 ·         sync_binlog 如果为正,当每个sync_binlog'th写入该二进制日志后,MySQL服务器将它的二进制日志同步到硬盘上(fdatasync())。请注意如果在autocommit模式,每执行一个语句向二进制日志写入一次,否则每个事务写入一次。 默认值是0,不与硬盘同步。值为1是最安全的选择,因为崩溃时,你最多丢掉二进制日志中的一个语句/事务;但是,这是最慢的选择(除非硬盘有电池备份缓存,从而使同步工作较快)。 ·         sync_frm 如果该变量设为1,当创建非临时表时它的.frm文件被同步到硬盘上(fdatasync());这样较慢但出现崩溃时较安全。 默认值为1。 ·         system_time_zone 服务器系统时区。当 服务器开始执行时,它继承机器默认时区设置值,可以由运行服务器的账户或在启动脚本中进行修改。该值用来设置system_time_zone。典型情况用TZ环境变量来指定时区。还可以用**mysqld_safe**脚本的--timez选项来指定。 ·         table_cache 所有线程打开的表的数目。增大该值可以增加**mysqld**需要的文件描述符的数量。你可以检查Opened_tables状态变量来检查你是否需要增加表缓存。参见[5.3.4节,“服务器状态变量”](# "5.3.4. Server Status Variables")。如果Opened_tables值较大,并且多次执行FLUSH TABLES(只是强制关闭所有表并重新),则应增加table_cache变量的值。 关于表缓存的详细信息,参见[7.4.9节,“MySQL如何打开和关闭表”](# "7.4.9. How MySQL Opens and Closes Tables")。 ·         table_type 默认表类型(存储引擎)。要想在服务器启动时设置表类型,使用--default-table-type选项。参见[5.3.1节,“**mysqld**命令行选项”](# "5.3.1. mysqld Command-Line Options")。 ·         thread_cache_size 服务器应缓存多少线程以便重新使用。当客户端断开连接时,如果线程少于thread_cache_size,则客户端的线程被放入缓存。当请求线程时如果允许可以从缓存中重新利用线程,并且只有当缓存空了时才会创建新线程。如果新连接很多,可以增加该变量以提高性能。(一般情况,如果线程执行得很好,性能提高不明显)。检查Connections和Threads_created状态变量的差(详见[5.3.4节,“服务器状态变量”](# "5.3.4. Server Status Variables")),你可以看见线程缓存的效率。 ·         thread_concurrency 在Solaris中,**mysqld**用该值调用thr_setconcurrency()。该函数使应用程序向线程系统提供需要同时运行的期望的线程数目的提示。 ·         thread_stack 每个线程的堆栈大小。用crash-me测试检测出的许多限制取决于该值。 默认值足够大,可以满足普通操作。参见[7.1.4节,“MySQL基准套件”](# "7.1.4. The MySQL Benchmark Suite")。 ·         time_format 该变量为使用。 ·         time_zone 当前的时区。初使值是'SYSTEM'(使用system_time_zone的值),但可以用--default-time-zone选项在服务器启动时显式指定。 ·         tmp_table_size 如果内存内的临时表超过该值,MySQL自动将它转换为硬盘上的MyISAM表。如果你执行许多高级GROUP BY查询并且有大量内存,则可以增加tmp_table_size的值。 ·         tmpdir 保存临时文件和临时表的目录。该变量可以设置为几个路径,按round-robin模式使用。在Unix中应该用冒号(‘:’)间隔开路径,在Windows、NetWare和OS/2中用分号(‘;’)。 用来将负荷分散到几个物理硬盘上。如果MySQL服务器为复制从服务器,你不应将tmpdir设置为指向基于内存的文件系统上的目录或当服务器主机重启时声明的目录。复制从服务器需要部分临时文件来在机器重启后仍可用,以便它可以复制临时表或执行LOAD DATA INFILE操作。如果服务器重启时临时文件夹中的文件丢失了,则复制失败。但是,如果你使用MySQL 4.0.0或更新版本,你可以使用 slave_load_tmpdir变量设置从服务器的临时目录。在这种情况下,从服务器不再使用常规tmpdir,说明你可以将tmpdir设置到一个非固定位置。 ·         transaction_alloc_block_size 为保存将保存到二进制日志中的事务的查询而分配的内存块的大小(字节)。 ·         transaction_prealloc_size 为transaction_alloc_blocks分配的固定缓冲区的大小(字节),在两次查询之间不会释放。使该值足够大,将所有查询固定到一个事务中,可以避免多次malloc()调用。 ·         tx_isolation 默认事务隔离级别。默认值为REPEATABLE-READ。 ·         updatable_views_with_limit 该变量控制如果更新包含LIMIT子句,是否可以在当前表中使用不包含主关键字的视图进行更新。(通常用GUI工具生成这类更新)。更新指UPDATE或DELETE语句。这儿主关键字指PRIMARY KEY,或一个UNIQUE索引,其中任何列不可以包含NULL。 该变量有两个值: o        1或YES:只发出警告(没有错误消息)。这是 默认值。 o        0或NO:禁止更新。 ·         version 服务器版本号。 ·         version_bdb BDB存储引擎版本。 ·         version_comment **configure**脚本有一个--with-comment选项,当构建MySQL时可以进行注释。该变量包含注释值。 ·         version_compile_machine MySQL构建的机器或架构的类型。 ·         version_compile_os MySQL构建的操作系统的类型。 ·         wait_timeout 服务器关闭非交互连接之前等待活动的秒数。 在线程启动时,根据全局wait_timeout值或全局interactive_timeout值初始化会话wait_timeout值,取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义)。又见interactive_timeout。 #### 5.3.3.1. 动态系统变量 许多服务器系统变量是动态的,可以使用SET GLOBAL或SET SESSION在运行时设置。你还可以使用SELECT获得它们的值。参见[9.4节,“系统变量”](# "9.4. System Variables")。 下面的表列出了所有动态系统变量。最后1列说明每个变量是否适用GLOBAL或SESSION(或二者)。 <table border="1" cellpadding="0" id="table7"><tr><td> <p><strong> <span>变量名</span></strong></p></td> <td> <p><strong> <span>值类型</span></strong></p></td> <td> <p><strong> <span>类型</span></strong></p></td> </tr><tr><td> <p> <span>autocommit</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>big_tables</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>binlog_cache_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>bulk_insert_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>character_set_client</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>character_set_connection</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span><span> </span></p></td> </tr><tr><td> <p> <span>character_set_results</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>character_set_server</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>collation_connection</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>collation_server</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>completion_type</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>concurrent_insert</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>connect_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>convert_character_set</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>default_week_format</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>delay_key_write</span></p></td> <td> <p> <span>OFF</span><span> | </span> <span>ON</span><span> | </span><span> ALL</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>delayed_insert_limit</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>delayed_insert_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>delayed_queue_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>div_precision_increment</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>engine_condition_pushdown</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>error_count</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>expire_logs_days</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>flush</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>flush_time</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>foreign_key_checks</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>ft_boolean_syntax</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>group_concat_max_len</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>identity</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>innodb_autoextend_increment</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>innodb_concurrency_tickets</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>innodb_max_dirty_pages_pct</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>innodb_max_purge_lag</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>innodb_support_xa</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>innodb_sync_spin_loops</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>innodb_table_locks</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>innodb_thread_concurrency</span></p></td> <td> <p><span>numeric </span> <span>GLOBAL</span></p></td> <td> <p><span> </span></p></td> </tr><tr><td> <p> <span>innodb_thread_sleep_delay</span></p></td> <td> <p><span>numeric </span> <span>GLOBAL</span></p></td> <td> <p><span> </span></p></td> </tr><tr><td> <p> <span>insert_id</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>interactive_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>join_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>key_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>last_insert_id</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>local_infile</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>log_warnings</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>long_query_time</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>low_priority_updates</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_allowed_packet</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_binlog_cache_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_binlog_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_connect_errors</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_connections</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_delayed_threads</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_error_count</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_heap_table_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_insert_delayed_threads</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_join_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_relay_log_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_seeks_for_key</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_sort_length</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_tmp_tables</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>max_user_connections</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>max_write_lock_count</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>myisam_stats_method</span></p></td> <td> <p><span>enum</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>multi_read_range</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>myisam_data_pointer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>log_bin_trust_routine_creators</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>myisam_max_sort_file_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>myisam_repair_threads</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>myisam_sort_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>net_buffer_length</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>net_read_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>net_retry_count</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>net_write_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>old_passwords</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>optimizer_prune_level</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>optimizer_search_depth</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>preload_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>query_alloc_block_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>query_cache_limit</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>query_cache_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>query_cache_type</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>query_cache_wlock_invalidate</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>query_prealloc_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>range_alloc_block_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>read_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>read_only</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>read_rnd_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>rpl_recovery_rank</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>safe_show_database</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>secure_auth</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>server_id</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>slave_compressed_protocol</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>slave_net_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>slave_transaction_retries</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>slow_launch_time</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>sort_buffer_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_auto_is_null</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_big_selects</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_big_tables</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_buffer_result</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_log_bin</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_log_off</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_log_update</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_low_priority_updates</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_max_join_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_mode</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_notes</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_quote_show_create</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_safe_updates</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_select_limit</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_slave_skip_counter</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>updatable_views_with_limit</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sql_warnings</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>sync_binlog</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>sync_frm</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>storage_engine</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>table_cache</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>table_type</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>thread_cache_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span></p></td> </tr><tr><td> <p> <span>time_zone</span></p></td> <td> <p><span>string</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>timestamp</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>tmp_table_size</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>transaction_alloc_block_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>transaction_prealloc_size</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>tx_isolation</span></p></td> <td> <p><span>enumeration</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>unique_checks</span></p></td> <td> <p><span>boolean</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>wait_timeout</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>GLOBAL</span><span> | </span> <span>SESSION</span></p></td> </tr><tr><td> <p> <span>warning_count</span></p></td> <td> <p><span>numeric</span></p></td> <td> <p> <span>SESSION</span></p></td> </tr></table> 标记为**string**的变量采用字符串值。标记为**numeric**的变量采用数字值。标记为**boolean**的变量可以设置为0、1、ON或OFF。标记为**enumeration**的变量一般情况应设置为该变量的某个可用值,但还可以设置为对应期望的枚举值的数字。对于枚举系统变量,第1个枚举值应对应0。这不同于ENUM列,第1个枚举值对应1。 ### 5.3.4. 服务器状态变量 服务器维护许多提供操作相关信息的状态变量。你可以通过SHOW STATUS语句查看这些变量和它们的值: ~~~ mysql> SHOW STATUS; ~~~ ~~~ +-----------------------------------+------------+ ~~~ ~~~ | Variable_name                     | Value      | ~~~ ~~~ +-----------------------------------+------------+ ~~~ ~~~ | Aborted_clients                   | 0          | ~~~ ~~~ | Aborted_connects                  | 0          | ~~~ ~~~ | Bytes_received                    | 155372598  | ~~~ ~~~ | Bytes_sent                        | 1176560426 | ~~~ ~~~   ~~~ ~~~ … ~~~ ~~~   ~~~ ~~~ | Connections                       | 30023      | ~~~ ~~~ | Created_tmp_disk_tables           | 0          | ~~~ ~~~ | Created_tmp_files                 | 3          | ~~~ ~~~ | Created_tmp_tables                | 2          | ~~~ ~~~   ~~~ ~~~ … ~~~ ~~~   ~~~ ~~~ | Threads_created                   | 217        | ~~~ ~~~ | Threads_running                   | 88         | ~~~ ~~~ | Uptime                            | 1389872    | ~~~ ~~~ +-----------------------------------+------------+ ~~~ ~~~   ~~~ 用FLUSH STATUS语句可以将许多状态变量重设为0。 状态变量有以下含义。没有指示版本的变量在MySQL 5.1之前已经出现。关于它们的使用历史,参见*MySQL 5.0参考手册*。 ·         Aborted_clients 由于客户端没有正确关闭连接导致客户端终止而中断的连接数。参见[A.2.10节,“通信错误和失效连接”](# "A.2.10. Communication Errors and Aborted Connections")。 ·         Aborted_connects 试图连接到MySQL服务器而失败的连接数。参见[A.2.10节,“通信错误和失效连接”](# "A.2.10. Communication Errors and Aborted Connections")。 ·         Binlog_cache_disk_use 使用临时二进制日志缓存但超过binlog_cache_size值并使用临时文件来保存事务中的语句的事务数量。 ·         Binlog_cache_use 使用临时二进制日志缓存的事务数量。 ·         Bytes_received 从所有客户端接收到的字节数。 ·         Bytes_sent 发送给所有客户端的字节数。 ·         Com_*xxx* Com_*xxx*语句计数变量表示每个*xxx*语句执行的次数。每类语句有一个状态变量。例如,Com_delete和Com_insert分别统计DELETE和INSERT语句执行的次数。 Com_stmt_*xxx*状态变量为: o        Com_stmt_prepare o        Com_stmt_execute o        Com_stmt_fetch o        Com_stmt_send_long_data o        Com_stmt_reset o        Com_stmt_close 这些变量代表准备好的语句命令。它们的名字对应网络层使用的COM_*xxx*命令系列;换句话说:当准备好的语句API调用如**mysql_stmt_prepare()**、**mysql_stmt_执行()**并执行时,它们的值增加。但是,当执行下面的SQL语句时,Com_stmt_prepare, Com_stmt_execute和Com_stmt_close也增加:PREPARE、EXECUTE或DEALLOCATE PREPARE。此外,旧(从MySQL 4.1.3起可用)语句计数变量Com_prepare_sql、Com_execute_sql和Com_dealloc_sql的值也随PREPARE、EXECUTE和DEALLOCATE PREPARE语句增加。Com_stmt_fetch代表通过光标获取的网络round-trips的总数量。 所有Com_stmt_*xxx*变量将增加,即使语句参数未知或执行过程中出现错误。换句话说,它们的值对应发出的请求数,而不是成功完成的请求数。 ·         Connections 试图连接到(不管是否成功)MySQL服务器的连接数。 ·         Created_tmp_disk_tables 服务器执行语句时在硬盘上自动创建的临时表的数量。 ·         Created_tmp_files **mysqld**已经创建的临时文件的数量。 ·         Created_tmp_files 服务器执行语句时自动创建的内存中的临时表的数量。如果Created_tmp_disk_tables较大,你可能要增加tmp_table_size值使临时 表基于内存而不基于硬盘。 ·         Delayed_errors 用INSERT DELAYED写的出现错误的行数(可能为duplicate key)。 ·         Delayed_insert_threads 使用的INSERT DELAYED处理器线程数。 ·         Delayed_writes 写入的INSERT DELAYED行数。 ·         Flush_commands 执行的FLUSH语句数。 ·         Handler_commit 内部提交语句数。 ·         Handler_discover MySQL服务器可以问NDB CLUSTER存储引擎是否知道某一名字的表。这被称作发现。Handler_discover说明通过该方法发现的次数。 ·         Handler_delete 行从表中删除的次数。 ·         Handler_read_first 索引中第一条被读的次数。如果较高,它建议服务器正执行大量全索引扫描;例如,SELECT col1 FROM foo,假定col1有索引。 ·         Handler_read_key 根据键读一行的请求数。如果较高,说明查询和表的索引正确。 ·         Handler_read_next 按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。 ·         Handler_read_prev 按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY ... DESC。 ·         Handler_read_rnd 根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。 ·         Handler_read_rnd_next 在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或写入的查询没有利用索引。 ·         Handler_rollback 内部ROLLBACK语句的数量。 ·         Handler_update 在表内更新一行的请求数。 ·         Handler_write 在表内插入一行的请求数。 ·         Innodb_buffer_pool_pages_data 包含数据的页数(脏或干净)。 ·         Innodb_buffer_pool_pages_dirty 当前的脏页数。 ·         Innodb_buffer_pool_pages_flushed 要求清空的缓冲池页数。 ·         Innodb_buffer_pool_pages_free 空页数。 ·         Innodb_buffer_pool_pages_latched 在InnoDB缓冲池中锁定的页数。这是当前正读或写或由于其它原因不能清空或删除的页数。 ·           Innodb_buffer_pool_pages_misc 忙的页数,因为它们已经被分配优先用作管理,例如行锁定或适用的哈希索引。该值还可以计算为Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free - Innodb_buffer_pool_pages_data。 ·         Innodb_buffer_pool_pages_total 缓冲池总大小(页数)。 ·         Innodb_buffer_pool_read_ahead_rnd InnoDB初始化的“随机”read-aheads数。当查询以随机顺序扫描表的一大部分时发生。 ·         Innodb_buffer_pool_read_ahead_seq InnoDB初始化的顺序read-aheads数。当InnoDB执行顺序全表扫描时发生。 ·         Innodb_buffer_pool_read_requests InnoDB已经完成的逻辑读请求数。 ·         Innodb_buffer_pool_reads 不能满足InnoDB必须单页读取的缓冲池中的逻辑读数量。 ·         Innodb_buffer_pool_wait_free 一般情况,通过后台向InnoDB缓冲池写。但是,如果需要读或创建页,并且没有干净的页可用,则它还需要先等待页面清空。该计数器对等待实例进行记数。如果已经适当设置缓冲池大小,该值应小。 ·         Innodb_buffer_pool_write_requests 向InnoDB缓冲池的写数量。 ·         Innodb_data_fsyncs fsync()操作数。 ·         Innodb_data_pending_fsyncs 当前挂起的fsync()操作数。 ·         Innodb_data_pending_reads 当前挂起的读数。 ·         Innodb_data_pending_writes 当前挂起的写数。 ·         Innodb_data_read 至此已经读取的数据数量(字节)。 ·         Innodb_data_reads 数据读总数量。 ·         Innodb_data_writes 数据写总数量。 ·         Innodb_data_written 至此已经写入的数据量(字节)。 ·         Innodb_dblwr_writes, Innodb_dblwr_pages_written 已经执行的双写操作数量和为此目的已经写好的页数。参见[15.2.14.1节,“磁盘I/O”](# "15.2.14.1. Disk I/O")。 ·         Innodb_log_waits 我们必须等待的时间,因为日志缓冲区太小,我们在继续前必须先等待对它清空。 ·         Innodb_log_write_requests 日志写请求数。 ·         Innodb_log_writes 向日志文件的物理写数量。 ·         Innodb_os_log_fsyncs 向日志文件完成的fsync()写数量。 ·         Innodb_os_log_pending_fsyncs 挂起的日志文件fsync()操作数量。 ·         Innodb_os_log_pending_writes 挂起的日志文件写操作。 ·         Innodb_os_log_written 写入日志文件的字节数。 ·         Innodb_page_size 编译的InnoDB页大小(默认16KB)。许多值用页来记数;页的大小很容易转换为字节。 ·         Innodb_pages_created 创建的页数。 ·         Innodb_pages_read 读取的页数。 ·         Innodb_pages_written 写入的页数。 ·         Innodb_row_lock_current_waits 当前等待的待锁定的行数。 ·         Innodb_row_lock_time 行锁定花费的总时间,单位毫秒。 ·         Innodb_row_lock_time_avg 行锁定的平均时间,单位毫秒。 ·         Innodb_row_lock_time_max 行锁定的最长时间,单位毫秒。 ·         Innodb_row_lock_waits 一行锁定必须等待的时间数。 ·         Innodb_rows_deleted 从InnoDB表删除的行数。 ·         Innodb_rows_inserted 插入到InnoDB表的行数。 ·         Innodb_rows_read 从InnoDB表读取的行数。 ·         Innodb_rows_updated InnoDB表内更新的行数。 ·         Key_blocks_not_flushed 键缓存内已经更改但还没有清空到硬盘上的键的数据块数量。 ·         Key_blocks_unused 键缓存内未使用的块数量。你可以使用该值来确定使用了多少键缓存;参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")中Key_buffer_size的讨论。 ·         Key_blocks_used 键缓存内使用的块数量。该值为高水平线标记,说明已经同时最多使用了多少块。 ·         Key_read_requests 从缓存读键的数据块的请求数。 ·         Key_reads 从硬盘读取键的数据块的次数。如果Key_reads较大,则Key_buffer_size值可能太小。可以用Key_reads/Key_read_requests计算缓存损失率。 ·         Key_write_requests 将键的数据块写入缓存的请求数。 ·         Key_writes 向硬盘写入将键的数据块的物理写操作的次数。 ·         Last_query_cost 用查询优化器计算的最后编译的查询的总成本。用于对比同一查询的不同查询方案的成本。默认值0表示还没有编译查询。 默认值是0。Last_query_cost具有会话范围。 ·         Max_used_connections 服务器启动后已经同时使用的连接的最大数量。 ·         Not_flushed_delayed_rows 等待写入INSERT DELAY队列的行数。 ·         Open_files 打开的文件的数目。 ·         Open_streams 打开的流的数量(主要用于记录)。 ·         Open_tables 当前打开的表的数量。 ·         Opened_tables 已经打开的表的数量。如果Opened_tables较大,table_cache 值可能太小。 ·         QCACHE_free_blocks 查询缓存内自由内存块的数量。 ·         QCACHE_free_memory 用于查询缓存的自由内存的数量。 ·         QCACHE_hits 查询缓存被访问的次数。 ·         QCACHE_inserts 加入到缓存的查询数量。 ·         QCACHE_lowmem_prunes 由于内存较少从缓存删除的查询数量。 ·         QCACHE_not_cached 非缓存查询数(不可缓存,或由于query_cache_type设定值未缓存)。 ·         Qcache_queries_in_cache 登记到缓存内的查询的数量。 ·         Qcache_total_blocks 查询缓存内的总块数。 ·         Questions 已经发送给服务器的查询的个数。 ·         Rpl_status 失败安全复制状态(还未使用)。 ·         Select_full_join 没有使用索引的联接的数量。如果该值不为0,你应仔细检查表的索引。 ·         Select_full_range_join 在引用的表中使用范围搜索的联接的数量。 ·         Select_range 在第一个表中使用范围的联接的数量。一般情况不是关键问题,即使该值相当大。 ·         Select_range_check 在每一行数据后对键值进行检查的不带键值的联接的数量。如果不为0,你应仔细检查表的索引。 ·         Select_scan 对第一个表进行完全扫描的联接的数量。 ·         Slave_open_temp_tables 当前由从SQL线程打开的临时表的数量。 ·         Slave_running 如果该服务器是连接到主服务器的从服务器,则该值为ON。 ·         Slave_retried_transactions 启动后复制从服务器SQL线程尝试事务的总次数。 ·         Slow_launch_threads 创建时间超过slow_launch_time秒的线程数。 ·         Slow_queries 查询时间超过long_query_time秒的查询的个数。参见[5.11.4节,“慢速查询日志”](# "5.11.4. The Slow Query Log")。 ·         Sort_merge_passes 排序算法已经执行的合并的数量。如果这个变量值较大,应考虑增加sort_buffer_size系统变量的值。 ·         Sort_range 在范围内执行的排序的数量。 ·         Sort_rows 已经排序的行数。 ·         Sort_scan 通过扫描表完成的排序的数量。 ·         Ssl_*xxx* 用于SSL连接的变量。 ·         Table_locks_immediate 立即获得的表的锁的次数。 ·         Table_locks_waited 不能立即获得的表的锁的次数。如果该值较高,并且有性能问题,你应首先优化查询,然后拆分表或使用复制。 ·         Threads_cached 线程缓存内的线程的数量。 ·         Threads_connected 当前打开的连接的数量。 ·         Threads_created 创建用来处理连接的线程数。如果Threads_created较大,你可能要增加thread_cache_size值。缓存访问率的计算方法Threads_created/Connections。 ·           Threads_running 激活的(非睡眠状态)线程数。 ·         Uptime 服务器已经运行的时间(以秒为单位)。 ### 5.4. mysql_fix_privilege_tables:升级MySQL系统表 一些MySQL发布对mysql数据库中的系统表的结构进行了更改,添加了新权限或特性。当你更新到新版本MySQL,你应同时更新系统表,以确保它们的结构最新。首先备份mysql数据库,然后按照下面的程序操作。 在Unix或Unix类系统中,运行**mysql_fix_privilege_tables**脚本来更新系统表: ~~~ shell> mysql_fix_privilege_tables ~~~ 你必须在服务器运行时执行该脚本。它试图连接本机上用root运行的服务器。如果root账户需要密码,在命令行中按下述方法给出密码: ~~~ shell> mysql_fix_privilege_tables--password=root_password ~~~ ** mysql_fix_privilege_tables**脚本可以执行将系统表转换为当前格式的任何动作。运行时你可能会看见一些Duplicate column name警告;你可以忽略它们。 运行完脚本后,停止服务器并重启。 在Windows系统中,MySQL分发包括mysql_fix_privilege_tables.sql SQL脚本,你可以用**mysql**客户端来运行。例如,如果MySQL安装到C:\Program Files\MySQL\MySQL Server 5.1,命令应为: ~~~ C:\> C:\Program Files\MySQL\MySQL Server 5.1\bin\mysql -u root -p mysql ~~~ ~~~ mysql> SOURCE C:/Program Files/MySQL/MySQL Server 5.1/scripts/mysql_fix_privilege_tables.sql ~~~ 如果安装到其它目录,相应地更改路径名。 **mysql**命令将提示输入root密码;按照提示输入密码。 在Unix中,当**mysql**处理mysql_fix_privilege_tables.sql script脚本中的语句时,你可能会看见一些Duplicate column name警告;你可以忽略它们。 运行完脚本后,停止服务器并重启。 ### 5.5. MySQL服务器关机进程 1.  服务器关闭进程可以概括为: 1.    启动关闭进程 2.    服务器根据需要创建关闭线程 3.    服务器停止接收新连接 4.    服务器终止当前的活动 5.    存储引擎被停掉或关闭 6.    服务器退出 下面是更详细的描述: 1.    启动关闭进程。 可以用多种方法启动服务器的关闭。例如,拥有SHUTDOWN权限的用户可以执行**mysqladmin shutdown**命令。**mysqladmin**可以用于所有支持MySQL的平台上。其它操作系统相关的关闭开始方法还可能有:在Unix中,当接收到SIGTERM信号后,服务器关闭。对于在Windows中作为服务运行的服务器,当服务管理器让它关闭时,则关闭。 2.    服务器根据需要创建关闭线程。 根据开始关闭的方式,服务器可以创建线程来处理关闭进程。如果客户端需要关闭,则创建关闭线程。如果收到SIGTERM信号后关闭,信号线程可以自己关闭,或者创建单独的线程来完成。如果服务器尝试创建关闭线程而不能创建(例如,如果内存被耗尽),它在错误日志中给出诊断消息: ~~~ Error: Can't create thread to kill server ~~~ 3.    服务器停止接收新连接。 在关闭过程中要想防止启动新活动,服务器停止接收新的客户端连接。它将关闭它帧听的网络连接:TCP/IP端口、Unix套接字文件、Windows命名管道和在Windows中的共享内存。 4.    服务器终止当前的活动。 对于每个与客户端连接相关的线程,与客户端的连接被中断,线程被标记为“杀掉的”。当线程注意到此类标记后则线程终止。空闲连接的线程很快终止。当前正处理查询的线程定期检查它们的状态,终止的时间较长。关于线程终止的详细信息,参见[13.5.5.3节,“KILL语法”](# "13.5.5.3. KILL Syntax"),特别是关于对MyISAM表的杀掉的REPAIR TABLE或OPTIMIZE TABLE操作。 对于有打开事务的线程,事务被回滚。请注意如果某个线程正在更新非事务表,多行UPDATE或INSERT等操作会使表部分更新,因为操作在完成前会终止。 如果服务器是主复制服务器,与当前连接的从服务器相关的线程的处理方式同其它客户端线程。即每个线程被标记为杀掉的,在下次检查他的状态后会退出。 如果服务器是从复制服务器,在客户端线程标记为杀掉的之前,激活的I/O和SQL线程被停止。SQL线程允许先结束它当前的语句(以避免造成复制问题)然后停止。如果此时SQL线程正位于事务中部,事务则 回滚。 5.    存储引擎被停掉或关闭。 在该阶段,表缓存被清空,所有打开的表被关闭。 每个存储引擎执行它管理的表需要的任何动作。例如,MyISAM清空任何挂起的表索引写操作。InnoDB将它的缓冲池清空到硬盘上(除非innodb_fast_shutdown为2),将当前的LSN写入表内,并终止自己的内部线程。 6.    服务器退出。 ### 5.6. 一般安全问题 [ 5.6.1. 通用安全指南](#)[ 5.6.2. 使MySQL在攻击者面前保持安全](#)[ 5.6.3. Mysqld安全相关启动选项****](#)[ 5.6.4. LOAD DATA LOCAL安全问题``](#) 本节描述一些常见的需要注意的安全问题,以及一些可以使你的MySQL安装更加安全以防止黑客和误用的措施。关于MySQL用于设置用户账户并检查数据库访问的访问控制系统的具体信息,参见[5.7节,“MySQL访问权限系统”](# "5.7. The MySQL Access Privilege System")。 ### 5.6.1. 通用安全指南 任何在与Internet联网的计算机上使用MySQL的用户都应仔细阅读本节,以避免最常见的安全问题。 讨论安全时,我们强调必须完全保护整个服务器主机的安全(而不只是MySQL服务器)防范各种类型的可能的攻击:偷听、修改、重放和拒绝服务。我们在这里不能覆盖各方面的内容和措施。 MySQL根据访问控制列表(ACL)对所有连接、查询和其它用户尝试执行的操作进行安全管理。MySQL客户端和服务器之间还支持SSL-加密连接。这儿讨论的许多概念并不是MySQL专有的;该思想几乎同样适合所有应用程序。 运行MySQL时,应尽量遵从下面的指导: ·         **不要让任何人(除了MySQL ****root****账户)访问****mysql****数据库中的****user****表!**这很关键。**加密的密码才是MySQL中的真正的密码。**知道user表中所列的密码并且能访问该账户客访问的主机的人**可以很容易地用该用户登录**。 ·         学习MySQL访问权限系统。用GRANT和REVOKE语句来控制对MySQL的访问。不要授予超过需求的权限。决不能为所有主机授权。 检查清单: o        试试mysql -u root。如果你能够成功连接服务器而没有要任何密码,则说明有问题。任何人可以作为MySQLroot用户用它的全部权限来连接MySQL服务器!查阅MySQL安装说明,应特别注意关于设置root密码的信息。参见[2.9.3节,“使初始MySQL账户安全”](# "2.9.3. Securing the Initial MySQL Accounts")。 o        通过SHOW GRANTS语句检查查看谁已经访问了什么。然后使用REVOKE语句删除不再需要的权限。 ·         不要将纯文本密码保存到数据库中。如果你的计算机有安全危险,入侵者可以获得所有的密码并使用它们。相反,应使用MD5()、SHA1()或单向哈希函数。 ·         不要从词典中选择密码。有专门的程序可以破解它们。即使象“xfish98”这样的密码也很差。而“duag98”要好得多,虽然包含了相同的字“fish”,但从标准QWERTY键盘向左输入。另一种方法是使用“Mhall”,来自句子“Mary had a little lamb.”中每个字的第一个字符。这样很容易记住并输入,但是不知道的人很难猜出来。 ·         购买防火墙。这样可以保护你防范各种软件中至少50%的各种类型的攻击。把MySQL放到防火墙后或隔离区(DMZ)。 检查清单: o        试试从Internet使用nmap工具扫描端口。MySQL默认使用端口3306。不应从不可信任主机访问该端口。另一种检查是否MySQL端口打开的简单方式是从远程机器试试下面的命令,其中server_host是MySQL服务器运行的主机: ~~~ o                     shell> telnet server_host 3306 ~~~ 如果得到连接并得到一些垃圾字符,则端口打开着,则应从防火墙或路由器上关闭,除非你有合理的理由让它开着。如果telnet挂起或连接被拒绝,则端口被阻塞,这是你所希望的。 不要信任应用程序的用户输入的任何数据。它们可以用Web形式、URL或构建的应用程序输入特殊或逃溢字符序列来尝试欺骗你的代码。如果某个用户输入“; DROP DATABASE mysql;”等内容,应确保你的应用程序保持安全。这是特例,但当黑客使用类似技术时,如果你没有做好准备,结果可能会出现大的安全漏洞和数据丢失。 一个常见的错误是只保护字符串数据值。一定要记住还应检查数字数据。如果当用户输入值234时,应用程序生成查询SELECT * FROM table WHERE ID=234,用户可以输入值234 OR 1=1使应用程序生成查询SELECT * FROM table WHERE ID=234 OR 1=1。结果是服务器查找表内的每个记录。这样会暴露每个记录并造成过多的服务器负载。保护防范这类攻击的最简单的方法是使用单引号将数字常量引起来:SELECT * FROM table WHERE ID='234'。如果用户输入其它信息,均变为字符串的一部分。在数字部分,MySQL自动将字符串转换为数字并剥离字符串包含的附加的非数字字符。 有时候人们会认为如果数据库只包含供公共使用的数据,则不需要保护。这是不正确的。即使允许显示数据库中的任何记录,你仍然应保护防范拒绝服务攻击(例如,基于前面段落中所述的技术的攻击,会使服务器浪费资源)。否则,你的服务器不再响应合法用户。 检查清单: o        试试用Web形式输入单引号和双引号(‘'’和‘"’)。如果得到任何形式的MySQL错误,立即分析原因。 o        试试修改动态URL,可以在其中添加%22(‘"’)、%23(‘#’)和%27(‘'’)。 o        试试在动态URL中修改数据类型,使用前面示例中的字符,包括数字和字符类型。你的应用程序应足够安全,可以防范此类修改和类似攻击。 o        试试输入字符、空格和特殊符号,不要输入数值字段的数字。你的应用程序应在将它们传递到MySQL之前将它们删除或生成错误。将未经过检查的值传递给MySQL是很危险的! o        将数据传给MySQL之前先检查其大小。 o        用管理账户之外的用户名将应用程序连接到数据库。不要给应用程序任何不需要的访问权限。 ·         许多应用程序编程接口提供了措施逃逸数据值中的特殊字符。如果使用正确,可以防止应用程序用户输入使应用程序生成不期望的效果的语句的数值: o        MySQL C API:使用mysql_real_escape_string() API调用。 o        MySQL++:查询流使用escape和quote修订符。 o        PHP:使用mysql_escape_string()函数基于MySQL C API中的同名函数。(在PHP 4.0.3之前,使用addslashes())。在PHP 5中,可以使用mysqli扩展名,它支持改进的MySQL鉴定协议和密码,以及用占位符编写的语句。 o        Perl DBI:使用quote()方法或使用占位符。 o        Java JDBC:使用一个PreparedStatement对象和占位符。 其它编程接口有类似的功能。 ·         不要通过Internet传送明文(未加密的)数据。该信息可以被有足够时间和能力来截取它并用于个人目的的任何人访问。相反,应使用加密协议,例如SSL或SSH。MySQL支持内部SSL连接,例如版本 4.0.0。可以使用SSH端口映射为通信创建加密(并压缩)的隧道。 ·         学会使用tcpdump和strings工具。在大多数情况下,你可以使用下面的命令检查是否MySQL数据流未加密: ~~~ ·                shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings ~~~ (该命令在Linux中可以工作,在其它系统中经过小小的修改后应可以工作)。 警告:如果你没有看见明文数据,并不一定说明信息实际上被加密了。如果你需要较高级别的安全,你应咨询安全专家。 ### 5.6.2. 使MySQL在攻击者面前保持安全 当你连接到MySQL服务器时,你应使用一个密码。密码不以明文在上传输。客户端连接序列中的密码处理在MySQL 4.1.1中已经升级,很安全。如果你仍然使用pre-4.1.1-风格的密码,加密算法不如新算法强;通过一些工作,可以窃取客户端和服务器之间的通信的聪明的攻击者可以破解密码。(关于不同的密码处理方法的讨论参见[5.7.9节,“MySQL 4.1中的密码哈希处理”](# "5.7.9. Password Hashing in MySQL 4.1"))。 如果客户端和服务器之间的连接通过不可信任网络,你应使用SSH隧道来加密通信。 所有其它信息以文本传送,可以被可以看到连接的任何人读取。如果你担心这个,你可以使用压缩协议来使通信更难以解密。要想使连接更加安全,你应使用SSH来获得加密的MySQL服务器和MySQL客户端之间的TCP/IP连接。你可以从[http://www.openssh.org/](http://www.openssh.org/)找到开放源码SSH 客户端,并可以从[http://www.ssh.com/](http://www.ssh.com/)获得商业SSH客户端。 你还可以使用MySQL内部OpenSSL支持。参见[5.8.7节,“使用安全连接”](# "5.8.7. Using Secure Connections")。 为了使MySQL系统安全,强烈要求你考虑下列建议: ·         对所有MySQL用户使用密码。客户端程序不需要知道运行它的人员的身份。对于客户端/服务器应用程序,用户可以指定客户端程序的用户名。例如,如果*other_user*没有密码,任何人可以简单地用mysql -u *other_user**db_name*冒充他人调用**mysql**程序进行连接。如果所有用户有密码,使用其它用户的账户进行连接要困难得多。 要想更改用户的密码,应使用SET PASSWORD语句。还可以直接更新mysql数据库中的user表。例如,要更改所有root用户的MySQL账户的密码,应: ~~~ shell> mysql -u root ~~~ ~~~ mysql> UPDATE mysql.user SET Password=PASSWORD('newpwd') ~~~ ~~~     -> WHERE User='root'; ~~~ ~~~ mysql> FLUSH PRIVILEGES; ~~~ ·         绝对不要作为Unix的root用户运行MySQL服务器。这样做非常危险,因为任何具有FILE权限的用户能够用root创建文件(例如,~root/.bashrc)。为了防止,**mysqld**拒绝用root运行,除非使用--user=root选项明显指定。 应可以(并且应该)用普通非特权用户运行**mysqld**。你可以创建独立的Unix中的mysql账户来以便使所有内容更加安全。该账户只用于管理MySQL。要想用其它Unix用户启动**mysqld**,增加user选项指定/etc/my.cnf选项文件或服务器数据目录的my.cnf选项文件中的[mysqld]组的用户名。例如: ~~~ [mysqld] ~~~ ~~~ user=mysql ~~~ 该命令使服务器用指定的用户来启动,无论你手动启动或通过**mysqld_safe**或**mysql.server**启动。详细信息参见[A.3.2节,“如何以普通用户身份运行MySQL”](# "A.3.2. How to Run MySQL as a Normal User")。 作为其它Unix用户而不用root运行mysqld,你不需要更改user表中的root用户名,因为MySQL账户的用户名与Unix账户的用户名无关。 ·         不要允许使用表的符号链接。(可以用--skip-symbolic-links选项禁用)。如果你用root运行**mysqld**则特别重要,因为任何对服务器的数据目录有写访问权限的人则能够删除系统中的任何文件!参见[7.6.1.2节,“在Unix平台上使用表的符号链接](# "7.6.1.2. Using Symbolic Links for Tables on Unix")”。 ·         确保**mysqld**运行时,只使用对数据库目录具有读或写权限的Unix用户来运行。 ·         不要将PROCESS或SUPER权限授给非管理用户。**mysqladmin processlist**的输出显示出当前执行的查询正文,如果另外的用户发出一个UPDATE user SET password=PASSWORD('not_secure')查询,被允许执行那个命令的任何用户可能看得到。 **mysqld**为有SUPER权限的用户专门保留一个额外的连接,因此即使所有普通连接被占用,MySQL root用户仍可以登录并检查服务器的活动。 可以使用SUPER权限来终止客户端连接,通过更改系统变量的值更改服务的器操作,并控制复制服务器。 ·         不要向非管理用户授予FILE权限。有这权限的任何用户能在拥有**mysqld**守护进程权限的文件系统那里写一个文件!为了更加安全,由SELECT ... INTO OUTFILE生成的所有文件对每个人是可写的,并且你不能覆盖已经存在的文件。 **file**权限也可以被用来读取任何作为运行服务器的Unix用户可读取或访问的文件。使用该权限,你可以将任何文件读入数据库表。这可能被滥用,例如,通过使用LOAD DATA装载“/etc/passwd”进一个数据库表,然后能用SELECT显示它。 ·         如果你不信任你的DNS,你应该在授权表中使用IP数字而不是主机名。在任何情况下,你应该非常小心地使用包含通配符的主机名来创建 授权表条目! ·         如果你想要限制单个账户允许的连接数量,你可以设置**mysqld**中的max_user_connections变量来完成。GRANT语句也可以支持 资源控制选项来限制服务器对一个账户允许的使用范围。参见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。 ### 5.6.3. Mysqld安全相关启动选项**** 下列**mysqld**选项影响安全: ·         --allow-suspicious-udfs 该选项控制是否可以载入主函数只有xxx符的用户定义函数。默认情况下,该选项被关闭,并且只能载入至少有辅助符的UDF。这样可以防止从未包含合法UDF的共享对象文件载入函数。参见[27.2.3.6节,“用户定义函数安全注意事项”](# "27.2.3.6. User-Defined Function Security Precautions")。 ·         --local-infile[={0|1}] 如果用--local-infile=0启动服务器,则客户端不能使用LOCAL in LOAD DATA语句。参见[5.6.4节,“LOAD DATA LOCAL安全问题``”](# "5.6.4. Security Issues with LOAD DATA LOCAL")。 ·         --old-passwords 强制服务器为新密码生成短(pre-4.1)密码哈希。当服务器必须支持旧版本客户端程序时,为了保证兼容性这很有用。参见[5.7.9节,“MySQL 4.1中的密码哈希处理”](# "5.7.9. Password Hashing in MySQL 4.1")。 ·         (*OBSOLETE*) --safe-show-database 在以前版本的MySQL中,该选项使SHOW DATABASES语句只显示用户具有部分权限的数据库名。在MySQL 5.1中,该选项不再作为现在的 默认行为使用,有一个SHOW DATABASES权限可以用来控制每个账户对数据库名的访问。参见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。 ·         --safe-user-create 如果启用,用户不能用GRANT语句创建新用户,除非用户有mysql.user表的INSERT权限。如果你想让用户具有授权权限来创建新用户,你应给用户授予下面的权限: ~~~ mysql> GRANT INSERT(user) ON mysql.user TO 'user_name'@'host_name'; ~~~ 这样确保用户不能直接更改权限列,必须使用GRANT语句给其它用户授予该权限。 ·         --secure-auth 不允许鉴定有旧(pre-4.1)密码的账户。 ·         --skip-grant-tables 这个选项导致服务器根本不使用权限系统。这给每个人以*完全访问*所有的数据库的权力!(通过执行**mysqladmin flush-privileges**或**mysqladmin reload命令**,或执行FLUSH PRIVILEGES语句,你能告诉一个正在运行的服务器再次开始使用授权表。)   ·         --skip-name-resolve 主机名不被解析。所有在授权表的Host的列值必须是IP号或localhost。 ·         --skip-networking 在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进行。 ·         --skip-show-database 使用该选项,只允许有SHOW DATABASES权限的用户执行SHOW DATABASES语句,该语句显示所有数据库名。不使用该选项,允许所有用户执行SHOW DATABASES,但只显示用户有SHOW DATABASES权限或部分数据库权限的数据库名。请注意全局权限指数据库的权限。 ### 5.6.4. LOAD DATA LOCAL安全问题`` LOAD DATA语句可以装载服务器主机上的文件,若指定LOCAL关键字,可以装载客户端文件。 支持LOCAL版本的LOAD DATA语句有两个可能的安全问题: ·         由MySQL服务器启动文件从客户端向服务器主机的传输。理论上,打过补丁的服务器可以告诉客户端程序传输服务器选择的文件,而不是客户用LOAD DATA语句指定的文件。这样服务器可以访问客户端上客户有读访问权限的任何文件。 ·         在Web环境中,客户从Web服务器连接,用户可以使用LOAD DATA LOCAL来读取Web服务器进程有读访问权限的任何文件(假定用户可以运行SQL服务器的任何命令)。在这种环境中,MySQL服务器的客户实际上是Web服务器,而不是连接Web服务器的用户运行的程序。 要处理这些问题,我们更改了MySQL 3.23.49和MySQL 4.0.2(Windows中的4.0.13)中的LOAD DATA LOCAL的处理方法: ·         默认情况下,现在所有二进制分中的发MySQL客户端和库是用--enable-local-infile选项编译,以便与MySQL 3.23.48和以前的版本兼容。 ·         如果你从源码构建MySQL但没有使用--enable-local-infile选项来进行**configure**,则客户不能使用LOAD DATA LOCAL,除非显式调用mysql_options (...MYSQL_OPT_本地_INFILE,0)。参见[25.2.3.48节,“mysql_options()”](# "25.2.3.48. mysql_options()")。 ·         你可以用--local-infile=0选项启动**mysqld**从服务器端禁用所有LOAD DATA LOCAL命令。 ·         对于**mysql**命令行客户端,可以通过指定--local-infile[=1]选项启用LOAD DATA LOCAL,或通过--local-infile=0选项禁用。类似地,对于**mysqlimport**,--local or -L选项启用本地数据文件装载。在任何情况下,成功进行本地装载需要服务器启用相关选项。 ·         如果你使用LOAD DATA LOCAL Perl脚本或其它读选项文件中的[client]组的程序,你可以在组内添加local-infile=1选项。但是,为了便面不理解local-infile的程序产生问题,则规定使用loose- prefix: ~~~ ·                [client] ~~~ ~~~ ·                loose-local-infile=1 ~~~ ·         如果LOAD DATA LOCAL INFILE在服务器或客户端被禁用,试图执行该语句的客户端将收到下面的错误消息: ~~~ ERROR 1148: The used command is not allowed with this MySQL version ~~~ ### 5.7. MySQL访问权限系统 [ 5.7.1. 权限系统的作用](#)[ 5.7.2. 权限系统工作原理](#)[ 5.7.3. MySQL提供的权限](#)[ 5.7.4. 与MySQL服务器连接](#)[ 5.7.5. 访问控制, 阶段1:连接核实](#)[ 5.7.6. 访问控制, 阶段2:请求核实](#)[ 5.7.7. 权限更改何时生效](#)[ 5.7.8. 拒绝访问错误的原因``](#)[ 5.7.9. MySQL 4.1中的密码哈希处理](#) **MySQL**有先进但非标准的安全/权限系统。本节描述它的工作原理。 ### 5.7.1. 权限系统的作用 **MySQL**权限系统的主要功能是证实连接到一台给定主机的用户,并且赋予该用户在数据库上的SELECT、INSERT、UPDATE和DELETE权限。 附加的功能包括有匿名的用户并对于**MySQL**特定的功能例如LOAD DATA INFILE进行授权及管理操作的能力。 ### 5.7.2. 权限系统工作原理 ** MySQL**权限系统保证所有的用户只执行允许做的事情。当你连接**MySQL**服务器时,你的身份由***你从那儿连接的主机***和***你指定的用户名***来决定。连接后发出请求后,系统根据你的身份和**你想做什么**来授予权限。 **MySQL**在认定身份中考虑你的主机名和用户名字,是因为几乎没有原因假定一个给定的用户在因特网上属于同一个人。例如,从office.com连接的用户joe不一定和从elsewhere.com连接的joe是同一个人。**MySQL**通过允许你区分在不同的主机上碰巧有同样名字的用户来处理它:你可以对joe从office.com进行的连接授与一个权限集,而为joe从elsewhere.com的连接授予一个不同的权限集。 ** MySQL**存取控制包含2个阶段: - 阶段1:服务器检查是否允许你连接。 - 阶段2:假定你能连接,服务器检查你发出的每个请求。看你是否有足够的权限实施它。例如,如果你从数据库表中选择(select)行或从数据库删除表,服务器确定你对表有SELECT权限或对数据库有DROP权限。 如果连接时你的权限被更改了(通过你和其它人),这些更改不一定立即对你发出的下一个语句生效。详情参见[5.7.7节,“权限更改何时生效”](# "5.7.7. When Privilege Changes Take Effect")。 服务器在mysql数据库的 授权表中保存权限信息(即在mysql数据库中)。当MySQL服务器启动时将这些表的内容读入内存,在[5.7.7节,“权限更改何时生效”](# "5.7.7. When Privilege Changes Take Effect")的环境下重新读取它们。访问控制决策取决于内存中的 授权表的份数。 一般情况,你通过GRANT和REVOKE语句间接来操作 授权表的内容,设置账户并控制个人的权限。参见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。下面讨论了 授权表的结构以及服务器与客户端交互操作时如何使用其内容。 服务器在存取控制的两个阶段使用mysql数据库中的user、db和host表,这些授权表中的列如下: <table border="1" cellpadding="0" style="margin-left: -.4pt" id="table8"><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>表名</span></strong></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p><strong> <span>user</span></strong></p></td> <td> <p><strong> <span>db</span></strong></p></td> <td> <p><strong> <span>host</span></strong></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 列范围</span></strong></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Host</span></p></td> <td> <p> <span>Host</span></p></td> <td> <p> <span>Host</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>User</span></p></td> <td> <p> <span>Db</span></p></td> <td> <p> <span>Db</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Password</span></p></td> <td> <p> <span>User</span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 权限列</span></strong></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Select_priv</span></p></td> <td> <p> <span>Select_priv</span></p></td> <td> <p> <span>Select_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Insert_priv</span></p></td> <td> <p> <span>Insert_priv</span></p></td> <td> <p> <span>Insert_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Update_priv</span></p></td> <td> <p> <span>Update_priv</span></p></td> <td> <p> <span>Update_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Delete_priv</span></p></td> <td> <p> <span>Delete_priv</span></p></td> <td> <p> <span>Delete_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Index_priv</span></p></td> <td> <p> <span>Index_priv</span></p></td> <td> <p> <span>Index_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Alter_priv</span></p></td> <td> <p> <span>Alter_priv</span></p></td> <td> <p> <span>Alter_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Create_priv</span></p></td> <td> <p> <span>Create_priv</span></p></td> <td> <p> <span>Create_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Drop_priv</span></p></td> <td> <p> <span>Drop_priv</span></p></td> <td> <p> <span>Drop_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Grant_priv</span></p></td> <td> <p> <span>Grant_priv</span></p></td> <td> <p> <span>Grant_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Create_view_priv</span></p></td> <td> <p> <span>Create_view_priv</span></p></td> <td> <p> <span>Create_view_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Show_view_priv</span></p></td> <td> <p> <span>Show_view_priv</span></p></td> <td> <p> <span>Show_view_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Create_routine_priv</span></p></td> <td> <p> <span>Create_routine_priv</span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Alter_routine_priv</span></p></td> <td> <p> <span>Alter_routine_priv</span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>References_priv</span></p></td> <td> <p> <span>References_priv</span></p></td> <td> <p> <span>References_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span style="font-family: &quot;Arial Unicode MS&quot;; color:windowtext"> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Reload_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Shutdown_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Process_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>File_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Show_db_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Super_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Create_tmp_table_priv</span></p></td> <td> <p> <span>Create_tmp_table_priv</span></p></td> <td> <p> <span>Create_tmp_table_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Lock_tables_priv</span></p></td> <td> <p> <span>Lock_tables_priv</span></p></td> <td> <p> <span>Lock_tables_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Execute_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Repl_slave_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Repl_client_priv</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 安全列</span></strong></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>ssl_type</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>ssl_cipher</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>x509_issuer</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>x509_subject</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 资源控制列</span></strong></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>max_questions</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>max_updates</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>max_connections</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="172" style="width:129.0pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>max_user_connections</span></p></td> <td> <p><span> </span></p></td> <td> <p><span> </span></p></td> </tr></table> 对存取控制的第二阶段(请求证实),服务器执行请求验证以确保每个客户端有充分的权限满足各需求。除了user、db和host授权表,如果请求涉及表,服务器可以另外参考tables_priv和columns_priv表。tables_priv和columns_priv表可以对表和列提供更精确的权限控制。这些表的列如下: <table border="1" cellpadding="0" style="margin-left: -.4pt" id="table9"><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>表名</span></strong></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p><strong> <span>tables_priv</span></strong></p></td> <td> <p><strong> <span>columns_priv</span></strong></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 范围列</span></strong></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Host</span></p></td> <td> <p> <span>Host</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Db</span></p></td> <td> <p> <span>Db</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>User</span></p></td> <td> <p> <span>User</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Table_name</span></p></td> <td> <p> <span>Table_name</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td> <p> <span>Column_name</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 权限列</span></strong></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Table_priv</span></p></td> <td> <p> <span>Column_priv</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Column_priv</span></p></td> <td> <p><span> </span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 其它列</span></strong></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Timestamp</span></p></td> <td> <p> <span>Timestamp</span></p></td> </tr><tr><td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><span> </span></p></td> <td width="103" style="width:77.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>Grantor</span></p></td> <td> <p><span> </span></p></td> </tr></table> Timestamp和Grantor列当前还未使用,这儿不再进一步讨论。 为了对涉及保存程序的请求进行验证,服务器将查阅procs_priv表。该表具有以下列: <table border="1" cellpadding="0" id="table10"><tr><td> <p><strong><span>表名</span></strong></p></td> <td> <p><strong> <span>procs_priv</span></strong></p></td> </tr><tr><td> <p><strong><span> 范围列</span></strong></p></td> <td> <p> <span>Host</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p> <span>Db</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p> <span>User</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p> <span>Routine_name</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p> <span>Routine_type</span></p></td> </tr><tr><td> <p><strong><span> 权限列</span></strong></p></td> <td> <p> <span>Proc_priv</span></p></td> </tr><tr><td> <p><strong><span> 其它列</span></strong></p></td> <td> <p> <span>Timestamp</span></p></td> </tr><tr><td> <p><span> </span></p></td> <td> <p> <span>Grantor</span></p></td> </tr></table> Routine_type列为ENUM列,值为'FUNCTION'或'PROCEDURE',表示行所指的程序类型。该列允许为同名函数和程序单独授权。 Timestamp和Grantor列当前还未使用,这儿不再进一步讨论。 每个授权表包含范围列和权限列: l        范围列决定表中每个条目(行)的范围,即,行适用的上下文。例如, 一个user表行的Host和User值为'thomas.loc.gov'和'bob',将被用于证实来自主机thomas.loc.gov的bob对服务器的连接。同样,一个db表行的Host、User和Db列的值是'thomas.loc.gov'、'bob'和'reports'将用在bob从主机thomas.loc.gov联接访问reports数据库的时候。tables_priv和columns_priv表包含范围列,指出每个行适用的表或表/列的组合。procs_priv范围列指出每个行适用的保存程序。 对于检查存取的用途,比较Host值是忽略大小写的。User、Password、Db和Table_name值是区分大小写的。Column_name值在**MySQL**3.22.12或以后版本是忽略大小写的。 l        权限列指出由一个表行授予的权限,即,可实施什么操作。服务器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规则在[5.7.6节,“访问控制, 阶段2:请求核实”](# "5.7.6. Access Control, Stage 2: Request Verification")描述。 范围列包含字符串,如下所述;每个列的默认值是空字符串: <table border="1" cellpadding="0" id="table11"><tr><td width="116"> <p><strong><span>列名</span></strong></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>类型</span></strong></p></td> </tr><tr><td width="116"> <p> <span>Host</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(60)</span></p></td> </tr><tr><td width="116"> <p> <span>User</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(16)</span></p></td> </tr><tr><td width="116"> <p> <span>Password</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(16)</span></p></td> </tr><tr><td width="116"> <p> <span>Db</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(64)</span></p></td> </tr><tr><td width="116"> <p> <span>Table_name</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(64)</span></p></td> </tr><tr><td width="116"> <p> <span>Column_name</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(64)</span></p></td> </tr><tr><td width="116"> <p> <span>Routine_name</span></p></td> <td width="69" style="width:51.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>CHAR(64)</span></p></td> </tr></table> 为了访问检查目的,Host值的比较对大小写不敏感。User、Password、Db和Table_name值对大小写敏感。Column_name值对大小写不敏感。 在user、db和host表中,所有权限列于单独的列内,被声明为ENUM('N','Y') DEFAULT 'N'。换句话说,每一个权限都可以被禁用和启用,并且 默认是禁用。 在tables_priv、columns_priv和procs_priv表中,权限列被声明为SET列。这些列的值可以包含该表控制的权限的组合: <table border="1" cellpadding="0" id="table12"><tr><td> <p><strong><span>表名</span></strong></p></td> <td> <p><strong><span>列名</span></strong></p></td> <td> <p><strong><span> 可能的设置元素</span></strong></p></td> </tr><tr><td> <p> <span>tables_priv</span></p></td> <td> <p> <span>Table_priv</span></p></td> <td> <p> <span>'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter'</span></p></td> </tr><tr><td> <p> <span>tables_priv</span></p></td> <td> <p> <span>Column_priv</span></p></td> <td> <p> <span>'Select', 'Insert', 'Update', 'References'</span></p></td> </tr><tr><td> <p> <span>columns_priv</span></p></td> <td> <p> <span>Column_priv</span></p></td> <td> <p> <span>'Select', 'Insert', 'Update', 'References'</span></p></td> </tr><tr><td> <p> <span>procs_priv</span></p></td> <td> <p> <span>Proc_priv</span></p></td> <td> <p> <span>'Execute', 'Alter Routine', 'Grant'</span></p></td> </tr></table> 简单地说,服务器使用这样的授权表: ·         user表范围列决定是否允许或拒绝到来的连接。对于允许的连接,user表授予的权限指出用户的全局(超级用户)权限。这些权限适用于服务器上的*all*数据库。 ·         db表范围列决定用户能从哪个主机存取哪个数据库。权限列决定允许哪个操作。授予的数据库级别的权限适用于数据库和它的表。 ·         当你想要一个给定的db表行应用于若干主机时,db和host表一起使用。例如,如果你想要一个用户能在你的网络从若干主机使用一个数据库,在用户的db表行的Host值设为空值,然后将那些主机的每一个移入host表。这个机制详细描述在[5.7.6节,“访问控制, 阶段2:请求核实”](# "5.7.6. Access Control, Stage 2: Request Verification")。 **注**释:host表不受GRANT和REVOKE语句的影响。大多数MySQL安装根本不需要使用该表。 ·         tables_priv和columns_priv表类似于db表,但是更精致:它们在表和列级应用而非在数据库级。授予表级别的权限适用于表和所有它的列。授予列级别的权限只适用于专用列。 ·         procs_priv表适用于保存的程序。授予程序级别的权限只适用于单个程序。 管理权限(例如RELOAD或SHUTDOWN等等)仅在user表中被指定。这是因为管理性操作是服务器本身的操作并且不是特定数据库,因此没有理由在其他授权表中列出这样的权限。事实上,只需要查询user表来决定你是否执行一个管理操作。 FILE权限也仅在user表中指定。它不是管理性权限,但你在服务器主机上读或写文件的能力与你正在存取的数据库无关。 当**mysqld**服务器启动时,将授权表的内容读入到内存中。你可以通过FLUSH PRIVILEGES语句或执行**mysqladmin flush-privileges**或**mysqladmin reload**命令让它重新读取表。对授权表的更改生效在[5.7.7节,“权限更改何时生效”](# "5.7.7. When Privilege Changes Take Effect")描述。 当你修改授权表的内容时,确保你按你想要的方式更改权限设置是一个好主意。要检查给定账户的权限,使用SHOW GRANTS语句。例如,要检查Host和User值分别为pc84.example.com和bob的账户所授予的权限,应通过语句:   mysql> **SHOW GRANTS FOR 'bob'@'pc84.example.com';** 一个有用的诊断工具是**mysqlaccess**脚本,由Carlier Yves 提供给**MySQL**分发。使用--help选项调用**mysqlaccess**查明它怎样工作。注意:**mysqlaccess**仅用user、db和host表检查存取。它不检查tables_priv、columns_priv或procs_priv表中指定的表、列和程序级权限。 对于诊断权限相关的问题的其它帮助,参见[5.7.8节,“拒绝访问错误的原因``”](# "5.7.8. Causes of Access denied Errors")。对于安全问题常规建议,参见[5.6节,“一般安全问题”](# "5.6. General Security Issues")。 ### 5.7.3. MySQL提供的权限 账户权限信息被存储在mysql数据库的user、db、host、tables_priv、columns_priv和procs_priv表中。在**MySQL**启动时并在[5.7.7节,“权限更改何时生效”](# "5.7.7. When Privilege Changes Take Effect")所说的情况时,服务器将这些数据库表内容读入内存。 GRANT和REVOKE语句所用的涉及权限的名称显示在下表,还有在授权表中每个权限的表列名称和每个权限有关的上下文。关于每个权限的含义相关的详细信息参见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。 <table border="1" cellpadding="0" style="margin-left: -.4pt" id="table13"><tr><td> <p><strong><span>权限</span></strong></p></td> <td> <p><strong><span>列</span></strong></p></td> <td> <p><strong><span> 上下文</span></strong></p></td> </tr><tr><td> <p> <span>CREATE</span></p></td> <td> <p> <span>Create_priv</span></p></td> <td> <p>数据库、表或索引</p></td> </tr><tr><td> <p> <span>DROP</span></p></td> <td> <p> <span>Drop_priv</span></p></td> <td> <p>数据库或表</p></td> </tr><tr><td> <p> <span>GRANT OPTION</span></p></td> <td> <p> <span>Grant_priv</span></p></td> <td> <p>数据库、表或保存的程序</p></td> </tr><tr><td> <p> <span>REFERENCES</span></p></td> <td> <p> <span>References_priv</span></p></td> <td> <p>数据库或表</p></td> </tr><tr><td> <p> <span>ALTER</span></p></td> <td> <p> <span>Alter_priv</span></p></td> <td> <p>表</p></td> </tr><tr><td> <p> <span>DELETE</span></p></td> <td> <p> <span>Delete_priv</span></p></td> <td> <p>表</p></td> </tr><tr><td> <p> <span>INDEX</span></p></td> <td> <p> <span>Index_priv</span></p></td> <td valign="top"> <p>表</p></td> </tr><tr><td> <p> <span>INSERT</span></p></td> <td> <p> <span>Insert_priv</span></p></td> <td valign="top"> <p>表</p></td> </tr><tr><td> <p> <span>SELECT</span></p></td> <td> <p> <span>Select_priv</span></p></td> <td valign="top"> <p>表</p></td> </tr><tr><td> <p> <span>UPDATE</span></p></td> <td> <p> <span>Update_priv</span></p></td> <td valign="top"> <p>表</p></td> </tr><tr><td> <p> <span>CREATE VIEW</span></p></td> <td> <p> <span>Create_view_priv</span></p></td> <td> <p>视图</p></td> </tr><tr><td> <p> <span>SHOW VIEW</span></p></td> <td> <p> <span>Show_view_priv</span></p></td> <td> <p>视图</p></td> </tr><tr><td> <p> <span>ALTER ROUTINE</span></p></td> <td> <p> <span>Alter_routine_priv</span></p></td> <td valign="top"> <p>保存的程序</p></td> </tr><tr><td> <p> <span>CREATE ROUTINE</span></p></td> <td> <p> <span>Create_routine_priv</span></p></td> <td valign="top"> <p>保存的程序</p></td> </tr><tr><td> <p> <span>EXECUTE</span></p></td> <td> <p> <span>Execute_priv</span></p></td> <td valign="top"> <p>保存的程序</p></td> </tr><tr><td> <p> <span>FILE</span></p></td> <td> <p> <span>File_priv</span></p></td> <td> <p>服务器主机上的文件访问</p></td> </tr><tr><td> <p> <span>CREATE TEMPORARY TABLES</span></p></td> <td> <p> <span>Create_tmp_table_priv</span></p></td> <td> <p>服务器管理</p></td> </tr><tr><td> <p> <span>LOCK TABLES</span></p></td> <td> <p> <span>Lock_tables_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>CREATE USER</span></p></td> <td> <p> <span>Create_user_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>PROCESS</span></p></td> <td> <p> <span>Process_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>RELOAD</span></p></td> <td> <p> <span>Reload_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>REPLICATION CLIENT</span></p></td> <td> <p> <span>Repl_client_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>REPLICATION SLAVE</span></p></td> <td> <p> <span>Repl_slave_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>SHOW DATABASES</span></p></td> <td> <p> <span>Show_db_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>SHUTDOWN</span></p></td> <td> <p> <span>Shutdown_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr><tr><td> <p> <span>SUPER</span></p></td> <td> <p> <span>Super_priv</span></p></td> <td valign="top"> <p>服务器管理</p></td> </tr></table> 当从早期的没有CREATE VIEW、SHOW VIEW、CREATE ROUTINE、ALTER ROUTINE和EXECUTE权限的版本的MySQL中升级时,要想使用这些权限,你必须使用MySQL分发提供的**mysql_fix_privilege_tables**脚本升级 授权表。参见[2.10.2节,“升级授权表”](# "2.10.2. Upgrading the Grant Tables")。 如果启用了二进制记录,要想创建或修改保存的程序,你还需要SUPER权限,详细描述见[20.4节,“存储子程序和触发程序的二进制日志功能”](# "20.4. Binary Logging of Stored Routines and Triggers")。 通过CREATE和DROP权限,你可以创建新数据库和表,或删除(移掉)已有数据库和表。*如果你将**mysql**数据库中的**DROP**权限授予某用户,用户可以删掉MySQL访问权限保存的数据库。* SELECT、INSERT、UPDATE和DELETE权限允许你在一个数据库现有的表上实施操作。 SELECT语句只有在他们真正从一个表中检索行时才需要SELECT权限。一些SELECT语句不访问表,甚至没有任何到服务器上的数据库里的存取任何东西的许可。例如,你可使用**mysql**客户端作为一个简单的计算器来评估未引用表的表达式: ~~~ mysql> SELECT 1+1; ~~~ ~~~ mysql> SELECT PI()*2; ~~~ INDEX权限允许你创建或删除索引。INDEX适用已有表。如果你具有某个表的CREATE权限,你可以在CREATE TABLE语句中包括索引定义。 通过ALTER权限,你可以使用ALTER TABLE来更改表的结构和重新命名表。 需要CREATE ROUTINE权限来创建保存的程序(函数和程序),ALTER ROUTINE权限来更改和删除保存的程序,EXECUTE来执行保存的程序。 GRANT权限允许你把你自己拥有的那些权限授给其他的用户。可以用于数据库、表和保存的程序。 FILE权限给予你用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句读和写服务器上的文件,任何被授予FILE权限的用户都能读或写**MySQL**服务器能读或写的任何文件。(说明用户可以读任何数据库目录下的文件,因为服务器可以访问这些文件)。 FILE权限允许用户在MySQL服务器具有写权限的目录下创建新文件。不能覆盖已有文件。 其余的权限用于管理性操作,它使用**mysqladmin**程序或SQL语句实施。下表显示每个管理性权限允许你执行的**mysqladmin**命令: <table border="1" cellpadding="0" style="margin-left: -.4pt" id="table14"><tr><td width="85" style="width:63.75pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span>权限</span></strong></p></td> <td width="886" style="width:664.2pt;padding:.75pt .75pt .75pt .75pt"> <p><strong><span> 权限拥有者允许执行的命令</span></strong></p></td> </tr><tr><td width="85" style="width:63.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>RELOAD</span></p></td> <td width="886" style="width:664.2pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>flush-hosts</span><span>, </span><span> flush-logs</span><span>, </span> <span> flush-privileges</span><span>, </span> <span> flush-status</span><span>, </span> <span> flush-tables</span><span>, </span> <span> flush-threads</span><span>, </span> <span>refresh</span><span>, </span><span> reload</span></p></td> </tr><tr><td width="85" style="width:63.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>SHUTDOWN</span></p></td> <td width="886" style="width:664.2pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>shutdown</span></p></td> </tr><tr><td width="85" style="width:63.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>PROCESS</span></p></td> <td width="886" style="width:664.2pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>processlist</span></p></td> </tr><tr><td width="85" style="width:63.75pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>SUPER</span></p></td> <td width="886" style="width:664.2pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>kill</span></p></td> </tr></table> reload命令告诉服务器将授权表重新读入内存。flush-privileges是reload的同义词,refresh命令清空所有表并打开并关闭记录文件,其它flush-*xxx*命令执行类似refresh的功能,但是范围更有限,并且在某些情况下可能更好用。例如,如果你只是想清空记录文件,flush-logs比refresh是更好的选择。 shutdown命令关掉服务器。只能从**mysqladmin**发出命令。没有相应的SQL语句。 processlist命令显示在服务器内执行的线程的信息(即其它账户相关的客户端执行的语句)。kill命令杀死服务器线程。你总是能显示或杀死你自己的线程,但是你需要PROCESS权限来显示或杀死其他用户和SUPER权限启动的线程。参见[13.5.5.3节,“KILL语法”](# "13.5.5.3. KILL Syntax")。 拥有CREATE TEMPORARY TABLES权限便可以使用CREATE TABLE语句中的关键字TEMPORARY。 拥有LOCK TABLES权限便可以直接使用LOCK TABLES语句来锁定你拥有SELECT权限的表。包括使用写锁定,可以防止他人读锁定的表。 拥有REPLICATION CLIENT权限便可以使用SHOW MASTER STATUS和SHOW SLAVE STATUS。 REPLICATION SLAVE权限应授予从服务器所使用的将当前服务器连接为主服务器的账户。没有这个权限,从服务器不能发出对主服务器上的数据库所发出的更新请求。 拥有SHOW DATABASES权限便允许账户使用SHOW DATABASE语句来查看数据库名。没有该权限的账户只能看到他们具有部分权限的数据库, 如果数据库用--skip-show-database选项启动,则根本不能使用这些语句。请注意全局权限指数据库的权限。 总的说来,只授予权限给需要他们的那些用户是好主意,但是你应该在授予FILE和管理权限时试验特定的警告: - FILE权限可以被滥用于将服务器主机上MySQL能读取的任何文件读入到数据库表中。包括任何人可读的文件和服务器数据目录中的文件。可以使用SELECT访问数据库表,然后将其内容传输到客户端上。 - GRANT权限允许用户将他们的权限给其他用户。有不同的权限并有GRANT权限的2个用户可以合并权限。 - ALTER权限可以用于通过重新命名表来推翻权限系统。 - SHUTDOWN权限通过终止服务器可以被滥用完全拒绝为其他用户服务。 - PROCESS权限能被用来察看当前执行的查询的明文文本,包括设定或改变密码的查询。 - SUPER权限能用来终止其它用户或更改服务器的操作方式。 - 授给mysql数据库本身的权限能用来改变密码和其他访问权限信息。密码被加密存储,所以恶意的用户不能简单地读取他们以知道明文密码。然而,具有user表Password列写访问权限的用户可以更改账户的密码,并可以用该账户连接MySQL服务器。 有一些事情你不能用**MySQL**权限系统做到: - 你不能明显地指定某个给定的用户应该被拒绝访问。即,你不能明显地匹配用户然后拒绝连接。 - 你不能指定用户有权创建立或删除数据库中的表,但不能创建或删除数据库本身。 ### 5.7.4. 与MySQL服务器连接 当你想要访问MySQL服务器时,MySQL客户端程序一般要求你指定参数: ·         MySQL服务器运行的主机名 ·         姓名 ·         密码 例如,可以从命令行按照下述提示启动**MySQL**客户端(用shell>表示): ~~~ shell> MySQL -h host_name -u user_name -pyour_pass ~~~ -h, -u和-p选项还可以采用形式--host=*host_name*、--user=*user_name*和--password=*your_pass*。请注意在-p或--password=和后面的密码之间*没有*空格**。 如果你使用-p或--password选项但没有指定密码值,客户端程序提示你输入密码。当你输入密码时并不显示密码。这比在在命令行输入密码要安全得多。系统上的任何用户可以通过命令**ps auxww**在命令行中指定密码。参见[5.8.6节,“使你的密码安全”](# "5.8.6. Keeping Your Password Secure")。 如果没有指定连接参数,MySQL客户端程序使用默认值: - 默认主机名是localhost。 - 默认用户名在Windows中是ODBC,在Unix中是你的Unix登录名。 ·         如果没有-p,则不提供密码。 这样, 对Unix用户joe,下列命令是等价的: ~~~ shell> MySQL -h localhost -u joe ~~~ ~~~ shell> MySQL -h localhost ~~~ ~~~ shell> MySQL -u joe ~~~ ~~~ shell> MySQL ~~~ 其它**MySQL**客户端程序类似。 当进行连接时,你可以指定要使用的不同的默认值,这样不必每次在你调用客户端程序是在命令行上输入它们。这可以有很多方法做到: - 你可以在选项文件的[client]小节里指定连接参数。文件的相关小节看上去可能像这样: ~~~ ·                [client] ~~~ ~~~ ·                host=host_name ~~~ ~~~ ·                user=user_name ~~~ ~~~ ·                password=your_pass ~~~ 在[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")中详细讨论了选项文件。 - 你可以用环境变量指定连接参数。主机可用MYSQL_HOST指定,**MySQL**用户名可用USER指定(仅对Windows和NetWare),密码可用MYSQL_PWD指定,尽管这不安全;参见[5.8.6节,“使你的密码安全”](# "5.8.6. Keeping Your Password Secure")。变量参见[附录F:](#)[*环境变量*](# "Appendix F. Environment Variables")。 ### 5.7.5. 访问控制, 阶段1:连接核实 当你试图连接**MySQL**服务器时,服务器基于你的身份以及你是否能通过供应正确的密码验证身份来接受或拒绝连接。如果不是,服务器完全拒绝你的访问,否则,服务器接受连接,然后进入阶段2并且等待请求。 你的身份基于2个信息: - 你从那个主机连接 - 你的**MySQL**用户名 身份检查使用3个user表(Host, User和Password)范围列执行。服务器只有在user表记录的Host和User列匹配客户端主机名和用户名并且提供了正确的密码时才接受连接。 在user表Host值的指定方法: - Host值可以是主机名或IP号,或'localhost'指出本地主机。 - 你可以在Host列值使用通配符字符“%”和“_”。 - Host值'%'匹配任何主机名,空Host值等价于'%'。它们的含义与LIKE操作符的模式匹配操作相同。例如,'%'的Host值与所有主机名匹配,而'%.mysql.com'匹配mysql.com域的所有主机。 ·         对于指定为IP号的Host值,你可以指定一个网络掩码,说明使用多少位地址位来评比网络号。例如: ~~~ ·                mysql> GRANT ALL PRIVILEGES ON db.* ~~~ ~~~ ·                    -> -> TO david@'192.58.197.0/255.255.255.0'; ~~~ 允许david从任何客户端用IP号client_ip来连接,下面的条件为真: ~~~ client_ip & netmask = host_ip ~~~ That is, for the GRANT statement just shown: ~~~ client_ip & 255.255.255.0 = 192.58.197.0 ~~~ 满足该条件并可以连接MySQL服务器的IP号的范围为192.58.197.0到192.58.197.255。 ·         注释:网络掩码只用来告诉服务器使用8、16、24或32位地址,例如: ~~~ ·                192.0.0.0/255.0.0.0(192 A类网络的任何地址) ~~~ ~~~ ·                192.168.0.0/255.255.0.0(192.168 A类网络的任何地址) ~~~ ~~~ ·                192.168.1.0/255.255.255.0(192.168.1 C类网络的任何地址) ~~~ ~~~ ·                192.168.1.1(只有该IP) ~~~ 下面的网络掩码(28 位)无效: ~~~ 192.168.0.1/255.255.255.240 ~~~ ·         db表记录中的空Host值表示它的权限应结合匹配客户端名的host表中的行使用。通过AND(相与)而不是或(联合)操作将权限组合到一起。你可以从[5.7.6节,“访问控制, 阶段2:请求核实”](# "5.7.6. Access Control, Stage 2: Request Verification")找到关于host表的详细信息。 其它grant表的空Host值与'%'相同。 既然你能在Host字段使用IP通配符值(例如,'144.155.166.%'匹配在一个子网上的每台主机),有可能某人可能企图探究这种能力,通过命名一台主机为144.155.166.somewhere.com。为了阻止这样的企图,**MySQL**不允许匹配以数字和一个点起始的主机名,这样,如果你用一个命名为类似1.2.foo.com的主机,它的名字决不会匹配授权表中的Host列。只有一个IP数字能匹配IP通配符值。 通配符字符在User列中不允许,但是你能指定空的值,它匹配任何名字。如果user表匹配的连接有一个空用户名,用户被认为是匿名用户(没有名字的用户),而非客户端实际指定的名字。这意味着一个空的用户名被用于在连接期间的进一步的访问检查(即,在阶段2期间)。 Password列可以是空的。这不是通配符,也不意味着匹配任何密码,它意味着用户必须不指定一个密码进行连接。 user表中的非空Password值代表加密的密码。**MySQL**不以任何人可以看的明文文本格式存储密码,相反,正在试图联接的用户提供的密码被加密(使用PASSWORD( )函数),在连接过程中使用加密的密码检查密码是否正确。(加密后的密码未通过连接即可实现)。从MySQL角度,加密的密码是实际密码,因此你不应让其它人访问它!特别是,绝对不要让非管理用户读mysql数据库中的表! MySQL 5.1使用强鉴定方法(最先在MySQL 4.1中适用)在前面的版本中在连接进程中的密码保护较好。即使TCP/IP包被截取或mysql数据库 被捕获也很安全。[5.7.9节,“MySQL 4.1中的密码哈希处理”](# "5.7.9. Password Hashing in MySQL 4.1")中详细讨论了密码加密。 下面的例子显示出各种user表中Host和User值的组合如何应用于到来的连接: <table border="0" cellpadding="0" width="100%" style="width: 100.0%" id="table15"><tr><td> <p> <span>Host</span><strong><span>值</span></strong></p></td> <td> <p> <span>User</span><strong><span>值</span></strong></p></td> <td> <p><strong><span> 被条目匹配的连接</span></strong></p></td> </tr><tr><td> <p> <span>'thomas.loc.gov'</span><span> </span></p></td> <td> <p> <span>'fred'</span><span> </span></p></td> <td> <p> <span>fred</span><span>, </span>从<span>thomas.loc.gov</span><span> </span>连接</p></td> </tr><tr><td> <p> <span>'thomas.loc.gov'</span><span> </span></p></td> <td> <p> <span>''</span><span> </span></p></td> <td> <p>任何用户<span>, </span>从<span>thomas.loc.gov</span>连接</p></td> </tr><tr><td> <p> <span>'%'</span><span> </span></p></td> <td> <p> <span>'fred'</span><span> </span></p></td> <td> <p> <span>fred</span><span>, </span>从任何主机连接</p></td> </tr><tr><td> <p> <span>'%'</span><span> </span></p></td> <td> <p> <span>''</span><span> </span></p></td> <td> <p>任何用户<span>, </span>从任何主机连接</p></td> </tr><tr><td> <p> <span>'%.loc.gov'</span><span> </span></p></td> <td> <p> <span>'fred'</span><span> </span></p></td> <td> <p> <span>fred</span><span>, </span>从在<span>loc.gov</span>域的任何主机连接</p></td> </tr><tr><td> <p> <span>'x.y.%'</span><span> </span></p></td> <td> <p> <span>'fred'</span><span> </span></p></td> <td> <p> <span>fred</span><span>, </span>从<span>x.y.net</span>、<span>x.y.com</span><span>,</span><span>x.y.edu</span>等联接。(这或许无用)</p></td> </tr><tr><td> <p> <span>'144.155.166.177'</span><span> </span></p></td> <td> <p> <span>'fred'</span><span> </span></p></td> <td> <p> <span>fred</span><span>, </span>从有<span>144.155.166.177</span><span> IP</span>地址的主机连接</p></td> </tr><tr><td> <p> <span>'144.155.166.%'</span><span> </span></p></td> <td> <p> <span>'fred'</span><span> </span></p></td> <td> <p> <span>fred</span><span>, </span>从<span>144.155.166 C</span>类子网的任何主机连接</p></td> </tr></table> 到来的连接中的客户端名和用户名可能与user表中的多行匹配。例如,由fred从thomas.loc.gov的连接匹配多个条目如上所述。 如果有多个匹配,服务器必须选择使用哪个条目。按照下述方法解决问题: l        服务器在启动时读入user表后进行排序。 l        然后当用户试图连接时,以排序的顺序浏览条目 l        服务器使用与客户端和用户名匹配的第一行。 user表排序工作如下,假定user表看起来像这样: ~~~ +-----------+----------+- ~~~ ~~~ | Host      | User     | … ~~~ ~~~ +-----------+----------+- ~~~ ~~~ | %         | root     | … ~~~ ~~~ | %         | jeffrey  | … ~~~ ~~~ | localhost | root     | … ~~~ ~~~ | localhost |          | … ~~~ ~~~ +-----------+----------+- ~~~ 当服务器读取表时,它首先以最具体的Host值排序。主机名和IP号是最具体的。'%'意味着“任何主机”并且是最不特定的。有相同Host值的条目首先以最具体的User值排序(空User值意味着“任何用户”并且是最不特定的)。最终排序的user表看起来像这样: ~~~ +-----------+----------+- ~~~ ~~~ | Host      | User     | … ~~~ ~~~ +-----------+----------+- ~~~ ~~~ | localhost | root     | … ... ~~~ ~~~ | localhost |          | … ... ~~~ ~~~ | %         | jeffrey  | … ... ~~~ ~~~ | %         | root     | … ... ~~~ ~~~ +-----------+----------+- ~~~ 当客户端试图连接时,服务器浏览排序的条目并使用找到的第一匹配。对于由jeffrey从localhost的连接,表内有两个条目匹配:Host和User值为'localhost'和''的条目,和值为'%'和'jeffrey'的条目。'localhost'条目首先匹配,服务器可以使用。 还有一个例子。假定user表看起来像这样: ~~~ +----------------+----------+- ~~~ ~~~ | Host           | User     | … ~~~ ~~~ +----------------+----------+- ~~~ ~~~ | %              | jeffrey  | … ~~~ ~~~ | thomas.loc.gov |          | … ~~~ ~~~ +----------------+----------+- ~~~ 排序后的表看起来像这样: ~~~ +----------------+----------+- ~~~ ~~~ | Host           | User     | … ~~~ ~~~ +----------------+----------+- ~~~ ~~~ | thomas.loc.gov |          | … ~~~ ~~~ | %              | jeffrey  | … ~~~ ~~~ +----------------+----------+- ~~~ 由jeffrey从thomas.loc.gov的连接与第一行匹配,而由jeffrey从whitehouse.gov的连接被第二个匹配。 普遍的误解是认为,对给定的用户名,当服务器试图对连接寻找匹配时,明确命名那个用户的所有条目将首先被使用。这明显不符合事实。先前的例子说明了这点,在那里由jeffrey从thomas.loc.gov的连接没被包含'jeffrey'作为User列值的行匹配,但是由没有用户名的题目匹配!结果是,jeffrey被鉴定为匿名用户,即使他连接时指定了用户名。 如果你能够连接服务器,但你的权限不是你期望的,你可能被鉴定为其它账户。要想找出服务器用来鉴定你的账户,使用CURRENT_USER()函数。它返回*user_name*@*host_name*格式的值,说明User和Host值匹配user表记录。假定jeffrey连接并发出下面的查询: ~~~ mysql> SELECT CURRENT_USER(); ~~~ ~~~ +----------------+ ~~~ ~~~ | CURRENT_USER() | ~~~ ~~~ +----------------+ ~~~ ~~~ | @localhost     | ~~~ ~~~ +----------------+ ~~~ 这儿显示的结果说明user表行有空的User列值。换句话说,服务器将jeffrey视为匿名用户。 诊断鉴定问题的另一个方法是打印出user表并且手动排序它看看第一个匹配在哪儿进行。又见[12.9.3节,“信息函数”](# "12.9.3. Information Functions")。 ### 5.7.6. 访问控制, 阶段2:请求核实 一旦你建立了连接,服务器进入访问控制的阶段2。对在此连接上进来的每个请求,服务器检查你想执行什么操作,然后检查是否有足够的权限来执行它。这正是在授权表中的权限列发挥作用的地方。这些权限可以来自user、db、host、tables_priv或columns_priv表。(你会发现参考[5.7.2节,“权限系统工作原理”](# "5.7.2. How the Privilege System Works")很有帮助,它列出了每个 授权表中呈现的列。) user表在全局基础上授予赋予你的权限,该权限不管当前的数据库是什么均适用。例如,如果user表授予你DELETE权限, 你可以删除在服务器主机上从任何数据库删除行!换句话说,user表权限是超级用户权限。只把user表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户,你应该把在user表中的权限设成'N'并且仅在特定数据库的基础上授权。你可以为特定的数据库、表或列授权。 db和host表授予数据库特定的权限。在这些表中的范围列的值可以采用以下方式: - 通配符字符“%”并“_”可用于两个表的Host和Db列。它们与用LIKE操作符执行的模式匹配操作具有相同的含义。如果授权时你想使用某个字符,必须使用反斜现引用。例如,要想在数据库名中包括下划线(‘_’),在GRANT语句中用‘\_’来指定。 - 在db表的'%'Host值意味着“任何主机”,在db表中空Host值意味着“对进一步的信息咨询host表”(本节后面将描述的一个过程)。 - 在host表的'%'或空Host值意味着“任何主机”。 - 在两个表中的'%'或空Db值意味着“任何数据库”。 - 在两个表中的空User值匹配匿名用户。 db和host表在服务器启动时被读取并排序(同时它读user表)。db表在Host、Db和User范围列上排序,并且host表在Host和Db范围列上排序。对于user表,首先根据最具体的值最后根据最不具体的值排序,并且当服务器寻找匹配条目时,它使用它找到的第一匹配。 tables_priv和columns_priv表授予表和列特定的权限。这些表的范围列的值可以如下被指定: - 通配符“%”并“_”可用在使用在两个表的Host列。 - 在两个表中的'%'或空Host意味着“任何主机”。 - 在两个表中的Db、Table_name和Column_name列不能包含通配符或空。 tables_priv和columns_priv表根据Host、Db和User列被排序。这类似于db表的排序,因为只有Host列可以包含通配符,排序更简单。 请求证实进程在下面描述。(如果你熟悉访问检查的源码,你会注意到这里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西;不同处只是使解释更简单。) 对需要管理权限的请求(SHUTDOWN、RELOAD等等),服务器仅检查user表条目,因为那是唯一指定管理权限的表。如果行许可请求的操作,访问被授权,否则拒绝。例如,如果你想要执行**mysqladmin shutdown**,但是由于user表行没有为你授予HUTDOWN权限,甚至不用检查db或host表就拒绝你的访问。(因为它们不包含hutdown_priv行列,没有这样做的必要。) 对数据库有关的请求(INSERT、UPDATE等等),服务器首先通过查找user表行来检查用户的全局(超级用户)权限。如果行允许请求的操作,访问被授权。如果在user表中全局权限不够,服务器通过检查db和host表确定特定的用户数据库权限: 1. 服务器在db表的Host、Db和User列上查找匹配。Host和User对应连接用户的主机名和**MySQL**用户名。Db列对应用户想要访问的数据库。如果没有Host和User的行,访问被拒绝。 1. 如果db表中有匹配的行而且它的Host列不是空的,该行定义用户的数据库特定的权限。 1. 如果匹配的db表的行的Host列是空的,它表示host表列举被允许访问数据库的主机。在这种情况下,在host表中作进一步查找以发现Host和Db列上的匹配。如果没有host表行匹配,访问被拒绝。如果有匹配,用户数据库特定的权限以在db和host表的行的权限,即在两个行都是'Y'的权限的交集(*而不是*并集!)计算。(这样你可以授予在db表行中的一般权限,然后用host表行按主机主机为基础有选择地限制它们。) 在确定了由db和host表行授予的数据库特定的权限后,服务器把他们加到由user表授予的全局权限中。如果结果允许请求的操作,访问被授权。否则,服务器检查在tables_priv和columns_priv表中的用户的表和列权限并把它们加到用户权限中。基于此结果允许或拒绝访问。 用布尔术语表示,前面关于用户权限如何计算的描述可以这样总结: ~~~ global privileges ~~~ ~~~ OR (database privileges AND host privileges) ~~~ ~~~ OR table privileges ~~~ ~~~ OR column privileges ~~~ 它可能不明显,为什么呢,如果全局user行的权限最初发现对请求的操作不够,服务器以后把这些权限加到数据库、表并列的特定权限。原因是请求可能要求超过一种类型的权限。例如,如果你执行INSERT INTO ... SELECT语句,你就需要INSERT和SELECT权限。你的权限必须是user表行授予一个权限而db表行授予另一个权限。在这种情况下,你有必要的权限执行请求,但是服务器不能自己把两个表区别开来;两个行授予的权限必须组合起来。 host表不受GRANT或REVOKE语句的影响,因此在大多数MySQL安装中没有使用。如果你直接修改它,你可以用于某种专门目的,例如用来维护安全服务器列表。例如,在TcX,host表包含在本地网络上所有的机器的表。这些表被授予所有的权限。 你也可以使用host表指定*不*安全的主机。假定你有一台机器public.your.domain,它位于你认为不安全的公共区域,你可以用下列的host表条目允许除了那台机器外的网络上所有主机的访问: ~~~ +--------------------+----+- ~~~ ~~~ | Host               | Db | ... ~~~ ~~~ +--------------------+----+- ~~~ ~~~ | public.your.domain | %  | ... (all privileges set to 'N') ~~~ ~~~ | %.your.domain      | %  | ... (all privileges set to 'Y') ~~~ ~~~ +--------------------+----+- ~~~ 当然,一定要测试授权表中的行(例如,使用SHOW GRANTS或**mysqlaccess**),确保你的访问权限实际按你期望的方式被设置。 ### 5.7.7. 权限更改何时生效 当mysqld启动时,所有授权表的内容被读进内存并且从此时生效。 当服务器注意到授权表被改变了时,现存的客户端连接有如下影响: - 表和列权限在客户端的下一次请求时生效。 - 数据库权限改变在下一个USE *db_name*命令生效。 ·         全局权限的改变和密码改变在下一次客户端连接时生效。 如果用GRANT、REVOKE或SET PASSWORD对授权表进行修改,服务器会注意到并立即重新将授权表载入内存。 如果你手动地修改授权表(使用INSERT、UPDATE或DELETE等等),你应该执行**mysqladmin flush-privileges**或**mysqladmin reload**告诉服务器再装载授权表,否则你的更改将*不会生效*,除非你重启服务器。 如果你直接更改了授权表但忘记重载,重启服务器后你的更改方生效。这样可能让你迷惑为什么你的更改没有什么变化! ### 5.7.8. 拒绝访问错误的原因`` 当你试着联接**MySQL**服务器时,如果碰到问题,下面各项可以帮助你纠正问题: ·         确保服务器在运行。如果服务器没有运行,则你不能连接服务器。如果你视图连接服务器并看到下述消息,可能是服务器没有运行: ~~~ ·                shell> mysql ~~~ ~~~ ·                ERROR 2003: Can't connect to MySQL server on 'host_name' (111) ~~~ ~~~ ·                shell> mysql ~~~ ~~~ ·                ERROR 2002: Can't connect to local MySQL server through socket ~~~ ~~~ ·                '/tmp/mysql.sock' (111) ~~~ 也可能服务器正在运行,但你可能使用与服务器上侦听的不一样的TCP/IP端口、命名管道或Unix套接字文件。你可以调用客户端程序,指定端口选项来指示正确的端口或套接字选项来指示正确的命名管道或Unix套接字文件。要找出套接字文件的地点,应: ~~~ shell> netstat -ln | grep mysql ~~~ - 必须正确设置授权表,以便服务器可以使用它们进行访问控制。对于某些分发版类型(例如Windows中的二进制分发版或Linux中的RPM分发版),安装过程初始化包含 授权表的mysql数据库。如果分发版没有这样做,你必须运行**mysql_install_db**脚本来手动初始化授权表。详细内容参见[2.9.2节,“Unix下安装后的过程”](# "2.9.2. Unix Post-Installation Procedures")。 确定是否要初始化授权表的一个方法是寻找数据目录下的mysql目录(数据目录名通常为data或var,位于MySQL安装目录下)。应保证**MySQL**数据库目录有文件“user.MYD”。否则,执行**mysql_install_db**脚本。运行并重启服务器后,执行该命令来测试初始权限: shell> **mysql -u root test** 服务器应该让你无误地连接。 - 在新的安装以后,你应该连接服务器并且设置你的用户及其访问许可: ~~~ ·                shell> mysql -u root mysql ~~~ 服务器应该让你连接,因为**MySQL**root用户初始时没有密码。那也是安全风险,当你正在设置其他**MySQL**用户时,也应设定root密码是一件重要的事请。关于设置初始密码的说明,参见[2.9.3节,“使初始MySQL账户安全”](# "2.9.3. Securing the Initial MySQL Accounts")。 - 如果你将一个现存的**MySQL**安装升级到较新的版本,运行了**mysql_fix_privilege_tables**脚本吗?如果没有,运行它。增加新功能后,授权表的结构可能会改变,因此更新后应确保表的结构随之更新。相关说明参见[2.10.2节,“升级授权表”](# "2.10.2. Upgrading the Grant Tables")。 ·         如果客户端程序试图连接时收到以下错误信息,说明服务器需要新格式的密码,而客户端不能生成: ~~~ ·                shell> mysql ~~~ ~~~ ·                Client does not support authentication protocol requested ~~~ ~~~ ·                by server; consider upgrading MySQL client ~~~ 关于如何处理的详细信息,参见[5.7.9节,“MySQL 4.1中的密码哈希处理”](# "5.7.9. Password Hashing in MySQL 4.1")和[A.2.3节,“客户端不支持鉴定协议”](# "A.2.3. Client does not support authentication protocol")。 - 如果你作为root试试连接并且得到这个错误,这意味着,你没有行在user表中的User列值为'root'并且mysqld不能为你的客户端解析主机名: - Access denied for user ''@'unknown' to database mysql 在这种情况下,你必须用--skip-grant-tables选项重启服务器并且编辑“/etc/hosts”或“\windows\hosts”文件为你的主机增加行。 - 如果你从3.22.11以前的版本更新现存的**MySQL**安装到3.22.11版或以后版本,你运行了mysql_fix_privilege_tables脚本吗?如果没有,运行它。在GRANT语句变得能工作时,授权表的结构用**MySQL** 3.22.11修改 。 ·         记住客户端程序使用选项文件或环境变量中指定的连接参数。如果客户端程序发送不正确的默认连接参数,而你没有在命令行中指定,检查环境变量和适用的选项文件。例如,当你不用任何选项运行客户端程序,得到Access denied错误,确保你没有在选项文件中指定旧密码! 你可以通过使用--no-defaults选项调用客户端程序来禁用选项文件。例如: ~~~ shell> mysqladmin --no-defaults -u root version ~~~ 客户端使用的选项文件见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。环境变量列于[附录F:*环境变量*](# "Appendix F. Environment Variables")。 ·         如果遇到下述错误,说明root密码错误: ~~~ ·                shell> mysqladmin -u root -pxxxx ver ~~~ ~~~ ·                Access denied for user 'root'@'localhost' (using password: YES) ~~~ 如果你未指定密码时出现前面的错误,说明某个选项文件中的密码不正确。试试前面所说的--no-defaults选项。 关于密码更改的信息参见[5.8.5节,“设置账户密码”](# "5.8.5. Assigning Account Passwords")。 如果你丢失或忘记root密码,你可以用--skip-grant-tables重启 **mysqld**来更改密码。参见[A.4.1节,“如何复位根用户密码”](# "A.4.1. How to Reset the Root Password"). ·         如果你使用SET PASSWORD、INSERT或UPDATE更改密码,你必须使用  PASSWORD()函数加密密码。如果你不使用PASSWORD()函数,密码不工作。例如,下面的语句设置密码,但没能加密,因此用户后面不能连接: ~~~ ·                mysql> SET PASSWORD FOR 'abe'@'host_name' = 'eagle'; ~~~ 相反,应这样设置密码: ~~~ mysql> SET PASSWORD FOR 'abe'@'host_name' = PASSWORD('eagle'); ~~~ 当你使用GRANT或CREATE USER语句或**mysqladmin password**命令指定密码时,不需要PASSWORD()函数,它们会自动使用PASSWORD()来加密密码。参见[5.8.5节,“设置账户密码”](# "5.8.5. Assigning Account Passwords")和[13.5.1.1节,“CREATE USER语法”](# "13.5.1.1. CREATE USER Syntax")。 ·         localhost是你本地主机名的一个同义词,并且也是如果你不明确地指定主机而客户端尝试连接的默认主机。 要想在这种系统上避免该问题,你可以使用--host=127.0.0.1选项来明确命名服务器主机。这样将通过TCP/IP协议来连接本地**mysqld服务器**。你还可以指定--host选项使用TCP/IP,使用实际的本机主机名。在这种情况下,主机名必须指定为服务器主机上的user表行,即使你在服务器上运行客户端程序。 ·         当尝试用mysql -u user_name与数据库连接时,如果你得到一个Access denied错误,可能会遇到与user表有关的问题,通过执行mysql -u root mysql并且执行下面的SQL语句进行检查: ~~~ ·                mysql> SELECT * FROM user; ~~~ 结果应该包含一个有Host和User列的行匹配你的计算机主机名和你的**MySQL**用户名。 - Access denied错误消息将告诉你,你正在用哪个用户尝试登录,你正在试图连接哪个主机,是否使用了密码。通常,你应该在user表中有一行,正确地匹配在错误消息给出的主机名和用户名。例如,如果遇到包含using password: NO的错误信息,说明你登录时没有密码。 ·         如果当你试着从一个不是**MySQL**服务器正在运行的主机上连接时,遇到下列错误,那么在user表中没有匹配那台主机的行: ~~~ ·                Host ... is not allowed to connect to this MySQL server ~~~ 可以通过组合你正在试图连接的用户/主机名设置一个账户来修正它。如果你不知道正连接的机器的IP号或主机名,应该把一个'%'行作为Host列值放在user表中。在试图从客户端器连接以后,通过SELECT USER()查询显示你如何真正进行连接。(然后用在日志文件上面显示出的实际的主机名代替user表中的'%'行。否则,你将得到一个不安全的系统,因为它允许从任何主机上以任何用户名连接。) 在Linux中,发生该错误的另一个原因可能是你正使用于你所使用版本的glibc库不同版本的库编译的二进制MySQL版本。在这种情况下,你应升级操作系统或glibc,或下载MySQL版本的源码分发版并自己编译。源码RPM一般很容易编译并安装,因此不是大问题。 ·         如果你连接时指定主机名,但得到错误消息主机名未显示或为IP号,表示当MySQL服务器将IP号解析为客户端来名时遇到错误: ~~~ ·                shell> mysqladmin -u root -pxxxx -h some-hostname ver ~~~ ~~~ ·                Access denied for user 'root'@'' (using password: YES) ~~~ 这表示DNS问题。要想修复,执行**mysqladmin flush-hosts**来重设内部 DNS主机名缓存。参见[7.5.6节,“MySQL如何使用DNS”](# "7.5.6. How MySQL Uses DNS")。 一些常用的解决方案包括: o        试试找出DNS服务器的错误并修复。 o        在MySQL授权表中指定IP号而不是主机名。 o        在/etc/hosts中放入客户端名。 o        用--skip-name-resolve选项启动**mysqld**。 o        用--skip-host-cache选项启动**mysqld**。 o        在Unix中,如果你在同一台机器上运行服务器和客户端,连接到localhost。连接到的localhost的Unix连接使用Unix套接字文件而不是TCP/IP。 o        在Windows中,你在同一台机器上运行服务器和客户端并且服务器支持命名管道连接,连接主机名(周期)。连接使用命名管道而不是TCP/IP。 - 如果mysql -u root test工作但是mysql -h your_hostname -u root test导致Access denied(*your_hostname*是本地机的实际主机名),那么在user表中可能没有你的主机的正确名字。这里的一个普遍的问题是在user表行中的Host值指定一个唯一的主机名,但是你系统的名字解析例程返回一个完全正规的域名(或相反)。例如,如果你在user表中有一个主机是'tcx'的行,但是你的DNS告诉**MySQL**你的主机名是'tcx.subnet.se',行将不工作。尝试把一个行加到user表中,它包含你主机的IP号作为Host列的值。(另外,你可以把一个行加到user表中,它有包含一个通配符如'tcx.%'的Host值。然而,使用以“%”结尾的主机名是*不安全的*并且*不*推荐!) - 如果mysql -u *user_name* test工作但是mysql -u *user_name**other_db_name*不工作,你没有为给定的用户授予*other_db_name*数据库的访问权限。 - 当在服务器上执行mysql -u *user_name*时,它工作,但是在其它远程客户端上执mysql -h *host_name* -u *user_name*时,它却不工作,你没有为给定的用户授予从远程主机访问服务器的权限。 - 如果你不能弄明白你为什么得到Access denied,从user表中删除所有Host包含通配符值的行(包含“%”或“_”的条目)。一个很普遍的错误是用Host='%'和User='*some_user*'插入一个新行,认为这将允许你指定localhost从同一台机器进行连接。它不工作的原因是 默认权限包括一个有Host='localhost'和User=''的行,因为那个行的Host值'localhost'比'%'更具体,当从localhost连接时,它用于指向新行!正确的步骤是插入Host='localhost'和User='*some_user*'的第2个行,或删除Host='localhost'和User=''行。删除条目后,记住用FLUSH PRIVILEGES语句重载授权表。 ·         如果你得到下列错误,可以与db或host表有关: ~~~ ·                Access to database denied ~~~ 如果从db表中选择了在Host列有空值的条目,保证在host表中有一个或多个相应的条目,指定db表中的条目适用哪些主机。 ·         如果你能够连接MySQL服务器,但如果在使用命令SELECT ... INTO OUTFILE或LOAD DATA INFILE语句时,你得到Access denied错误,在user表中的条目可能没有启用FILE权限。 ·         如果你直接更改授权表(例如,使用INSERT、UPDATE或DELETE语句)并且你的更改好像被忽略了,记住你必须执行FLUSH PRIVILEGES语句或**mysqladmin flush-privileges**命令让服务器来重读授权表。否则,直到服务器下次重启,你的更改方有效。记住用UPDATE命令更改root密码后,在清空权限前,你不需要指定新密码,因为服务器还不知道你已经更改了密码! ·         如果你的权限似乎在一个会话过程中改变了,可能是一个超级用户改变了他们。再次装入授权表会影响新客户端连接,但是它也影响现存的连接,如[5.7.7节,“权限更改何时生效”](# "5.7.7. When Privilege Changes Take Effect")小节所述。 ·         如果你有Perl、Python或ODBC程序的存取问题,试着用mysql -u *user_name**db_name*或mysql -u *user_name* -p*your_pass**db_name*与服务器连接。如果你能用**mysql**客户端进行连接,这是程序的一个问题而不是访问权限的问题。(注意在-p和密码之间没有空格;也可以使用--password=*your_pass*语法指定密码。如果使用-p选项,MySQL提示你输入密码。) ·         为了测试,用--skip-grant-tables选项启动**mysqld**守护进程,然后你可以改变**MySQL**授权表并且使用**mysqlaccess**脚本检查你的修改是否有如期的效果。当你对你的改变满意时,执行**mysqladmin flush-privileges**告诉**mysqld**服务器开始使用新的 授权表。(再次装入授权表覆盖了--skip-grant-tables选项。这允许你告诉服务器开始使用授权表,而不用停掉并重启它)。 ·         如果任何其它事情失败,用调试选项(例如,--debug=d,general,query)启动**mysqld**服务器。这将打印有关尝试连接的主机和用户信息,和发出的每个命令的信息。请参见[E.1.2节,“创建跟踪文件”](# "E.1.2. Creating Trace Files")。 ·         如果你有任何与**MySQL**授权表的其它问题,而且觉得你必须将这个问题发送到邮件表,一定要提供一个**MySQL**授权表的倾倒副本(dump)。你可用**mysqldump mysql**命令复制数据库表。象平时一样,用**mysqlbug**脚本邮寄你的问题。参见[1.7.1.3节,“如何通报缺陷和问题”](# "1.7.1.3. How to Report Bugs or Problems")。在一些情况下可以用--skip-grant-tables重启**mysqld**以便能运行**mysqldump**。   ### 5.7.9. MySQL 4.1中的密码哈希处理 [ 5.7.9.1. 更改应用程序密码哈希值的含义](#) MySQL用户账户列于mysql数据库中的user表内。每个MySQL账户指定一个密码,尽管保存在user表Password列的密码不是明文,但哈希值是从表中的记录计算的。用PASSWORD()函数来计算密码的哈希值。 MySQL在客户端/服务器通信的两个阶段使用密码: ·         如果客户端试图连接服务器,有一个初始鉴定步骤,客户必须提供一个密码,并且必须与客户想要使用的账户在user表保存的哈希值匹配。 ·         客户端连接后,它可以(如果有充分的权限) 设置或更改user表内所列的账户的密码哈希值值。客户端可以通过PASSWORD()函数来生成密码哈希值,或使用GRANT或SET PASSWORD语句。 换句话说,当客户端首次试图连接时,服务器使用哈希值进行鉴定。如果连接的客户端调用PASSWORD()函数或使用GRANT或SET语句来设置或更改密码,则服务器*产生*哈希值。 在MySQL 4.1中密码哈希算法已经更新,提供了更好的安全性并降低了密码被截取的风险。但是,该新机制只能在MySQL 4.1(和更新版本的)服务器和客户端中使用,会产生一些兼容性问题。4.1或新客户端可以连接4.1之前的服务器,因为客户端可以同时理解旧的和新的密码哈希机制。但是,4.1之前的客户端试图连接4.1版或更新版的服务器时会遇到困难。例如,3.23版**mysql**客户端试图连接5.1服务器时会失败并出现下面的错误消息: ~~~ shell> mysql -h localhost -u root ~~~ ~~~ Client does not support authentication protocol requested ~~~ ~~~ by server; consider upgrading MySQL client ~~~ 出现该问题的另一个普通例子是在升级到MySQL 4.1或更新版后,试图使用旧版本的PHP** mysql**扩展名。(参见[25.3.1节,“使用MySQL和PHP的常见问题”](# "25.3.1. Common Problems with MySQL and PHP"))。 下面讨论了新、旧密码机制之间的差别,以及如果你升级了服务器但需要为4.1版以前的客户端保持向后兼容性该怎样做。[A.2.3节,“客户端不支持鉴定协议”](# "A.2.3. Client does not support authentication protocol")中有更详细的信息。该信息将MySQL数据库从4.0版本或更低版升级到4.1版或更高版的PHP编程人员特别重要。 **注**释:该讨论对比了4.1版的行为和4.1前的行为,这儿描述的4.1中的行为实际上从4.1.1开始。MySQL 4.1.0是一个“旧”的发布,因为它的实施机制与4.1.1版和更新版中的稍有不同。在MySQL 5.0 参考手册中详细描述了4.1.0和最新版之间的差别。 在MySQL 4.1之前,用PASSWORD()函数计算的密码哈希值有16个字节长。应为: ~~~ mysql> SELECT PASSWORD('mypass'); ~~~ ~~~ +--------------------+ ~~~ ~~~ | PASSWORD('mypass') | ~~~ ~~~ +--------------------+ ~~~ ~~~ | 6f8c114b58f2ce9e   | ~~~ ~~~ +--------------------+ ~~~ 在MySQL 4.1之前,user表的Password列(保存了哈希值)也是16字节长。 在MySQL 4.1中,已经对PASSWORD()函数进行了修改,可以生成41字节的哈希值: ~~~ mysql> SELECT PASSWORD('mypass'); ~~~ ~~~ +-------------------------------------------+ ~~~ ~~~ | PASSWORD('mypass')                        | ~~~ ~~~ +-------------------------------------------+ ~~~ ~~~ | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 | ~~~ ~~~ +-------------------------------------------+ ~~~ 同样,user表的Password列必须有41字节长来保存这些值: ·         如果你新安装MySQL 5.1, Password列自动为41字节长。 ·         从MySQL 4.1(4.1.1或4.1系列的更新版)升级到MySQL 5.1,应不会出现相关问题,因为两个版本使用相同的密码哈希机制。如果你想要将更早版本的MySQL升级到MySQL5.1,你应先升级到4.1,然后将4.1升级到5.1。 加宽的Password列可以同时保存新、旧格式的密码哈希值。可以有两种方式确定任何给定格式的密码哈希值: ·         明显的不同之处是长度(16字节和41字节)。 ·         第2个不同之处是新格式的密码哈希值都以‘*’字符开头,而旧格式的密码绝对不是。  长密码哈希值具有更好的加密属性,并且客户端根据长哈希值进行鉴定比旧的短哈希值更加安全。 短密码哈希值和长密码哈希值之间的不同之处与服务器如何使用密码进行鉴定以及如何为执行密码更改操作的连接的客户端生成密码哈希值都有关。 服务器使用密码哈希值进行鉴定的方式受Password列的宽度影响: ·         如果列较短,只用短哈希鉴定。 ·         如果列较长,可以有短或长哈希值,并且服务器可以使用任何一种格式: o        4.1之前的客户端可以连接,它们只可以使用旧的哈希机制,它们可以只鉴定有短哈希的账户。 o        4.1及以后版本的客户端可以鉴定有短哈希或长哈希的账户。 对于短哈希账户的鉴定过程,4.1和以后版本的客户端比为旧版本的客户端实际要安全得多。从安全性角度,从最低安全到最安全的梯度为: ·         4.1之前的客户端用短密码哈希值进行鉴定 ·         4.1或以后版本的客户端用短密码哈希值进行鉴定 ·         4.1或以后版本的客户端用长密码哈希值进行鉴定 服务器为连接的客户端生成密码哈希值的方式受Password列宽度和--old-passwords选项的影响。4.1或更新版本的服务器只有满足某个条件才生成长哈希:Password列必须足够宽以容纳长哈希值并且未给定--old-passwords选项。这些条件适合: ·         Password列必须足够宽以容纳长哈希(41字节)值。如果列没有更新,仍然为4.1之前的16字节宽,当客户端使用PASSWORD()、GRANT或SET PASSWORD执行密码更改操作时,服务器注意到长哈希不适合,只生成短哈希。如果你已经升级到4.1但还没有运行 ** mysql_fix_privilege_tables**脚本来扩宽Password列时会出现这种行为。 ·         如果Password列足够宽,则可以保存短或长密码哈希值。在这种情况下,PASSWORD()、GRANT或SET PASSWORD生成长哈希,除非 用--old-passwords选项启动服务器。该选项强制服务器生成短密码哈希值。 --old-passwords选项的目的是当服务器生成长密码哈希值时,允许你维持同4.1之前的客户端的向后兼容性。该选项不影响鉴定(4.1和以后版本的客户端仍然可以使用有长密码哈希值的账户),但它防止在密码更改操作中在user表中创建长密码哈希值。在这种情况下,该账户不能再用于4.1之前的客户端。没有--old-passwords选项,可能会出现下面的不期望的情况: ·         旧客户端连接有短密码哈希值的账户。 ·         客户更改自己的密码。没有--old-passwords,可以为该账户生成长密码哈希值。 ·         下次旧客户试图连接账户时不能连接上,因为账户有长密码哈希值,需要新的哈希机制进行鉴定。(一旦账户user表中为长密码哈希值,只有4.1和以后版本的客户端可以鉴定它,因为4.1之前的客户端不理解长哈希)。 该场景说明,如果你必须支持旧的4.1之前的客户端,不使用--old-passwords选项运行4.1或更新版本的服务器很危险。用--old-passwords运行服务器,密码更改操作不会生成长密码哈希值,这样旧客户端也可以访问账户。(这些客户端不能意外地因更改了密码将自己锁出去,并留下长密码哈希值)。 --old-passwords选项的不利之处是你创建或更改的密码使用短哈希,甚至对于4.1客户端也如此。这样,你丢失了长密码哈希值提供的安全性。如果你想要创建有长哈希的账户(例如,为4.1客户端),你必须不使用--old-passwords来运行服务器。 下面的场景可用于运行4.1或以后的服务器,包括MySQL 5.1: **场景1:**user表中的短Password列: ·         只有短哈希可以保存到Password列。 ·         服务器只使用短哈希进行客户端鉴定。 ·         对于连接的客户端,调用PASSWORD()、GRANT或SET PASSWORD的密码哈希生成操作专使用短哈希。对账户的任何更改均会生成短密码哈希值。 ·          --old-passwords选项可以使用但是多余,因为Password列较短,服务器只生成短密码哈希值。 **场景2:**长Password列;没有用--old-passwords选项启动服务器: ·         短或长哈希可以保存到Password列。 ·         4.1和以后版本的客户端(包括5.1客户端)可以鉴定有短或长哈希的账户。 ·         4.1之前的客户端只能鉴定有短哈希的账户。 ·         对于连接的客户端,调用PASSWORD()、GRANT或SET PASSWORD的密码哈希生成操作专使用短哈希。对账户的任何更改均会生成短密码哈希值。 如前面所示,该场景的危险性在于4.1之前的客户端可能不能访问有短密码哈希值的账户。通过PASSWORD()、GRANT或SET PASSWORDA对这些账户密码的更改会产生长的密码哈希值。从该点看,4.1之前的客户端升级到4.1之前不能鉴定该账户。 要处理该问题,可以用特殊方法更改密码。例如,一般情况你可以使用SET PASSWORD按照下面的方法更改账户密码: ~~~ mysql> SET PASSWORD FOR 'some_user'@'some_host' = PASSWORD('mypass'); ~~~ 要想更改密码但创建短哈希,使用OLD_PASSWORD()函数: ~~~ mysql> SET PASSWORD FOR 'some_user'@'some_host' = OLD_PASSWORD('mypass'); ~~~ 当你想明显生成短哈希时,OLD_PASSWORD()很有用。 **场景3:**长Password列;用--old-passwords选项启动4.1或新版本的服务器: ·         短或长哈希可以保存到Password列。 ·         4.1和以后版本的客户端可以鉴定有短或长哈希的账户(请注意只有不使用--old-passwords选项启动服务器,方可以创建长哈希)。 ·         4.1之前的客户端只可以鉴定短哈希账户。 ·         对于连接的客户端,调用PASSWORD()、GRANT或SET PASSWORD的密码哈希生成操作专使用短哈希。对账户的任何更改均会生成短密码哈希值。 在该场景中,你不能创建长密码哈希值的账户,因为--old-passwords选项防止生成长哈希。并且,如果你在使用--old-passwords选项前创建长哈希账户,当--old-passwords有时更改账户密码,结果会使账户的密码为短密码,安全性较长哈希要降低。 这些场景的不利之处可以概括为: 在场景1中,你不能利用长哈希提供更安全的鉴定。 在场景2中, 如果你没有显式使用OLD_PASSWORD()来更改密码,则4.1之前的客户端不能再访问短哈希账户。 在场景3中,--old-passwords防止短哈希账户不可访问,但密码更改操作使账户的长哈希转换为短哈希,当--old-passwords有效时不能将它改回长哈希。 #### 5.7.9.1. 更改应用程序密码哈希值的含义 升级到MySQL4.1或更新版本后,使用PASSWORD()为自己的目的生成密码的应用程序会出现兼容性问题。应用程序实际不应这样做,因为PASSWORD()只应用来管理MySQL账户的密码。但一些应用程序使用PASSWORD()用于自己的目的。 如果你从MySQL 4.1之前的版本升级到4.1或以后版本,并在生成长密码哈希值的条件下运行服务器,应用程序使用PASSWORD()破解自己的密码。这种情况下推荐的方法是修改应用程序,使用其它函数,例如SHA1()或MD5(),来产生哈希值。如果不行,你可以使用OLD_PASSWORD()函数,该函数用来提供旧格式的短哈希。但是,请注意OLD_PASSWORD()可能有一天不再被支持。 如果服务器运行在生成短哈希的条件下,可以使用 OLD_PASSWORD()但与PASSWORD()等同。 将MySQL数据库从4.0或更低版本移植到4.1或更高版本的PHP编程人员应参阅[旧客户端](#)。 ### 5.8. MySQL用户账户管理 [ 5.8.1. MySQL用户名和密码](#)[ 5.8.2. 向MySQL增加新用户账户](#)[ 5.8.3. 从MySQL删除用户账户](#)[ 5.8.4. 限制账户资源](#)[ 5.8.5. 设置账户密码](#)[ 5.8.6. 使你的密码安全](#)[ 5.8.7. 使用安全连接](#) 本节描述如何为MySQL服务器的客户端设置账户。讨论了下面的主题: ·         MySQL使用的账户名和密码的含义,以及如何比较你的操作系统所使用的账户名和密码 ·         如何设置新账户并移除已有账户 ·         如何更改密码 ·         安全使用密码指导 ·         如何使用安全SSL连接 ### 5.8.1. MySQL用户名和密码 用用户名和客户端或主机定义MySQL账户,用户可以根据这些名称来连接服务器。账户也有密码。MySQL和操作系统使用用户名和密码的方式有几处区别: ·         MySQL用于鉴定目的用户名与Windows或Unix使用的用户名(登录名)没有关系。在Unix中,大多数MySQL客户端默认试图使用当前Unix的用户名作为MySQL用户名来登录,但这样只是为了方便。 默认值可以很容易被覆盖,因为客户端程序允许用-u或--user选项来指定用户名。因为这表示任何人可以试图使用任何用户名来连接服务器,除非所有MySQL账户有密码,否则你不能使数据库保持安全。通过为没有密码的账户指定用户名,任何人能够成功连接服务器。 ·         MySQL用户名最大客达16字符长。这样可以限制MySQL服务器和客户端之间的硬编码,并且防止通过修改mysql数据库中表的定义来偷窃密码。 **注**:你*应绝对不要以任何方式修改**mysql**数据库中的任何表,只能运行MySQL分发中专为此目的提供的脚本。将MySQL系统表重新定义为其它方式会导致未定义的(和不支持的!)行为*。 操作系统用户名与MySQL用户名完全不相关,甚至最大长度可能不同。例如, Unix用户名限制为8个字符。 ·         MySQL密码与登录到你的操作系统的密码没有关系。不需要将你用来登录Windows或Unix机器的密码和你用来访问该机器上的MySQL服务器的密码关联起来。 ·         MySQL的加密密码使用自己的算法。该加密算法不同于Unix登录过程使用的算法。MySQL密码加密与PASSWORD()SQL函数的方法相同。Unix密码加密与ENCRYPT()SQL函数的方法相同。PASSWORD()和ENCRYPT()函数的描述参见[12.9.2节,“加密函数”](# "12.9.2. Encryption Functions")。从版本4.1 起,MySQL使用更强的鉴定方法,同以前的版本相比可以在连接过程中提供更好的密码保护。即使TCP/IP包被截取或mysql数据库被捕获也很安全。(在前面的版本中,即使密码以加密形式保存到user表中,仍可以通过加密密码值来连接MySQL服务器)。 当安装MySQL时,授权表装载时有一系列初使账户。这些账户的名称和访问权限见[2.9.3节,“使初始MySQL账户安全”](# "2.9.3. Securing the Initial MySQL Accounts"),其中还讨论了如何未这些账户赋予密码。因此,你一般应使用GRANT和REVOKE语句来设置、修改和移除MySQL账户。参见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。 当用命令行客户端连接MySQL服务器时,你应为想要使用的账户指定用户名和密码: ~~~ shell> mysql --user=monty --password=guess db_name ~~~ 如果你想用较短的选项,命令应为: ~~~ shell> mysql -u monty -pguess db_name ~~~ -p选项和后面的密码值之间绝对不能有*空格*。参见[5.7.4节,“与MySQL服务器连接”](# "5.7.4. Connecting to the MySQL Server")。 前面的命令包括命令行中的密码值,会很危险。参见[5.8.6节,“使你的密码安全”](# "5.8.6. Keeping Your Password Secure")。要想避免,指定--password或-p选项后面不跟任何密码值: ~~~ shell> mysql --user=monty --password db_name ~~~ ~~~ shell> mysql -u monty -p db_name ~~~ 然后客户端程序输出提示符并等待你输入密码。(在这些示例中,*db_name*并不为密码,因为用空格将它同前面的密码项隔离开了)。 在一些系统中,MySQL用来提示输入密码的库调用自动将密码限制到8个字符。这是系统库的问题,而不是MySQL的问题。MySQL本身并不限制密码的长度。要解决该问题,将MySQL密码改为8个字符和更少字符的值,或将密码放入选项文件中。 ### 5.8.2. 向MySQL增加新用户账户 可以用两种方式创建MySQL账户: ·         使用GRANT语句 ·         直接操作MySQL授权表 最好的方法是使用GRANT语句,因为这样更精确,错误少。从MySQL 3.22.11起提供了GRANT;其语法见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。 创建账户的其它方法是使用MySQL账户管理功能的第三方程序。phpMyAdmin即是一个程序。 下面的示例说明如何使用**MySQL**客户端程序来设置新用户。假定按照[2.9.3节,“使初始MySQL账户安全”](# "2.9.3. Securing the Initial MySQL Accounts")描述的 默认值来设置权限。这说明为了更改,你必须以MySQL root用户连接MySQL服务器,并且root账户必须有mysql数据库的INSERT权限和RELOAD管理权限。 首先,使用**MySQL**程序以MySQL root用户来连接服务器: ~~~ shell> MySQL --user=root MySQL ~~~ 如果你为root账户指定了密码,还需要为该**MySQL**命令和本节中的其它命令提供--password或-p选项。 以root连接到服务器上后,可以添加新账户。下面的语句使用GRANT来设置四个新账户: ~~~ mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost' ~~~ ~~~     ->     IDENTIFIED BY 'some_pass' WITH GRANT OPTION; ~~~ ~~~ mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%' ~~~ ~~~     ->     IDENTIFIED BY 'some_pass' WITH GRANT OPTION; ~~~ ~~~ mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost'; ~~~ ~~~ mysql> GRANT USAGE ON *.* TO 'dummy'@'localhost'; ~~~ 用GRANT语句创建的账户有下面的属性: ·         其中两个账户有相同的用户名monty和密码some_pass。两个账户均为超级用户账户,具有完全的权限可以做任何事情。一个账户 ('monty'@'localhost')只用于从本机连接时。另一个账户('monty'@'%')可用于从其它主机连接。请注意monty的两个账户必须能从任何主机以monty连接。没有localhost账户,当monty从本机连接时,**mysql_install_db**创建的localhost的匿名用户账户将占先。结果是,monty将被视为匿名用户。原因是匿名用户账户的Host列值比'monty'@'%'账户更具体,这样在user表排序顺序中排在前面。(user表排序的讨论参见[5.7.5节,“访问控制, 阶段1:连接核实”](# "5.7.5. Access Control, Stage 1: Connection Verification"))。 ·         一个账户有用户名admin,没有密码。该账户只用于从本机连接。授予了RELOAD和PROCESS管理权限。这些权限允许admin用户执行**mysqladmin reload**、**mysqladmin refresh**和**mysqladmin flush-*****xxx***命令,以及**mysqladmin processlist**。未授予访问数据库的权限。你可以通过GRANT语句添加此类权限。 ·         一个账户有用户名dummy,没有密码。该账户只用于从本机连接。未授予权限。通过GRANT语句中的USAGE权限,你可以创建账户而不授予任何权限。它可以将所有全局权限设为'N'。假定你将在以后将具体权限授予该账户。 除了GRANT,你可以直接用INSERT语句创建相同的账户,然后使用FLUSH PRIVILEGES告诉服务器重载授权表: ~~~ shell> mysql --user=root mysql ~~~ ~~~ mysql> INSERT INTO user ~~~ ~~~     ->     VALUES('localhost','monty',PASSWORD('some_pass'), ~~~ ~~~     ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'); ~~~ ~~~ mysql> INSERT INTO user ~~~ ~~~     ->     VALUES('%','monty',PASSWORD('some_pass'), ~~~ ~~~     ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'); ~~~ ~~~ mysql> INSERT INTO user SET Host='localhost',User='admin', ~~~ ~~~     ->     Reload_priv='Y', Process_priv='Y'; ~~~ ~~~ mysql> INSERT INTO user (Host,User,Password) ~~~ ~~~     ->     VALUES('localhost','dummy',''); ~~~ ~~~ mysql> FLUSH PRIVILEGES; ~~~ 当你用INSERT创建账户时使用FLUSH PRIVILEGES的原因是告诉服务器重读授权表。否则,只有重启服务器后更改方会被注意到。使用 GRANT,则不需要使用FLUSH PRIVILEGES。 用INSERT使用PASSWORD()函数是为了加密密码。GRANT语句为你加密密码,因此不需要PASSWORD()。 'Y'值启用账户权限。对于admin账户,还可以使用更加可读的INSERT扩充的语法(使用SET)。 在为dummy账户的INSERT语句中,只有user表中的Host、User和Password列记录为指定的值。没有一个权限列为显式设置,因此MySQL将它们均指定为 默认值'N'。这样等同于GRANT USAGE的操作。 请注意要设置超级用户账户,只需要创建一个权限列设置为'Y'的user表条目。user表权限为全局权限,因此其它 授权表不再需要条目。 下面的例子创建3个账户,允许它们访问专用数据库。每个账户的用户名为custom,密码为obscure。 要想用GRANT创建账户,使用下面的语句: ~~~ shell> MySQL --user=root MySQL ~~~ ~~~ shell> mysql --user=root mysql ~~~ ~~~ mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ~~~ ~~~     ->     ON bankaccount.* ~~~ ~~~     ->     TO 'custom'@'localhost' ~~~ ~~~     ->     IDENTIFIED BY 'obscure'; ~~~ ~~~ mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ~~~ ~~~     ->     ON expenses.* ~~~ ~~~     ->     TO 'custom'@'whitehouse.gov' ~~~ ~~~     ->     IDENTIFIED BY 'obscure'; ~~~ ~~~ mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ~~~ ~~~     ->     ON customer.* ~~~ ~~~     ->     TO 'custom'@'server.domain' ~~~ ~~~     ->     IDENTIFIED BY 'obscure'; ~~~ 这3个账户可以用于: ·         第1个账户可以访问bankaccount数据库,但只能从本机访问。 ·         第2个账户可以访问expenses数据库,但只能从主机whitehouse.gov访问。 ·         第3个账户可以访问customer数据库,但只能从主机server.domain访问。 要想不用GRANT设置custom账户,使用INSERT语句直接修改 授权表: ~~~ shell> mysql --user=root mysql ~~~ ~~~ mysql> INSERT INTO user (Host,User,Password) ~~~ ~~~     ->     VALUES('localhost','custom',PASSWORD('obscure')); ~~~ ~~~ mysql> INSERT INTO user (Host,User,Password) ~~~ ~~~     ->     VALUES('whitehouse.gov','custom',PASSWORD('obscure')); ~~~ ~~~ mysql> INSERT INTO user (Host,User,Password) ~~~ ~~~     ->     VALUES('server.domain','custom',PASSWORD('obscure')); ~~~ ~~~ mysql> INSERT INTO db ~~~ ~~~     ->     (Host,Db,User,Select_priv,Insert_priv, ~~~ ~~~     ->     Update_priv,Delete_priv,Create_priv,Drop_priv) ~~~ ~~~     ->     VALUES('localhost','bankaccount','custom', ~~~ ~~~     ->     'Y','Y','Y','Y','Y','Y'); ~~~ ~~~ mysql> INSERT INTO db ~~~ ~~~     ->     (Host,Db,User,Select_priv,Insert_priv, ~~~ ~~~     ->     Update_priv,Delete_priv,Create_priv,Drop_priv) ~~~ ~~~     ->     VALUES('whitehouse.gov','expenses','custom', ~~~ ~~~     ->     'Y','Y','Y','Y','Y','Y'); ~~~ ~~~ mysql> INSERT INTO db ~~~ ~~~     ->     (Host,Db,User,Select_priv,Insert_priv, ~~~ ~~~     ->     Update_priv,Delete_priv,Create_priv,Drop_priv) ~~~ ~~~     ->     VALUES('server.domain','customer','custom', ~~~ ~~~     ->     'Y','Y','Y','Y','Y','Y'); ~~~ ~~~ mysql> FLUSH PRIVILEGES; ~~~ ~~~   ~~~ 前3个INSERT语句在user表中加入条目,允许用户custom从各种主机用给定的密码进行连接,但不授予全局权限(所有权限设置为 默认值'N')。后面3个INSERT语句在user表中加入条目,为custom授予bankaccount、expenses和customer数据库权限,但只能从合适的主机访问。通常若直接修改 授权表,则应告诉服务器用FLUSH PRIVILEGES重载授权表,使权限更改生效。 如果你想要让某个用户从给定域的所有机器访问(例如,mydomain.com),你可以在账户名的主机部分使用含‘%’通配符的GRANT语句: ~~~ mysql> GRANT ... ~~~ ~~~     ->     ON *.* ~~~ ~~~     ->     TO 'myname'@'%.mydomain.com' ~~~ ~~~     ->     IDENTIFIED BY 'mypass'; ~~~ 要想通过直接修改授权表来实现: ~~~ mysql> INSERT INTO user (Host,User,Password,...) ~~~ ~~~     ->     VALUES('%.mydomain.com','myname',PASSWORD('mypass'),...); ~~~ mysql> **FLUSH PRIVILEGES;** ### 5.8.3. 从MySQL删除用户账户 要想移除账户,应使用DROP USER语句,请参见[13.5.1.2节,“DROP USER语法”](# "13.5.1.2. DROP USER Syntax")。 ### 5.8.4. 限制账户资源 限制MySQL服务器资源使用的一个方法是将max_user_connections系统变量设置为非零值。但是,该方法严格限于全局,不允许管理具体账户。并且,它只限制使用单一账户同时连接的数量,而不是客户端连接后的操作。许多MySQL管理员对两种类型的控制均感兴趣,特别是Internet服务提供者。 在MySQL 5.1中,你可以为具体账户限制下面的服务器资源: ·         账户每小时可以发出的查询数 ·         账户每小时可以发出的更新数 ·         账户每小时可以连接服务器的次数 客户端可以执行的语句根据查询限制来记数。只有修改数据库或表的语句根据更新限制来记数。 还可以限制每个账户的同时连接服务器的连接数。 本文中的账户为user表中的单个记录。根据User和Host列值唯一识别每个账户。 做为使用该特性的先决条件,mysql数据库的user表必须包含资源相关的列。资源限制保存在max_questions、max_updates、max_connections和max_user_connections列内。如果user表没有这些列,必须对它进行升级;参见[2.10.2节,“升级授权表”](# "2.10.2. Upgrading the Grant Tables")。 要想用GRANT语句设置资源限制,使WITH子句来命名每个要限制的资源和根据每小时记数的限制值。例如,要想只以限制方式创建可以访问customer数据库的新账户,执行该语句: ~~~ mysql> GRANT ALL ON customer.* TO 'francis'@'localhost' ~~~ ~~~     ->     IDENTIFIED BY 'frank' ~~~ ~~~     ->     WITH MAX_QUERIES_PER_HOUR 20 ~~~ ~~~     ->          MAX_UPDATES_PER_HOUR 10 ~~~ ~~~     ->          MAX_CONNECTIONS_PER_HOUR 5 ~~~ ~~~     ->          MAX_USER_CONNECTIONS 2; ~~~ 限制类型不需要全部在WITH子句中命名,但已经命名的可以按任何顺序。每个每小时限制值均应为整数,代表每小时的记数。如果GRANT语句没有WITH子句,则每个限制值设置为 默认值零(即没有限制)。对于MAX_USER_CONNECTIONS,限制为整数,表示账户一次可以同时连接的最大连接数。如果限制设置为 默认值零,则根据MAX_USER_CONNECTIONS系统变量确定该账户可以同时连接的数量。 要想设置或更改已有账户的限制,在全局级别使用GRANT USAGE语句(在*.*)。下面的语句可以将francis的查询限制更改为100: ~~~ mysql> GRANT USAGE ON *.* TO 'francis'@'localhost' ~~~ ~~~     ->     WITH MAX_QUERIES_PER_HOUR 100; ~~~ 该语句没有改变账户的已有权限,只修改了指定的限制值。 要想取消已有限制,将该值设置为零。例如,要想取消francis每小时可以连接的次数的限制,使用该语句: ~~~ mysql> GRANT USAGE ON *.* TO 'francis'@'localhost' ~~~ ~~~     ->     WITH MAX_CONNECTIONS_PER_HOUR 0; ~~~ 当账户使用资源时如果有非零限制,则对资源使用进行记数。 服务器运行时,它统计每个账户使用资源的次数。如果账户在最后一个小时的连接次数达到限制,该账户的进一步的连接被拒绝。类似地,如果账户达到查询或更新次数的限制,进一步的查询或更新被拒绝。在这种情况下,会给出相关错误消息。 根据每个账户进行资源计算,而不是根据每个客户端。例如,如果你的账户的查询限制为50,你不能通过两个客户端同时连接服务器将限制增加到100。两个连接的查询被计算到一起。 可以为所有账户从全局重设当前的每小时资源使用记数,或单独重设给定的账户: ·         要想将所有账户当前的记数重设为零,可以执行FLUSH USER_RESOURCES语句。还可以通过重载授权表来重设记数(例如,使用FLUSH PRIVILEGES语句或**mysqladmin reload**命令)。 ·         将具体账户的限制重新授予任何值,可以将它设置为零。要想实现,按照前面所述使用GRANT USAGE,并将限制值指定为该账户当前的限制值。 计数器重设不影响MAX_USER_CONNECTIONS限制。 当服务器启动时所有记数从零开始。 ### 5.8.5. 设置账户密码 - 可以用**mysqladmin**命令在命令行指定密码: ~~~ shell> mysqladmin -u user_name -h host_name password "newpwd" ~~~ 该命令重设密码的账户为user表内匹配User列的*user_name*和Host列*你发起连接的*客户端的记录。 为账户赋予密码的另一种方法是执行SET PASSWORD语句: ~~~ mysql> SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit'); ~~~ 只有root等可以更新mysql数据库的用户可以更改其它用户的密码。如果你没有以匿名用户连接,省略FOR子句便可以更改自己的密码: ~~~ mysql> SET PASSWORD = PASSWORD('biscuit'); ~~~ 你还可以在全局级别使用GRANT USAGE语句(在*.*)来指定某个账户的密码而不影响账户当前的权限: ~~~ mysql> GRANT USAGE ON *.* TO 'jeffrey'@'%' IDENTIFIED BY 'biscuit'; ~~~ 一般情况下最好使用上述方法来指定密码,你还可以直接修改user表: ·         要想在创建新账户时建立密码,在Password列提供一个值: ~~~ ·                shell> mysql -u root mysql ~~~ ~~~ ·                mysql> INSERT INTO user (Host,User,Password) ~~~ ~~~ ·                     -> VALUES('%','jeffrey',PASSWORD('biscuit')); ~~~ ~~~ ·                mysql> FLUSH PRIVILEGES; ~~~ ~~~ ·                  ~~~ ·         要想更改已有账户的密码,使用UPDATE来设置Password列值: ~~~ ·                shell> mysql -u root mysql ~~~ ~~~ ·                 mysql> UPDATE user SET Password = PASSWORD('bagel') ~~~ ~~~ ·                       -> WHERE Host = '%' AND User = 'francis'; ~~~ ~~~ ·                mysql> FLUSH PRIVILEGES; ~~~ 当你使用SET PASSWORD、INSERT或UPDATE指定账户的密码时,必须用PASSWORD()函数对它进行加密。(唯一的特例是如果密码为空,你不需要使用PASSWORD())。需要使用PASSWORD()是因为user表以加密方式保存密码,而不是明文。如果你忘记了,你可能会象这样设置密码: ~~~ shell> mysql -u root mysql ~~~ ~~~ mysql> INSERT INTO user (Host,User,Password) ~~~ ~~~     -> VALUES('%','jeffrey','biscuit'); ~~~ ~~~ mysql> FLUSH PRIVILEGES; ~~~ ~~~   ~~~ 结果是密码'biscuit'保存到user表后没有加密。当jeffrey使用该密码连接服务器时,值被加密并同保存在user表中的进行比较。但是,保存的值为字符串'biscuit',因此比较将失败,服务器拒绝连接: ~~~ shell> mysql -u jeffrey -pbiscuit test ~~~ ~~~ Access denied ~~~ 如果你使用GRANT ... IDENTIFIED BY语句或**mysqladmin password**命令设置密码,它们均会加密密码。在这种情况下,不需要使用 PASSWORD()函数。 **注**释:PASSWORD()加密不同于Unix密码加密。参见[5.8.1节,“MySQL用户名和密码”](# "5.8.1. MySQL Usernames and Passwords")。 ### 5.8.6. 使你的密码安全 在管理级别,你决不能将mysql.user表的访问权限授予任何非管理账户。 当你运行客户端程序连接MySQL服务器时,以一种暴露的可被其他用户发现的方式指定你的密码是不妥当的。当你运行客户端程序时,你可以使用下列方法指定你的密码,还有每个方法的风险评估: ·         使用一个在命令行上-p*your_pass*或--password=*your_pass*的选项。例如: ~~~ ·                shell> mysql -u francis -pfrank db_name ~~~ 这很方便但是不安全,因为你的密码对系统状态程序(例如ps)变得可见,它可以被其他的用户调用来显示命令行。一般**MySQL**客户在他们的初始化顺序期间用零覆盖命令行参数,但是仍然有一个短暂间隔时间内参数值可见的。 ·         使用一个-p或--password选项(没有指定密码)。在这种情况下,客户端程序请求来自终端的密码: ~~~ ·                shell> mysql -u francis -p db_name ~~~ ~~~ ·                Enter password: ******** ~~~  “*”字符指示输入密码的地方。输入密码时密码看不见。 因为它对其他用户不可见,与在命令行上指定它相比,这样进入你的密码更安全。然而,这个输入一个密码的方法仅仅为你交互式运行程序是合适的。如果你想要从非交互式运行的一个脚本调用一个客户端,就没有从终端输入入密码的机会。在某些系统中,你甚至会发现脚本的第一行被(错误地)读并解释为你的密码! ·         在一个配置文件中存储你的密码。例如,在Unix中,你可在主目录的“.my.cnf”文件中的[client]节列出你的密码: ~~~ ·                [client] ~~~ ~~~ ·                password=your_pass ~~~ 如果你在“.my.cnf”里面存储密码,除了你本人其它人不能访问该文件。保证文件的访问模式是400或600。例如: ~~~ shell> chmod 600 .my.cnf ~~~ 关于选项文件的详细讨论参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。 ·         你可在MYSQL_PWD环境变量中存储密码。但是这种指定MySQL密码的方法是极不安全的,不应该使用。ps的某些版本包括显示运行进程的环境的选项;如果你设定MYSQL_PWD,你的密码将被运行**ps**的所有人看见,甚至在没有这样一个版本的ps的系统上,没有其它方法观察到进程环境的假设是不明智的。参见[附录F:*环境变量*](# "Appendix F. Environment Variables")。 总之,最安全的方法是让客户端程序提示输入密码或在适当保护的选项文件中指定密码。 ### 5.8.7. 使用安全连接 [ 5.8.7.1. SSL基本概念](#)[ 5.8.7.2. 需求(OpenSSL)](#)[ 5.8.7.3. 使用yaSSL](#)[ 5.8.7.4. 为MySQL设置SSL证书](#)[5.8.7.5. SSL GRANT 选项](#)[ 5.8.7.6. SSL命令行选项](#)[ 5.8.7.7. 用SSH以远程方式从Windows连接到MySQL](#) MySQL支持MySQL客户端和服务器之间的安全(加密的)连接所使用的安全套接字层(SSL)协议。本节讨论如何使用SSL连接。还描述了在Windows中设置SSH的方法。 MySQL的标准配置倾向于尽可能快,因此默认情况不使用加密连接。使用该协议会使客户端/服务器协议慢得多。对数据进行加密非常耗CPU,需要计算机多做许多工作,会延迟MySQL的其它任务。对于需要通过加密连接提供安全的应用程序,可以保证额外的计算。 MySQL允许在连接前启用加密。你可以根据具体应用程序的需求选择普通未加密连接或安全加密SSL连接。 #### 5.8.7.1. SSL基本概念 要想理解MySQL如何使用SSL,需要解释一些基本SSL和X509概念。熟悉的人们可以跳过该部分。 默认情况下,MySQL在客户端和服务器之间使用未加密的连接。这说明可以访问网络的部分人可以看到你的通信,并看到发送和接收的数据。他们甚至可以更改在客户端和服务器之间传递的数据。要想提高安全性,当调用客户端程序时,你可以通过--compress选项压缩客户端/服务器之间的通信。但是,这样并不能阻挡住顽固的攻击者。 当你需要以安全方式在网络中传递信息时,未加密的连接是不可接受的。加密是使任何数据不可读的方法。事实上,今天的许多惯例需要加密算法提供更加安全的要素。它们应能抵抗各种已知的攻击,例如更改加密消息的顺序或两次重放数据。 SSL是一种使用不同的加密算法确保从公用网接收到的数据是可信的协议。它具有检测数据更改、丢失或重放的机制。SSL还包括使用 X509标准提供身份认证的算法。 使用X509,可以识别Internet上的某些人。通常用于电子商务应用程序中。按照基本概念,应有某种称之为“认证机构”(或CA)的机构,可以向请求者分发电子证书。证书依赖非对称加密算法,有两个加密密钥(公共密钥和私人密钥)。认证持有者可以向其它方出示证书来证明身份。证书包括持有者的公共密钥。只能使用对应的私人密钥对含该公共密钥的加密数据进行解密,私人密钥由证书持有者拥有。 如果你需要关于SSL、X509、或加密的详细信息,使用Internet搜索引擎来搜索你感兴趣的关键字。 #### 5.8.7.2. 需求(OpenSSL) 要想在MySQL服务器和客户端程序之间使用SSL连接,系统必须能够支持OpenSSL。如果用支持内嵌式yaSSL的MySQL版本,不要读该节,但应阅读[5.8.7.3节,“使用yaSSL”](# "5.8.7.3. Using yaSSL")。 要想获得安全的MySQL连接,必须: 1.    安装OpenSSL库。我们已经测试了带OpenSSL 0.9.6的MySQL。如果你需要OpenSSL,请访问[http://www.openssl.org](http://www.openssl.org)。 2.    配置MySQL,用--with-vio和--with-openssl选项运行**configure**脚本。 3.    确保升级了授权表,使mysql.user表内包含SSL相关列。如果 授权表是从MySQL 4.0.0之前的版本升级,这很重要。升级过程见[2.10.2节,“升级授权表”](# "2.10.2. Upgrading the Grant Tables")。 4.    要想检查是否运行的**mysqld****服务器**支持OpenSSL,应检查have_openssl系统变量的值: ~~~ 5.            mysql> SHOW VARIABLES LIKE 'have_openssl'; ~~~ ~~~ 6.            +---------------+-------+ ~~~ ~~~ 7.            | Variable_name | Value | ~~~ ~~~ 8.            +---------------+-------+ ~~~ ~~~ 9.            | have_openssl  | YES   | ~~~ ~~~ 10.        +---------------+-------+ ~~~ 如果值为YES,服务器支持OpenSSL连接。 #### 5.8.7.3. 使用yaSSL 使用MySQL的内嵌式yaSSL支持,可以很容易地使用安全连接。不需要安装OpenSSL和执行[5.8.7.2节,“需求(OpenSSL)”](# "5.8.7.2. Requirements (OpenSSL)")中的步骤。并且,MySQL和yaSSL使用相同的许可模型。 当前,在以下平台上支持yaSSL: ·         Linux/x86-64 Red Hat Enterprise 3.0 ·         Linux RHAS21 Itanium-2,带gcc,静态链接 ·         Linux Itanium-2,带gcc ·         Windows 当从源码构建MySQL时如果你想要启用yaSSL,应这样配置MySQL: ~~~ ./configure --with-yassl=yes ~~~ 要想启动MySQL服务器支持yaSSL,使用支持OpenSSL的相同的选项,并识别建立安全连接需要的证书: ~~~ shell> mysqld --ssl-ca=cacert.pem \ ~~~ ~~~        --ssl-cert=server-cert.pem \ ~~~ ~~~        --ssl-key=server-key.pem ~~~ ·         --ssl-ca识别认证机构证书。 ·         --ssl-cert识别服务器证书。 ·         --ssl-key识别客户证书。 要想用yaSSL支持建立与MySQL服务器的安全连接,应这样启动客户端: ~~~ shell> mysql --ssl-ca=cacert.pem \ ~~~ ~~~        --ssl-cert=server-cert.pem \ ~~~ ~~~        --ssl-key=server-key.pem ~~~ 换句话说,选项与服务器的相同,并且认证机构证书必须相同。 要想从应用程序建立安全连接,调用mysql_real_connect()之前,应使用mysql_ssl_set()API函数来设置相应认证选项。参见[25.2.3.64节,“mysql_ssl_set()”](# "25.2.3.64. mysql_ssl_set()")。 #### 5.8.7.4. 为MySQL设置SSL证书 下面是一个为MySQ设置SSL证书的例子: ~~~ DIR=`pwd`/openssl ~~~ ~~~ PRIV=$DIR/private ~~~ ~~~   ~~~ ~~~ mkdir $DIR $PRIV $DIR/newcerts ~~~ ~~~ cp /usr/share/ssl/openssl.cnf $DIR ~~~ ~~~ replace ./demoCA $DIR -- $DIR/openssl.cnf ~~~ ~~~   ~~~ ~~~ # Create necessary files: $database, $serial and $new_certs_dir ~~~ ~~~ # directory (optional) ~~~ ~~~   ~~~ ~~~ touch $DIR/index.txt ~~~ ~~~ echo "01" > $DIR/serial ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Generation of Certificate Authority(CA) ~~~ ~~~ # ~~~ ~~~   ~~~ ~~~ openssl req -new -x509 -keyout $PRIV/cakey.pem -out $DIR/cacert.pem \ ~~~ ~~~     -config $DIR/openssl.cnf ~~~ ~~~   ~~~ ~~~ # Sample output: ~~~ ~~~ # Using configuration from /home/monty/openssl/openssl.cnf ~~~ ~~~ # Generating a 1024 bit RSA private key ~~~ ~~~ # ................++++++ ~~~ ~~~ # .........++++++ ~~~ ~~~ # writing new private key to '/home/monty/openssl/private/cakey.pem' ~~~ ~~~ # Enter PEM pass phrase: ~~~ ~~~ # Verifying password - Enter PEM pass phrase: ~~~ ~~~ # ----- ~~~ ~~~ # You are about to be asked to enter information that will be ~~~ ~~~ # incorporated into your certificate request. ~~~ ~~~ # What you are about to enter is what is called a Distinguished Name ~~~ ~~~ # or a DN. ~~~ ~~~ # There are quite a few fields but you can leave some blank ~~~ ~~~ # For some fields there will be a default value, ~~~ ~~~ # If you enter '.', the field will be left blank. ~~~ ~~~ # ----- ~~~ ~~~ # Country Name (2 letter code) [AU]:FI ~~~ ~~~ # State or Province Name (full name) [Some-State]:. ~~~ ~~~ # Locality Name (eg, city) []: ~~~ ~~~ # Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB ~~~ ~~~ # Organizational Unit Name (eg, section) []: ~~~ ~~~ # Common Name (eg, YOUR name) []:MySQL admin ~~~ ~~~ # Email Address []: ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Create server request and key ~~~ ~~~ # ~~~ ~~~ openssl req -new -keyout $DIR/server-key.pem -out \ ~~~ ~~~     $DIR/server-req.pem -days 3600 -config $DIR/openssl.cnf ~~~ ~~~   ~~~ ~~~ # Sample output: ~~~ ~~~ # Using configuration from /home/monty/openssl/openssl.cnf ~~~ ~~~ # Generating a 1024 bit RSA private key ~~~ ~~~ # ..++++++ ~~~ ~~~ # ..........++++++ ~~~ ~~~ # writing new private key to '/home/monty/openssl/server-key.pem' ~~~ ~~~ # Enter PEM pass phrase: ~~~ ~~~ # Verifying password - Enter PEM pass phrase: ~~~ ~~~ # ----- ~~~ ~~~ # You are about to be asked to enter information that will be ~~~ ~~~ # incorporated into your certificate request. ~~~ ~~~ # What you are about to enter is what is called a Distinguished Name ~~~ ~~~ # or a DN. ~~~ ~~~ # There are quite a few fields but you can leave some blank ~~~ ~~~ # For some fields there will be a default value, ~~~ ~~~ # If you enter '.', the field will be left blank. ~~~ ~~~ # ----- ~~~ ~~~ # Country Name (2 letter code) [AU]:FI ~~~ ~~~ # State or Province Name (full name) [Some-State]:. ~~~ ~~~ # Locality Name (eg, city) []: ~~~ ~~~ # Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB ~~~ ~~~ # Organizational Unit Name (eg, section) []: ~~~ ~~~ # Common Name (eg, YOUR name) []:MySQL server ~~~ ~~~ # Email Address []: ~~~ ~~~ # ~~~ ~~~ # Please enter the following 'extra' attributes ~~~ ~~~ # to be sent with your certificate request ~~~ ~~~ # A challenge password []: ~~~ ~~~ # An optional company name []: ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Remove the passphrase from the key (optional) ~~~ ~~~ # ~~~ ~~~   ~~~ ~~~ openssl rsa -in $DIR/server-key.pem -out $DIR/server-key.pem ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Sign server cert ~~~ ~~~ # ~~~ ~~~ openssl ca  -policy policy_anything -out $DIR/server-cert.pem \ ~~~ ~~~     -config $DIR/openssl.cnf -infiles $DIR/server-req.pem ~~~ ~~~   ~~~ ~~~ # Sample output: ~~~ ~~~ # Using configuration from /home/monty/openssl/openssl.cnf ~~~ ~~~ # Enter PEM pass phrase: ~~~ ~~~ # Check that the request matches the signature ~~~ ~~~ # Signature ok ~~~ ~~~ # The Subjects Distinguished Name is as follows ~~~ ~~~ # countryName           :PRINTABLE:'FI' ~~~ ~~~ # organizationName      :PRINTABLE:'MySQL AB' ~~~ ~~~ # commonName            :PRINTABLE:'MySQL admin' ~~~ ~~~ # Certificate is to be certified until Sep 13 14:22:46 2003 GMT ~~~ ~~~ # (365 days) ~~~ ~~~ # Sign the certificate? [y/n]:y ~~~ ~~~ # ~~~ ~~~ # ~~~ ~~~ # 1 out of 1 certificate requests certified, commit? [y/n]y ~~~ ~~~ # Write out database with 1 new entries ~~~ ~~~ # Data Base Updated ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Create client request and key ~~~ ~~~ # ~~~ ~~~ openssl req -new -keyout $DIR/client-key.pem -out \ ~~~ ~~~     $DIR/client-req.pem -days 3600 -config $DIR/openssl.cnf ~~~ ~~~   ~~~ ~~~ # Sample output: ~~~ ~~~ # Using configuration from /home/monty/openssl/openssl.cnf ~~~ ~~~ # Generating a 1024 bit RSA private key ~~~ ~~~ # .....................................++++++ ~~~ ~~~ # .............................................++++++ ~~~ ~~~ # writing new private key to '/home/monty/openssl/client-key.pem' ~~~ ~~~ # Enter PEM pass phrase: ~~~ ~~~ # Verifying password - Enter PEM pass phrase: ~~~ ~~~ # ----- ~~~ ~~~ # You are about to be asked to enter information that will be ~~~ ~~~ # incorporated into your certificate request. ~~~ ~~~ # What you are about to enter is what is called a Distinguished Name ~~~ ~~~ # or a DN. ~~~ ~~~ # There are quite a few fields but you can leave some blank ~~~ ~~~ # For some fields there will be a default value, ~~~ ~~~ # If you enter '.', the field will be left blank. ~~~ ~~~ # ----- ~~~ ~~~ # Country Name (2 letter code) [AU]:FI ~~~ ~~~ # State or Province Name (full name) [Some-State]:. ~~~ ~~~ # Locality Name (eg, city) []: ~~~ ~~~ # Organization Name (eg, company) [Internet Widgits Pty Ltd]:MySQL AB ~~~ ~~~ # Organizational Unit Name (eg, section) []: ~~~ ~~~ # Common Name (eg, YOUR name) []:MySQL user ~~~ ~~~ # Email Address []: ~~~ ~~~ # ~~~ ~~~ # Please enter the following 'extra' attributes ~~~ ~~~ # to be sent with your certificate request ~~~ ~~~ # A challenge password []: ~~~ ~~~ # An optional company name []: ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Remove a passphrase from the key (optional) ~~~ ~~~ # ~~~ ~~~ openssl rsa -in $DIR/client-key.pem -out $DIR/client-key.pem ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Sign client cert ~~~ ~~~ # ~~~ ~~~   ~~~ ~~~ openssl ca  -policy policy_anything -out $DIR/client-cert.pem \ ~~~ ~~~     -config $DIR/openssl.cnf -infiles $DIR/client-req.pem ~~~ ~~~   ~~~ ~~~ # Sample output: ~~~ ~~~ # Using configuration from /home/monty/openssl/openssl.cnf ~~~ ~~~ # Enter PEM pass phrase: ~~~ ~~~ # Check that the request matches the signature ~~~ ~~~ # Signature ok ~~~ ~~~ # The Subjects Distinguished Name is as follows ~~~ ~~~ # countryName           :PRINTABLE:'FI' ~~~ ~~~ # organizationName      :PRINTABLE:'MySQL AB' ~~~ ~~~ # commonName            :PRINTABLE:'MySQL user' ~~~ ~~~ # Certificate is to be certified until Sep 13 16:45:17 2003 GMT ~~~ ~~~ # (365 days) ~~~ ~~~ # Sign the certificate? [y/n]:y ~~~ ~~~ # ~~~ ~~~ # ~~~ ~~~ # 1 out of 1 certificate requests certified, commit? [y/n]y ~~~ ~~~ # Write out database with 1 new entries ~~~ ~~~ # Data Base Updated ~~~ ~~~   ~~~ ~~~ # ~~~ ~~~ # Create a my.cnf file that you can use to test the certificates ~~~ ~~~ # ~~~ ~~~   ~~~ ~~~ cnf="" ~~~ ~~~ cnf="$cnf [client]" ~~~ ~~~ cnf="$cnf ssl-ca=$DIR/cacert.pem" ~~~ ~~~ cnf="$cnf ssl-cert=$DIR/client-cert.pem" ~~~ ~~~ cnf="$cnf ssl-key=$DIR/client-key.pem" ~~~ ~~~ cnf="$cnf [mysqld]" ~~~ ~~~ cnf="$cnf ssl-ca=$DIR/cacert.pem" ~~~ ~~~ cnf="$cnf ssl-cert=$DIR/server-cert.pem" ~~~ ~~~ cnf="$cnf ssl-key=$DIR/server-key.pem" ~~~ ~~~ echo $cnf | replace " " ' ~~~ ~~~ ' > $DIR/my.cnf ~~~   要想测试SSL连接,按下面方法启动服务器,其中$DIR是示例my.cnf选项文件安装的路径名: ~~~ shell> MySQLd --defaults-file=$DIR/my.cnf & ~~~ 然后使用相同的选项文件调用客户端程序: ~~~ shell> MySQL --defaults-file=$DIR/my.cnf ~~~ 如果你有MySQL源码分发版,还可以修改前面的my.cnf文件来指向SSL目录中的示范证书和密钥文件来测试你的设置。 #### 5.8.7.5. SSL GRANT 选项 MySQL可以检查X509证书的属性和基于用户名和密码的通用鉴定方法。要想为MySQL账户指定SSL相关选项,使用GRANT语句的REQUIRE子句。参见[13.5.1.3节,“GRANT和REVOKE语法”](# "13.5.1.3. GRANT and REVOKE Syntax")。 有多种可能来限制一个账户的连接类型: ·         如果账户没有SSL或X509需求,如果用户名和密码合法,允许未加密的连接。但是,如果客户有正确的证书和密钥文件,在客户选项中可以使用加密连接。 ·         REQUIRE SSL选项限制服务器只允许该账户的SSL加密连接。请注意如果有ACL记录允许非SSL连接,该选项会被忽略。 ~~~ ·                  mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost' ~~~ ~~~ ·                     -> IDENTIFIED BY 'goodsecret' REQUIRE SSL; ~~~ ·         REQUIRE X509表示客户必须有合法证书但确切的证书、分发者和主体不重要。唯一的需求是应可以被某个CA认证机构验证它的签名。 ~~~ ·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost' ~~~ ~~~ ·                    -> IDENTIFIED BY 'goodsecret' REQUIRE X509; ~~~ ·         REQUIRE ISSUER 'issuer'限制连接企图,即客户必须出示CA 'issuer'签发的合法X509证书。如果客户出示了一个合法证书,但是是由不同的分发者签发,服务器拒绝连接。使用X509证书表示要加密,因此不需要SSL选项。 ~~~ ·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost' ~~~ ~~~ ·                    -> IDENTIFIED BY 'goodsecret' ~~~ ~~~ ·                    -> REQUIRE ISSUER '/C=FI/ST=Some-State/L=Helsinki/ ~~~ ~~~ ·                       O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com'; ~~~ 请注意ISSUER值应做为单一字符串输入。 ·         REQUIRE SUBJECT 'subject' 限制连接企图,即客户必须出示主题为'subject'的合法X509证书。如果客户出示了一个合法证书,但是有不同的主题,服务器拒绝连接。 ~~~ ·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost' ~~~ ~~~ ·                    -> IDENTIFIED BY 'goodsecret' ~~~ ~~~ ·                    -> REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/ ~~~ ~~~ ·                       O=MySQL demo client certificate/ ~~~ ~~~        CN=Tonu Samuel/Email=tonu@example.com'; ~~~ 请注意SUBJECT值应做为单一字符串输入。 ·         REQUIRE CIPHER 'cipher'用来确保使用足够强的密码和密钥长度。如果使用旧的短加密密钥算法,SSL本身可能很弱。使用该选项,我们可以索取确切的加密方法来连接。 ~~~ ·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost' ~~~ ~~~ ·                    -> IDENTIFIED BY 'goodsecret' ~~~ ~~~     -> REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA'; ~~~ 在REQUIRE子句中,可以结合使用SUBJECT、ISSUER和CIPHER选项: ~~~ mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost' ~~~ ~~~     -> IDENTIFIED BY 'goodsecret' ~~~ ~~~     -> REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/ ~~~ ~~~        O=MySQL demo client certificate/ ~~~ ~~~        CN=Tonu Samuel/Email=tonu@example.com' ~~~ ~~~     -> AND ISSUER '/C=FI/ST=Some-State/L=Helsinki/ ~~~ ~~~        O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com' ~~~ ~~~     -> AND CIPHER 'EDH-RSA-DES-CBC3-SHA'; ~~~ 请注意SUBJECT和ISSUER值应做为单一字符串输入。 在MySQL 5.1中,在REQUIRE选项之间可以选用AND关键字。 选项的顺序不重要,但任何选项不能用两次。 #### 5.8.7.6. SSL命令行选项 下面列出了规定SSL、证书文件和密钥文件使用的选项。它们可以位于命令行中或选项文件中。 ·         --ssl 对于服务器,该选项规定该服务器允许SSL连接。对于客户端程序,它允许客户使用SSL连接服务器。单单该选项不足以使用SSL连接。还必须指定--ssl-ca、--ssl-cert和--ssl-key选项。 通常从反向使用该选项表示不应使用SSL。要想实现,将选项指定为--skip-ssl或--ssl=0。 请注意使用--ssl不*需要*SSL连接。例如,如果编译的服务器或客户不支持SSL,则使用普通的未加密的连接。 确保使用SSL连接的安全方式是使用含REQUIRE SSL子句的GRANT语句在服务器上创建一个账户。然后使用该账户来连接服务器,服务器和客户端均应启用SSL支持。 ·         --ssl-ca=*file_name* 含可信SSL CA的清单的文件的路径。 ·         --ssl-capath=*directory_name* 包含pem格式的可信SSL CA证书的目录的路径。 ·         --ssl-cert=*file_name* SSL证书文件名,用于建立安全连接。 ·         --ssl-cipher=*cipher_list* 允许的用于SSL加密的密码的清单。*cipher_list*的格式与OpenSSL ciphers命令相同。 示例:--ssl-cipher=ALL:-AES:-EXP ·         --ssl-key=*file_name* SSL密钥文件名,用于建立安全连接。 #### 5.8.7.7. 用SSH以远程方式从Windows连接到MySQL 本节说明如何用SSH安全连接到远程MySQL服务器(David Carlson <[dcarlson@mplcomm。com](#)>): 1.    在Windows主机上安装SSH客户端。作为用户,我所发现的最好的非免费客户端来自[http://www.vandyke.com/](http://www.vandyke.com/)的SecureCRT。另一个选则是[http://www.f-secure.com/](http://www.f-secure.com/)的f-secure。你还可以从[http://directory.google.com/Top/Computers/Security/Products_and_Tools/Cryptography/SSH/Clients/Windows/](http://directory.google.com/Top/Computers/Security/Products_and_Tools/Cryptography/SSH/Clients/Windows/)的Google找到一些免费客户端。 2.    启动Windows SSH客户端。设置Host_Name = yourmysqlserver_URL_or_IP。设置userid=your_userid以便登录服务器。此userid值可以与你的MySQL账户的用户名不相同。 3.    设置端口映射。可以进行远程映射(设置local_port: 3306, remote_host: yourmysqlservername_or_ip, remote_port: 3306)或本地映射(设置port: 3306, host: localhost, remote port: 3306)。 4.    进行保存,否则下次需要重设。 5.    刚创建的SSH会话登录服务器。 6.    在Windows机器上启动相应ODBC应用程序(例如Access)。 7.    在Windows中创建一个新的文件按照常用方法通过ODBC驱动程序链接MySQL,不同的是要为MySQL服务器输入localhost,而不是yourmysqlservername。 你应有使用SSH加密的ODBC连接到MySQL。 ### 5.9. 备份与恢复 [ 5.9.1. 数据库备份](#)[ 5.9.2. 示例用备份与恢复策略](#)[ 5.9.3. 自动恢复](#)[ 5.9.4. 表维护和崩溃恢复](#)[ 5.9.5. myisamchk:MyISAM表维护实用工具](#)[ 5.9.6. 建立表维护计划](#)[ 5.9.7. 获取关于表的信息](#) 本节讨论如何进行数据库备份(完全备份和增量备份),以及如何执行表的维护。本节描述的SQL语句语法参见[第5章:](#)[*数据库管理*](# "Chapter 5. Database Administration")。此处提供的大多数信息主要适合MyISAM表。InnoDB备份程序参见[15.2.8节,“InnoDB数据库的备份和恢复``”](# "15.2.8. Backing Up and Recovering an InnoDB Database")。 ### 5.9.1. 数据库备份 因为MySQL表保存为文件方式,很容易备份。要想保持备份的一致性,对相关表执行LOCK TABLES操作,然后对表执行FLUSH TABLES。参见[13.4.5节,“LOCK TABLES和UNLOCK TABLES语法”](# "13.4.5. LOCK TABLES and UNLOCK TABLES Syntax")和[13.5.5.2节,“FLUSH语法”](# "13.5.5.2. FLUSH Syntax")。你只需要读锁定;这样当你复制数据库目录中的文件时,允许其它客户继续查询表。需要FLUSH TABLES语句来确保开始备份前将所有激活的索引页写入硬盘。 如果你想要进行SQL级别的表备份,你可以使用SELECT INTO ...OUTFILE或BACKUP TABLE。对于SELECT INTO ...OUTFILE, 输出的文件不能先存在。对于BACKUP TABLE也如此,因为覆盖完整的文件会有安全风险。参见[13.2.7节,“SELECT语法”](# "13.2.7. SELECT Syntax")和[13.5.2.2节,“BACKUP TABLE语法”](# "13.5.2.2. BACKUP TABLE Syntax")。 备份数据库的另一个技术是使用**mysqldump**程序或**mysqlhotcopy****脚本**。参见[8.8节,“mysqldump:数据库备份程序”](# "8.8. mysqldump — A Database Backup Program")和[8.9节,“mysqlhotcopy:数据库备份程序”](# "8.9. mysqlhotcopy — A Database Backup Program")。 1.    完全备份数据库: ~~~ 2.            shell> mysqldump --tab=/path/to/some/dir --opt db_name ~~~ 或: ~~~ shell> mysqlhotcopy db_name /path/to/some/dir ~~~ 只要服务器不再进行更新,还可以只复制所有表文件(*.frm、*.MYD和*.MYI文件)。**mysqlhotcopy**脚本使用该方法。(但请注意如果数据库包含InnoDB表,这些方法不工作。InnoDB不将表的内容保存到数据库目录中,**mysqlhotcopy**只适合MyISAM表)。 3.    如果**mysqld**在运行则停止,然后用--log-bin[=file_name]选项来启动。参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。二进制日志文件中提供了  执行**mysqldump**之后对数据库的更改进行复制所需要的信息。 对于InnoDB表,可以进行在线备份,不需要对表进行锁定;参见[8.8节,“mysqldump:数据库备份程序”](# "8.8. mysqldump — A Database Backup Program")。 MySQL支持增量备份:需要用--log-bin选项来启动服务器以便启用二进制日志;参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。当想要进行增量备份时(包含上一次完全备份或增量备份之后的所有更改),应使用FLUSH LOGS回滚二进制日志。然后,你需要将从最后的完全或增量备份的某个时刻到最后某个点的所有二进制日志复制到备份位置。这些二进制日志为增量备份;恢复时,按照下面的解释应用。下次进行完全备份时,还应使用FLUSH LOGS或mysqlhotcopy --flushlogs回滚二进制日志。参见[8.8节,“mysqldump:数据库备份程序”](# "8.8. mysqldump — A Database Backup Program")和[8.9节,“mysqlhotcopy:数据库备份程序”](# "8.9. mysqlhotcopy — A Database Backup Program")。 如果MySQL服务器为从复制服务器,则无论选择什么备份方法,当备份从机数据时,还应备份master.info和relay-log.info文件。恢复了从机数据后,需要这些文件来继续复制。如果从机执行复制LOAD DATA INFILE命令,你应还备份用--slave-load-tmpdir选项指定的目录中的SQL_LOAD-*文件。(如果未指定,该位置默认为tmpdir变量值)。从机需要这些文件来继续复制中断的LOAD DATA INFILE操作。 如果必须恢复MyISAM表,先使用REPAIR TABLE或**myisamchk -r**来恢复。99.9%的情况下该方法可以工作。如果**myisamchk**失败,试试下面的方法。请注意只有用--log-bin选项启动了MySQL从而启用二进制日志它才工作;参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。 1.    恢复原**mysqldump**备份,或二进制备份。 2.    执行下面的命令重新更新二进制日志: ~~~ 3.            shell> mysqlbinlog hostname-bin.[0-9]* | mysql ~~~ 在某些情况下,你可能只想要从某个位置重新运行某些二进制日志。(通常你想要从恢复备份的日期重新运行所有二进制日志,查询不正确时例外)。关于**mysqlbinlog**工具和如何使用它的详细信息参见[8.6节,“mysqlbinlog:用于处理二进制日志文件的实用工具”](# "8.6. mysqlbinlog — Utility for Processing Binary Log Files")。 还可以对具体文件进行选择备份: ·         要想复制表,使用SELECT * INTO OUTFILE '*file_name*' FROM *tbl_name*。 ·         要想重载表,使用LOAD DATA INFILE 'file_name' REPLACE ...并恢复。要避免复制记录,表必须有PRIMARY KEY或一个UNIQUE索引。当新记录复制唯一键值的旧记录时,REPLACE关键字可以将旧记录替换为新记录。 如果备份时遇到服务器性能问题,可以有帮助的一个策略是在从服务器而不是主服务器上建立复制并执行备份。参见[6.1节,“复制介绍”](# "6.1. Introduction to Replication")。 如果使用Veritas文件系统,可以这样备份: 1.    从客户端程序执行FLUSH TABLES WITH READ LOCK。 2.    从另一个shell执行mount vxfs snapshot。 3.    从第一个客户端执行UNLOCK TABLES。 4.    从快照复制文件。 5.    卸载快照。 ### 5.9.2. 示例用备份与恢复策略 [ 5.9.2.1. 备份策略](#)[ 5.9.2.2. 为恢复进行备份](#)[ 5.9.2.3. 备份策略摘要](#) 本节讨论进行备份的程序,在出现崩溃后,可以恢复数据: ·         操作系统崩溃 ·         电源故障 ·         文件系统崩溃 ·         硬件问题(硬盘、母板等等) 该命令不包括**mysqldump**和**mysql**程序的--user和—password等选项。应包括必要的选项让MySQL服务器允许你连接它。 我们假定数据保存在MySQL的InnoDB存储引擎中,支持事务和自动崩溃恢复。我们假定崩溃时MySQL服务器带负载。如果不带负载,则不需要恢复。 出现操作系统崩溃或电源故障时,我们可以假定重启后硬盘上的MySQLś数据仍可用。由于崩溃,InnoDB数据文件中的数据可能不再保持一致性,但InnoDB读取它的日志并会查到挂起的提交的和未提交的事务清单,它们没有清空到数据文件中。InnoDB自动卷回未提交的事务,并清空到它的数据文件中。通过MySQL错误日志将该恢复过程相关信息传达给用户。下面的例子为日志摘录: ~~~ InnoDB: Database was not shut down normally. ~~~ ~~~ InnoDB: Starting recovery from log files... ~~~ ~~~ InnoDB: Starting log scan based on checkpoint at ~~~ ~~~ InnoDB: log sequence number 0 13674004 ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 13739520 ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 13805056 ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 13870592 ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 13936128 ~~~ ~~~ ... ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 20555264 ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 20620800 ~~~ ~~~ InnoDB: Doing recovery: scanned up to log sequence number 0 20664692 ~~~ ~~~ InnoDB: 1 uncommitted transaction(s) which must be rolled back ~~~ ~~~ InnoDB: Starting rollback of uncommitted transactions ~~~ ~~~ InnoDB: Rolling back trx no 16745 ~~~ ~~~ InnoDB: Rolling back of trx no 16745 completed ~~~ ~~~ InnoDB: Rollback of uncommitted transactions completed ~~~ ~~~ InnoDB: Starting an apply batch of log records to the database... ~~~ ~~~ InnoDB: Apply batch completed ~~~ ~~~ InnoDB: Started ~~~ ~~~ mysqld: ready for connections ~~~ 如果文件系统崩溃或出现硬件问题,我们可以假定重启后硬盘上的MySQLś数据不可用。这说明MySQL未能成功启动,因为一些硬盘数据块不再可读。在这种情况下,需要重新格式化硬盘,安装一个新的,或纠正问题。然后需要从备份中恢复MySQL数据,这说明我们必须先做好备份。要想确保,应及时返回并设计备份策略。 #### 5.9.2.1. 备份策略 我们都知道必须按计划定期进行备份。可以用几个工具完全备份(在某个时间点的数据快照)MySQL。例如,InnoDB Hot Backup为InnoDB数据文件提供在线非数据块物理备份,**mysqldump**提供在线逻辑备份。这里使用**mysqldump**。 假定我们在星期日下午1点进行了备份,此时负荷较低。下面的命令可以完全备份所有数据库中的所有InnoDB表: ~~~ shell> mysqldump --single-transaction --all-databases > backup_sunday_1_PM.sql ~~~ 这是在线非块备份,不会干扰对表的读写。我们以前假定我们的表为InnoDB表,因此--single-transaction使用一致性地读,并且保证**mysqldump**所看见的数据不会更改。(其它客户端对InnoDB表进行的更改不会被**mysqldump**进程看见)。如果我们还有其它类型的表,我们必须假定在备份过程中它们不会更改。例如,对于mysql数据库中的MyISAM表,我们必须假定在备份过程中没有对MySQL账户进行管理更改。 **mysqldump**命令产生的.sql文件包含一系列SQL INSERT语句,可以用来重载转储的表。 需要进行完全备份,但有时不方便。会产生大的备份文件并需要花时间来生成。从某个角度,完全备份并不理想,因为每个成功的完全备份包括所有数据,甚至自从上一次完全备份以来没有更改的部分。完成了初使完全备份后,进行增量备份会更有效。这样备份文件要小得多,备份时间也较短。不利之处是,恢复时不能只重载完全备份来恢复数据。还必须要用增量备份来恢复增量更改。 要想进行增量备份,我们需要保存增量更改。应使用--log-bin选项启动MySQL服务器,以便更新数据时将这些更改保存到文件中。该选项启用二进制日志,因此服务器写将每个更新数据的SQL语句写入MySQL二进制日志。让我们看看用--log-bin选项启动的已经运行多日的MySQL服务器的数据目录。我们找到以下MySQL二进制日志文件: ~~~ -rw-rw---- 1 guilhem  guilhem   1277324 Nov 10 23:59 gbichot2-bin.000001 ~~~ ~~~ -rw-rw---- 1 guilhem  guilhem         4 Nov 10 23:59 gbichot2-bin.000002 ~~~ ~~~ -rw-rw---- 1 guilhem  guilhem        79 Nov 11 11:06 gbichot2-bin.000003 ~~~ ~~~ -rw-rw---- 1 guilhem  guilhem       508 Nov 11 11:08 gbichot2-bin.000004 ~~~ ~~~ -rw-rw---- 1 guilhem  guilhem 220047446 Nov 12 16:47 gbichot2-bin.000005 ~~~ ~~~ -rw-rw---- 1 guilhem  guilhem    998412 Nov 14 10:08 gbichot2-bin.000006 ~~~ ~~~ -rw-rw---- 1 guilhem  guilhem       361 Nov 14 10:07 gbichot2-bin.index ~~~ 每次重启,MySQL服务器用序列中的下一个编号创建一个新的二进制日志文件。当服务器运行时,你还可以通过执行FLUSH LOGS SQL语句或**mysqladmin flush-logs**命令,告诉服务器关闭当前的二进制日志文件并创建一个新文件。**mysqldump**也有一个选项来清空日志。数据目录中的.index文件包含该目录下所有MySQL二进制日志的清单。该文件用于复制。 恢复时MySQL二进制日志很重要,因为它们是增量备份。如果进行完全备份时确保清空了日志,则后面创建的二进制日志文件包含了备份后的所有数据更改。让我们稍稍修改前面的**mysqldump**命令,让它在完全备份时能够清空 MySQL二进制日志,以便转储文件包含包含新的当前的二进制日志: ~~~ shell> mysqldump --single-transaction --flush-logs --master-data=2 ~~~ ~~~            --all-databases > backup_sunday_1_PM.sql ~~~ 执行该命令后,数据目录则包含新的二进制日志文件,gbichot2-bin.000007。结果.sql文件包含下列行: ~~~ -- Position to start replication or point-in-time 恢复时y from ~~~ ~~~ -- CHANGE MASTER TO MASTER_LOG_FILE='gbichot2-bin.000007',MASTER_LOG_POS=4; ~~~ 因为**mysqldump**命令可以执行完全备份,这些行表示两件事情: ·         .sql文件包含所有写入gbichot2-bin.000007二进制日志文件或最新的文件之前的更改。 ·         备份后所记录的所有数据更改不出现在.sql中,但出现在gbichot2-bin.000007二进制日志文件或最新的文件中。 在星期一下午1点,我们可以清空日志开始新的二进制日志文件来创建增量备份。例如,执行**mysqladmin flush-logs**命令创建gbichot2-bin.000008。星期日下午1点的完全备份和星期一下午1点之间的所有更改为文件gbichot2-bin.000007。该增量备份很重要,因此最好将它复制到安全的地方。(例如,备份到磁带或DVD上,或复制到另一台机器上)。在星期二下午1点,执行另一个**mysqladmin flush-logs**命令。星期一下午1点和星期二下午1点之间的所有所有更改为文件gbichot2-bin.000008(也应复制到某个安全的地方)。 MySQL二进制日志占据硬盘空间。要想释放空间,应随时清空。操作方法是删掉不再使用的二进制日志,例如进行完全备份时: ~~~ shell> mysqldump --single-transaction --flush-logs --master-data=2 ~~~ ~~~            --all-databases --delete-master-logs > backup_sunday_1_PM.sql ~~~ **注**释:如果你的服务器为复制主服务器,用**mysqldump --delete-master-logs**删掉MySQL二进制日志很危险,因为从服务器可能还没有完全处理该二进制日志的内容。 PURGE MASTER LOGS语句的描述中解释了为什么在删掉MySQL二进制日志之前应进行确认。参见[13.6.1.1节,“PURGE MASTER LOGS语法”](# "13.6.1.1. PURGE MASTER LOGS Syntax")。 #### 5.9.2.2. 为恢复进行备份 现在假设在星期三上午8点出现了灾难性崩溃,需要使用备份文件进行恢复。恢复时,我们首先恢复最后的完全备份(从星期日下午1点开始)。完全备份文件是一系列SQL语句,因此恢复它很容易: ~~~ shell> mysql < backup_sunday_1_PM.sql ~~~ 在该点,数据恢复到星期日下午1点的状态。要想恢复从那时起的更改,我们必须使用增量备份,也就是,gbichot2-bin.000007和gbichot2-bin.000008二进制日志文件。根据需要从备份处取过这些文件,然后按下述方式处理: ~~~ shell> mysqlbinlog gbichot2-bin.000007 gbichot2-bin.000008 | mysql ~~~ 我们现在将数据恢复到星期二下午1点的状态,但是从该时刻到崩溃之间的数据仍然有丢失。要想恢复,我们需要MySQL服务器将MySQL二进制日志保存到安全的位置(RAID disks, SAN, ...),应为与数据文件的保存位置不同的地方,保证这些日志不在毁坏的硬盘上。(也就是,我们可以用--log-bin选项启动服务器,指定一个其它物理设备上的与数据目录不同的位置。这样,即使包含该目录的设备丢失,日志也不会丢失)。如果我们执行了这些操作,我们手头上会有gbichot2-bin.000009文件,我们可以用它来恢复大部分最新的数据更改,而不会丢失到崩溃时的数据。 #### 5.9.2.3. 备份策略摘要 出现操作系统崩溃或电源故障时,InnoDB自己可以完成所有数据恢复工作。但为了确保你可以睡好觉,应遵从下面的指导: ·         一定用--log-bin或甚至--log-bin=*log_name*选项运行MySQL服务器,其中日志文件名位于某个安全媒介上,不同于数据目录所在驱动器。如果你有这样的安全媒介,最好进行硬盘负载均衡(这样能够提高性能)。 ·         定期进行完全备份,使用**mysqldump**命令进行在线非块备份。 ·         用FLUSH LOGS或**mysqladmin flush-logs**清空日志进行定期增量备份。 ### 5.9.3. 自动恢复 [ 5.9.3.1. 指定恢复时间](#)[ 5.9.3.2. 指定恢复位置](#) 如果MySQL服务器启用了二进制日志,你可以使用**mysqlbinlog**工具来恢复从指定的时间点开始 (例如,从你最后一次备份)直到现在或另一个指定的时间点的数据。关于启用二进制日志的信息,参见[5.11.3节,“二进制日志”](# "5.11.3. The Binary Log")。对于**mysqlbinlog**的详细信息,参见[8.6节,“mysqlbinlog:用于处理二进制日志文件的实用工具”](# "8.6. mysqlbinlog — Utility for Processing Binary Log Files")。 要想从二进制日志恢复数据,你需要知道当前二进制日志文件的路径和文件名。一般可以从选项文件(即my.cnf or my.ini,取决于你的系统)中找到路径。如果未包含在选项文件中,当服务器启动时,可以在命令行中以选项的形式给出。启用二进制日志的选项为--log-bin。要想确定当前的二进制日志文件的文件名,输入下面的MySQL语句: ~~~ SHOW BINLOG EVENTS \G ~~~ 你还可以从命令行输入下面的内容: ~~~ mysql --user=root -pmy_pwd -e 'SHOW BINLOG EVENTS \G' ~~~ 将密码*my_pwd*替换为服务器的*root*密码。 #### 5.9.3.1. 指定恢复时间 对于MySQL 4.1.4,可以在**mysqlbinlog**语句中通过--start-date和--stop-date选项指定DATETIME格式的起止时间。举例说明,假设在今天上午10:00(今天是2005年4月20日),执行SQL语句来删除一个大表。要想恢复表和数据,你可以恢复前晚上的备份,并输入: ~~~ mysqlbinlog --stop-date="2005-04-20 9:59:59" /var/log/mysql/bin.123456 \ ~~~ ~~~      | mysql -u root -pmypwd ~~~ 该命令将恢复截止到在--stop-date选项中以DATETIME格式给出的日期和时间的所有数据。如果你没有检测到几个小时后输入的错误的SQL语句,可能你想要恢复后面发生的活动。根据这些,你可以用起使日期和时间再次运行**mysqlbinlog**: ~~~ mysqlbinlog --start-date="2005-04-20 10:01:00" /var/log/mysql/bin.123456 \ ~~~ ~~~      | mysql -u root -pmypwd \ ~~~ 在该行中,从上午10:01登录的SQL语句将运行。组合执行前夜的转储文件和**mysqlbinlog**的两行可以将所有数据恢复到上午10:00前一秒钟。你应检查日志以确保时间确切。下一节介绍如何实现。 #### 5.9.3.2. 指定恢复位置 也可以不指定日期和时间,而使用**mysqlbinlog**的选项--start-position和--stop-position来指定日志位置。它们的作用与起止日选项相同,不同的是给出了从日志起的位置号。使用日志位置是更准确的恢复方法,特别是当由于破坏性SQL语句同时发生许多事务的时候。要想确定位置号,可以运行**mysqlbinlog**寻找执行了不期望的事务的时间范围,但应将结果重新指向文本文件以便进行检查。操作方法为: ~~~ mysqlbinlog --start-date="2005-04-20 9:55:00" --stop-date="2005-04-20 10:05:00" \ ~~~ ~~~       /var/log/mysql/bin.123456 > /tmp/mysql_restore.sql ~~~ 该命令将在/tmp目录创建小的文本文件,将显示执行了错误的SQL语句时的SQL语句。你可以用文本编辑器打开该文件,寻找你不要想重复的语句。如果二进制日志中的位置号用于停止和继续恢复操作,应进行注释。用log_pos加一个数字来标记位置。使用位置号恢复了以前的备份文件后,你应从命令行输入下面内容: ~~~ mysqlbinlog --stop-position="368312" /var/log/mysql/bin.123456 \ ~~~ ~~~     | mysql -u root -pmypwd ~~~ ~~~   ~~~ ~~~ mysqlbinlog --start-position="368315" /var/log/mysql/bin.123456 \ ~~~ ~~~     | mysql -u root -pmypwd \ ~~~ 上面的第1行将恢复到停止位置为止的所有事务。下一行将恢复从给定的起始位置直到二进制日志结束的所有事务。因为**mysqlbinlog**的输出包括每个SQL语句记录之前的SET TIMESTAMP语句,恢复的数据和相关MySQL日志将反应事务执行的原时间。 ### 5.9.4. 表维护和崩溃恢复 后面几节讨论如何使用**myisamchk**来检查或维护MyISAM表(对应.MYI和.MYD文件的表)。 你可以使用**myisamchk**实用程序来获得有关你的数据库表的信息或检查、修复、优化他们。下列小节描述如何调用**myisamchk**(包括它的选项的描述),如何建立表的维护计划,以及如何使用**myisamchk**执行各种功能。 尽管用**myisamchk**修复表很安全,在修复(或任何可以大量更改表的维护操作)之前先进行备份*也是很好的习惯* 影响索引的**myisamchk**操作会使ULLTEXT索引用full-text参数重建,不再与MySQL服务器使用的值兼容。要想避免,请阅读[5.9.5.1节,“用于myisamchk的一般选**项**”](# "5.9.5.1. General Options for myisamchk")的说明。 在许多情况下,你会发现使用SQL语句实现MyISAM表的维护比执行**myisamchk**操作要容易地多: ·         要想检查或维护MyISAM表,使用CHECK TABLE或REPAIR TABLE。 ·         要想优化MyISAM表,使用OPTIMIZE TABLE。 ·         要想分析MyISAM表,使用ANALYZE TABLE。 可以直接这些语句,或使用**mysqlcheck**客户端程序,可以提供命令行接口。 这些语句比**myisamchk**有利的地方是服务器可以做任何工作。使用**myisamchk**,你必须确保服务器在同一时间不使用表。否则,**myisamchk**和服务器之间会出现不期望的相互干涉。 ### 5.9.5. myisamchk:MyISAM表维护实用工具 [ 5.9.5.1. 用于myisamchk的一般选**项**](#)[ 5.9.5.2. 用于myisamchk的检**查选项**](#)[ 5.9.5.3. myisamchk的修复选项****](#)[ 5.9.5.4. 用于myisamchk的其**它选项**](#)[5.9.5.5. ** myisamchk**内存使用](#)[ 5.9.5.6. 将myisa**mchk用于崩溃恢**复](#)[ 5.9.5.7. 如何检查MyISAM表的错误](#)[ 5.9.5.8. 如何修复表](#)[ 5.9.5.9. 表优化](#) 可以使用**myisamchk**实用程序来获得有关数据库表的信息或检查、修复、优化他们。**myisamchk**适用MyISAM表(对应.MYI和.MYD文件的表)。 调用**myisamchk**的方法: ~~~ shell> myisamchk [options] tbl_name ... ~~~ *options*指定你想让**myisamchk**做什么。在后面描述它们。还可以通过调用**myisamchk --help**得到选项列表。 *tbl_name*是你想要检查或修复的数据库表。如果你不在数据库目录的某处运行**myisamchk**,你必须指定数据库目录的路径,因为**myisamchk**不知道你的数据库位于哪儿。实际上,**myisamchk**不在乎你正在操作的文件是否位于一个数据库目录;你可以将对应于数据库表的文件拷贝到别处并且在那里执行恢复操作。 如果你愿意,可以用**myisamchk**命令行命名几个表。还可以通过命名索引文件(用“ .MYI”后缀)来指定一个表。它允许你通过使用模式“*.MYI”指定在一个目录所有的表。例如,如果你在数据库目录,可以这样在目录下检查所有的MyISAM表: ~~~ shell> myisamchk *.MYI ~~~ 如果你不在数据库目录下,可通过指定到目录的路径检查所有在那里的表: ~~~ shell> myisamchk /path/to/database_dir/*.MYI ~~~ 你甚至可以通过为**MySQL**数据目录的路径指定一个通配符来检查所有的数据库中的所有表: ~~~ shell> myisamchk /path/to/datadir/*/*.MYI ~~~ 推荐的快速检查所有MyISAM表的方式是: ~~~ shell> myisamchk --silent --fast /path/to/datadir/*/*.MYI ~~~ 如果你想要检查所有MyISAM表并修复任何破坏的表,可以使用下面的命令: ~~~ shell> myisamchk --silent --force --fast --update-state \ ~~~ ~~~           -O key_buffer=64M -O sort_buffer=64M \ ~~~ ~~~           -O read_buffer=1M -O write_buffer=1M \ ~~~ ~~~           /path/to/datadir/*/*.MYI ~~~ 该命令假定你有大于64MB的自由内存。关于用**myisamchk**分配内存的详细信息,参见[5.9.5.5节,“**myisamchk**内存使用”](# "5.9.5.5. myisamchk Memory Usage")。 当你运行**myisamchk**时,必须确保其它程序不使用表。否则,当你运行**myisamchk**时,会显示下面的错误消息: ~~~ warning: clients are using or haven't closed the table properly ~~~ 这说明你正尝试检查正被另一个还没有关闭文件或已经终止而没有正确地关闭文件的程序(例如**mysqld服务器**)更新的表。 如果**mysqld**正在运行,你必须通过FLUSH TABLES强制清空仍然在内存中的任何表修改。当你运行**myisamchk**时,必须确保其它程序不使用表。避免该问题的最容易的方法是使用CHECK TABLE而不用**myisamchk**来检查表。 #### 5.9.5.1. 用于myisamchk的一般选**项** 本节描述的选项可以用于用**myisamchk**执行的任何类型的表维护操作。本节后面的章节中描述的选项只适合具体操作,例如检查或修复表。 ·         --help,-? 显示帮助消息并退出。 ·         --debug=*debug_options*, -# *debug_options* 输出调试记录文件。*debug_options*字符串经常是'd:t:o,*filename*'。 ·         --silent,-s 沉默模式。仅当发生错误时写输出。你能使用-s两次(-ss)使**myisamchk**沉默。 ·         --verbose,-v 冗长模式。打印更多的信息。这能与-d和-e一起使用。为了更冗长,使用-v多次(-vv, -vvv)! ·         --version, -V 显示版本信息并退出。 ·         --wait, -w 如果表被锁定,不是提示错误终止,而是在继续前等待到表被解锁。请注意如果用--skip-external-locking选项运行**mysqld**,只能用另一个**myisamchk**命令锁定表。 还可以通过--*var_name*=*value*选项设置下面的变量: <table border="1" cellpadding="0" id="table16"><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p><strong> <span>变量</span></strong></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><strong> <span>默认值</span></strong></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>decode_bits</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>9</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>ft_max_word_len</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p>取决于版本</p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>ft_min_word_len</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>4</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>ft_stopword_file</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p>内建列表</p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>key_buffer_size</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>523264</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>myisam_block_size</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>1024</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>read_buffer_size</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>262136</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>sort_buffer_size</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>2097144</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>sort_key_blocks</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>16</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>stats_method</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>nulls_unequal</span></p></td> </tr><tr><td width="175" style="width:131.25pt;padding:.75pt .75pt .75pt .75pt"> <p> <span>write_buffer_size</span></p></td> <td width="154" style="width:115.85pt;padding:.75pt .75pt .75pt .75pt"> <p><span>262136</span></p></td> </tr></table> 可以用**myisamchk --help**检查**myisamchk**变量及其 默认值: 当用排序键值修复键值时使用sort_buffer_size,使用--recover时这是很普通的情况。 当用--extend-check检查表或通过一行一行地将键值插入表中(如同普通插入)来修改键值时使用Key_buffer_size。在以下情况通过键值缓冲区进行修复: ·         使用--safe-recover。 ·         当直接创建键值文件时,需要对键值排序的临时文件有两倍大。通常是当CHAR、VARCHAR、或TEXT列的键值较大的情况,因为排序操作在处理过程中需要保存全部键值。如果你有大量临时空间,可以通过排序强制使用**myisamchk**来修复,可以使用--sort-recover选项。 通过键值缓冲区的修复占用的硬盘空间比使用排序么少,但是要慢。 如果想要快速修复,将key_buffer_size和sort_buffer_size变量设置到大约可用内存的25%。可以将两个变量设置为较大的值,因为一个时间只使用一个变量。 myisam_block_size是用于索引块的内存大小。 stats_method影响当给定--analyze选项时,如何为索引统计搜集处理NULL值。它如同myisam_stats_method系统变量。详细信息参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")和[7.4.7节,“MyISAM索引统计集合”](# "7.4.7. MyISAM Index Statistics Collection")的myisam_stats_method的描述。 ft_min_word_len和ft_max_word_len表示FULLTEXT索引的最小和最大字长。ft_stopword_file为停止字文件的文件名。需要在以下环境中对其进行设置。 如果你使用**myisamchk**来修改表索引(例如修复或分析),使用最小和最大字长和停止字文件的 默认全文参数值(除非你另外指定)重建FULLTEXT索引。这样会导致查询失败。 出现这些问题是因为只有服务器知道这些参数。它们没有保存在MyISAM索引文件中。如果你修改了服务器中的最小或最大字长或停止字文件,要避免该问题,为用于**mysqld**的**myisamchk**指定相同的ft_min_word_len,ft_max_word_len和ft_stopword_file值。例如,如果你将最小字长设置为3,可以这样使用**myisamchk**来修复表: ~~~ shell> myisamchk --recover --ft_min_word_len=3 tbl_name.MYI ~~~ 要想确保**myisamchk**和服务器使用相同的全文参数值,可以将它们放入选项文件的[mysqld]和[myisamchk]小节: ~~~ [mysqld] ~~~ ~~~ ft_min_word_len=3 ~~~ ~~~   ~~~ ~~~ [myisamchk] ~~~ ~~~ ft_min_word_len=3 ~~~ 除了**myisamchk**,还可以使用REPAIR TABLE、ANALYZE TABLE、OPTIMIZE TABLE或ALTER TABLE。这些语句由服务器执行,知道要使用的正确的全文参数值。 #### 5.9.5.2. 用于myisamchk的检**查选项** **myisamchk**支持下面的表检查操作选项: ·         --check, -c 检查表的错误。如果你不明确指定操作类型选项,这就是默认操作。 ·         --check-only-changed, -C 只检查上次检查后有变更的表。 ·         --extend-check, -e 非常仔细地检查表。如果表有许多索引将会相当慢。该选项只能用于极端情况。一般情况下,可以使用**myisamchk**或**myisamchk --medium-check**来确定表内是否有错误。 如果你使用了--extend-check并且有充分的内存,将key_buffer_size变量设置为较大的值可以使修复操作运行得更快。 ·         --fast,-F 只检查没有正确关闭的表。 ·         --force, -f 如果**myisamchk**发现表内有任何错误,则自动进行修复。维护类型与--repair或-r选项指定的相同。 ·         --information, -i 打印所检查表的统计信息。 ·         --medium-check, -m 比--extend-check更快速地进行检查。只能发现99.99%的错误,在大多数情况下就足够了。 ·         --read-only, -T 不要将表标记为已经检查。如果你使用**myisamchk**来检查正被其它应用程序使用而没有锁定的表很有用,例如当用--skip-external-locking选项运行时运行**mysqld**。 ·         --update-state, -U 将信息保存在.MYI文件中,来表示表检查的时间以及是否表崩溃了。该选项用来充分利用--check-only-changed选项,但如果**mysqld服务器**正使用表并且正用--skip-external-locking选项运行时不应使用该选项。 #### 5.9.5.3. myisamchk的修复选项**** **myisamchk**支持下面的表修复操作的选项: ·         --backup, -B 将.MYD文件备份为file_name-time.BAK ·         --character-sets-dir=*path* 字符集安装目录。参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。 ·         --correct-checksum 纠正表的校验和信息。 ·         --data-file-length=*len*, -D *len* 数据文件的最大长度(当重建数据文件且为“满”时)。 ·         --extend-check,-e 进行修复,试图从数据文件恢复每一行。一般情况会发现大量的垃圾行。不要使用该选项,除非你不顾后果。 ·         --force, -f 覆盖旧的中间文件(文件名类似*tbl_name*.TMD),而不是中断。 ·         --keys-used=*val*, -k *val* 对于**myisamchk**,该选项值为位值,说明要更新的索引。选项值的每一个二进制位对应表的一个索引,其中第一个索引对应位0。选项值0禁用对所有索引的更新,可以保证快速插入。通过**myisamchk -r**可以重新激活被禁用的索引。 ·         --no-symlinks, -l 不跟随符号连接。通常**myisamchk**修复一个符号连接所指的表。在MySQL 4.0中该选项不存在,因为从4.0开始的版本在修复过程中不移除符号链接。 ·         --parallel-recover, -p 与-r和-n的用法相同,但使用不同的线程并行创建所有键。*这是alpha代码。自己承担风险!* ·         --quick,-q 不修改数据文件,快速进行修复。出现复制键时,你可以两次指定该项以强制**myisamchk**修改原数据文件。 ·         --recover, -r 可以修复几乎所有一切问题,除非唯一的键不唯一时(对于MyISAM表,这是非常不可能的情况)。如果你想要恢复表,这是首先要尝试的选项。如果**myisamchk**报告表不能用-r恢复,则只能尝试-o。在不太可能的情况下-r失败,数据文件保持完好)。 如果你有大量内存,你应增加sort_buffer_size的值。 ·         --safe-recover, -o 使用一个老的恢复方法读取,按顺序读取所有行,并根据找到的行更新所有索引树。这比-r慢些,但是能处理-r不能处理的情况。该恢复方法使用的硬盘空间比-r少。一般情况,你应首先用-r维修,如果-r失败则用-o。 如果你有大量内存,你应增加sort_buffer_size的值。 ·         (*OBSOLETE*) --set-character-set=*name* 在MySQL 5.1中不使用。参见--set-collation。 ·         --set-collation=*name* 更改用来排序表索引的校对规则。校对规则名的第一部分包含字符集名。 ·         --sort-recover, -n 强制**myisamchk**通过排序来解析键值,即使临时文件将可能很大。 ·         --tmpdir=*path*, -t *path* 用于保存临时文件的目录的路径。如果未设置,**myisamchk**使用TMPDIR环境变量的值。tmpdir可以设置为一系列目录路径,用于成功地以round-robin模式创建临时文件。在Unix中,目录名之间的间隔字符为冒号(‘:’),在Windows、NetWare和OS/2中为分号 (‘;’)。 ·         --unpack,-u 将用**myisampack**打包的表解包。 #### 5.9.5.4. 用于myisamchk的其**它选项** **myisamchk**支持以下表检查和修复之外的其它操作的选项: ·         --analyze,-a 分析键值的分布。这通过让联结优化器更好地选择表应该以什么次序联结和应该使用哪个键来改进联结性能。要想获取分布相关信息,使用**myisamchk --description --verbose *****tbl_name***命令或SHOW KEYS FROM *tbl_name*语句。 ·         --description, -d 打印出关于表的描述性信息。 ·         --set-auto-increment[=*value*], -A[*value*] 强制从给定值开始的新记录使用AUTO_INCREMENT编号(或如果已经有AUTO_INCREMENT值大小的记录,应使用更高值)。如果未指定*value*,新记录的AUTO_INCREMENT编号应使用当前表的最大值加上1。 ·         --sort-index, -S 以从高到低的顺序排序索引树块。这将优化搜寻并且将使按键值的表扫描更快。 ·         --sort-records=*N*, -R *N* 根据一个具体索引排序记录。这使你的数据更局部化并且可以加快在该键上的SELECT和ORDER BY的范围搜索。(第一次做排序可能很慢!)为了找出一张表的索引编号,使用SHOW INDEX,它以**myisamchk**看见他们的相同顺序显示一张表的索引。索引从1开始编号。 如果键没有打包(PACK_KEYS=0),它们的长度相同,因此当**myisamchk**排序并移动记录时,只覆盖索引中的记录偏移量。如果键已经打包(PACK_KEYS=1),**myisamchk**必须先解开打包的键块,然后重新创建索引并再次将键块打包。(在这种情况下,重新创建索引比更新每个索引的偏移量要快)。 #### 5.9.5.5. **myisamchk**内存使用 当你运行**myisamchk**时内存分配重要.MYI**samchk**使用的内存大小不能超过用-O选项指定的。如果你想对每一个大表使用**myisamchk**,你必须首先确定你想使用多少内存。修复时可以使用的 默认值只有3MB。使用更大的内存,可以让**myisamchk**工作得更快一些。例如,如果有大于32MB的RAM,可以使用如下所示选项(除了你可以指定的其它选项): ~~~ shell> myisamchk -O sort=16M -O key=16M -O read=1M -O write=1M ... ~~~ 对于大多数情况,使用-O sort=16M应该足够了。 应记住**myisamchk**使用TMPDIR中的临时文件。如果TMPDIR指向内存文件系统,你可能很容易得到内存溢出的错误。如果发生,设定TMPDIR指向有更多空间的文件系统目录并且重启**myisamchk**。 修复时**myisamchk**也需要大量硬盘空间: ·         将数据文件大小扩大一倍(原文件和复制文件)。如果你用--quick修复则不需要该空间;在这种情况下,只重新创建了索引文件。在文件系统上需要的空间与原数据文件相同!(创建的复制文件位于原文件所在目录)。 ·         代替旧索引文件的新索引文件所占空间。修复工作一开始,就对旧索引文件进行了删减,因此你通常会忽略该空间。在文件系统上需要的该空间与原数据文件相同! ·         当使用--recover或---sort-recover(但不使用--safe-recover)时,需要排序缓冲区空间。需要的空间为: ~~~ ·                (largest_key + row_pointer_length) * number_of_rows * 2 ~~~ 可以用**myisamchk -dv *****tbl_name***检查键值和row_pointer_length的长度。在临时目录分配该空间(用TMPDIR或--tmpdir=*path*指定)。 如果在修复过程中出现硬盘空间问题,可以试试用--safe-recover代替--recover。 #### 5.9.5.6. 将myisa**mchk用于崩溃恢**复 如果用--skip-external-locking运行**mysqld**(在某些系统上为 默认设置,例如Linux),当**mysqld**使用某个表时,你不能可靠地使用**myisamchk**来检查相同的表。当你运行**myisamchk**时如果可以确保没有人在通过**mysqld**访问表,在开始检查表前,你只需要运行**mysqladmin flush-tables**。如果你不能保证,则你检查表时你必须停止**mysqld**。如果**mysqld**更新表时运行**myisamchk**,你可能会获得表被破坏的警告,即使事实并非如此。 如果不使用--skip-external-locking,可以随时使用**myisamchk**来检查表。当检查表时,所有尝试更新表的客户端将等待,直到**myisamchk**准备好可以继续。 如果使用**myisamchk**来修复或优化表,*必须*确保**mysqld服务器**没有在使用该表(如果你正使用--skip-external-locking选项也适用)。如果不关闭**mysqld**,在运行**myisamchk**之前至少应执行**mysqladmin flush-tables**。如果服务器和**myisamchk**同时访问表,表*可能会被破坏*。 本节描述如何检查和处理MySQL数据库中的数据破坏。如果表经常被破坏,你应尽力找到原因。参见[A.4.2节,“如果MySQL依然崩溃,应作些什么”](# "A.4.2. What to Do If MySQL Keeps Crashing")。 关于MyISAM表怎样会被破坏的解释,参见[15.1.4节,“MyISAM表方面的问题”](# "15.1.4. MyISAM Table Problems")。 在执行崩溃恢复时,理解在一个数据库中的每一个*MyISAM*表tbl_name对应的在数据库目录中的3个文件是很重要的: <table border="1" cellpadding="0" id="table17"><tr><td> <p><strong> <span>文件</span></strong></p></td> <td> <p><strong> <span>目的</span></strong></p></td> </tr><tr><td> <p><span><i> <span>tbl_name</span></i><span>.frm</span></span></p></td> <td> <p>定义<span>(</span>格式<span>)</span>文件</p></td> </tr><tr><td> <p><span><i> <span>tbl_name</span></i><span>.MYD</span></span></p></td> <td> <p>数据文件</p></td> </tr><tr><td> <p><span><i> <span>tbl_name</span></i><span>.MYI</span></span></p></td> <td> <p>索引文件</p></td> </tr></table> 这3类文件的每一类都可能遭受不同形式的损坏,但是问题最常发生在数据文件和索引文件。 **myisamchk**通过一行一行地创建一个“.MYD”数据文件的副本来工作,它通过删除旧的“.MYD 文件并且重命名新文件到原来的文件名结束修复阶段。如果你使用--quick,**myisamchk**不创建一个临时“.MYD”文件,只是假定“.MYD”文件是正确的并且仅创建一个新的索引文件,不接触“.MYD”文件,这是安全的,因为**myisamchk**自动检测“.MYD”文件是否损坏并且在这种情况下,放弃修复。你也可以给**myisamchk**两个--quick选项。在这种情况下,**myisamchk**不会在一些错误上(象重复键)放弃,相反试图通过修改“.MYD”文件解决它们。通常,只有在太少的空闲磁盘空间上实施正常修复,使用两个--quick选项时才有用。在这种情况下,你至少应该在运行**myisamchk**前做进行备份。 #### 5.9.5.7. 如何检查MyISAM表的错误 要想检查MyISAM表,应使用下面的命令: ·         myisamchk *tbl_name* 这样能找出99.99%的错误。它不能找出的是**仅仅**涉及数据文件的损坏(这很不常见)。如果想要检查一张表,通常应该没有选项地运行myisamchk或用-s或--silent选项的任何一个。 ·         myisamchk -m * tbl_name* 这样能找出99.99%的错误。它首先检查所有索引条目的错误并通读所有行。它还计算行内所有键值的校验和,并确认校验和与索引树内键的校验和相匹配。 ·         myisamchk -e * tbl_name* 可以完全彻底地检查数据(-e意思是“扩展检查”)。它对每一行做每个键的读检查以证实它们确实指向正确的行。这在一个有很多键的大表上可能花很长时间。**myisamchk**通常将在它发现第一个错误以后停止。如果你想要获得更多的信息,可以增加--verbose(-v)选项。这使得**myisamchk**继续一直到最多20个错误。 ·         myisamchk -e -i * tbl_name* 象前面的命令一样,但是-i选项告诉**myisamchk**还打印出一些统计信息。 在一般使用中,一个简单的**myisamchk**(没有除表名以外的参数)就足够检查表了。 #### 5.9.5.8. 如何修复表 本节描述如何对MyISAM表使用**myisamchk**(扩展名.MYI和.MYD)。 你还可以(并且应该,如果可能)使用CHECK TABLE和REPAIR TABLE语句来检查和修复MyISAM表。参见[13.5.2.3节,“CHECK TABLE语法”](# "13.5.2.3. CHECK TABLE Syntax")和[13.5.2.6节,“REPAIR TABLE语法”](# "13.5.2.6. REPAIR TABLE Syntax")。 一张损坏的表的症状通常是查询意外中断并且能看到下述错误: - “*tbl_name*.frm”被锁定不能更改。 - 不能找到文件“*tbl_name*.MYI”(Errcode:*nnn*)。 - 文件意外结束。 - 记录文件被毁坏。 - 从表处理器得到错误*nnn*。 要想得到错误相关的详细信息,你可以运行**perror***nnn*,其中*nnn*为错误编号。下面的示例显示了如何使用**perror**来找到最常用错误编号(用表的方式指出问题)的含义: ~~~ shell> perror 126 127 132 134 135 136 141 144 145 ~~~ ~~~ 126 = Index file is crashed / Wrong file format ~~~ ~~~ 127 = Record-file is crashed ~~~ ~~~ 132 = Old database file ~~~ ~~~ 134 = Record was already deleted (or record file crashed) ~~~ ~~~ 135 = No more room in record file ~~~ ~~~ 136 = No more room in index file ~~~ ~~~ 141 = Duplicate unique key or constraint on write or update ~~~ ~~~ 144 = Table is crashed and last repair failed ~~~ 145 = Table was marked as crashed and should be repaired 请注意错误135(记录文件中没有更多的空间)和错误136(索引文件中没有更多的空间)不是可以通过简单修复可以修复的错误。在这种情况下,必须使用ALTER TABLE来增加MAX_ROWS和AVG_ROW_LENGTH表选项值: ~~~ ALTER TABLE tbl_name MAX_ROWS=xxx AVG_ROW_LENGTH=yyy; ~~~ 如果你不知道当前的表的选项值,使用SHOW CREATE TABLE或DESCRIBE来查询。 对于其它的错误,你必须修复表。**myisamchk**通常可以检测和修复大多数问题。 修复过程包括四个阶段,此处将进行描述。开始修复前,应进入数据库目录并检查表文件的许可。在Unix中,确保它们对于运行**mysqld的**用户可读(你也应可读,因为你需要访问检查的文件)。如果你需要修改文件,你还必须拥有写访问权限。 用**myisamchk**修复表的选项的描述参见[5.9.5节,“myisamchk:MyISAM表维护实用工具”](# "5.9.5. myisamchk — MyISAM Table-Maintenance Utility")的前几节。 下面几节列出了上述命令失败或你想要使用**myisamchk**提供的扩展特性等情况的例子。 如果你要通过命令行来修复表,必须首先停止**mysqld服务器**。请注意当你在远程服务器上运行**mysqladmin shutdown**时,**mysqladmin**返回后,**mysqld服务器将**仍然运行一会儿,直到停止所有查询并将所有键清空到硬盘上。 **阶段1:检查你的表** 如果你有很多时间,运行**myisamchk *.MYI**或**myisamchk -e *.MYI**。使用-s(沉默)选项禁止不必要的信息。 如果**mysqld服务器处于宕机状态**,应使用--update-state选项来告诉**myisamchk**将表标记为'检查过的'。 你必须只修复那些**myisamchk**报告有错误的表。对这样的表,继续到阶段2。 如果在检查时,你得到奇怪的错误(例如out of memory错误),或如果**myisamchk**崩溃,到阶段3。 **阶段2:简单安全的修复** 注释:如果想更快地进行修复,当运行**myisamchk**时,你应将sort_buffer_size和Key_buffer_size变量的值设置为可用内存的大约25%。 首先,试试**myisamchk -r -q *tbl_name***(-r -q意味着“快速恢复模式”)。这将试图不接触数据文件来修复索引文件。如果数据文件包含它应有的一切内容和指向数据文件内正确地点的删除连接,这应该管用并且表可被修复。开始修复下一张表。否则,执行下列过程: 1. 在继续前对数据文件进行备份。 1. 使用**myisamchk -r *tbl_name***(-r意味着“恢复模式”)。这将从数据文件中删除不正确的记录和已被删除的记录并重建索引文件。 1. 如果前面的步骤失败,使用**myisamchk --safe-recover *tbl_name***。安全恢复模式使用一个老的恢复方法,处理常规恢复模式不行的少数情况(但是更慢)。 如果在修复时,你得到奇怪的错误(例如out of memory错误),或如果**myisamchk**崩溃,到阶段3。 **阶段3:困难的修复** 只有在索引文件的第一个16K块被破坏,或包含不正确的信息,或如果索引文件丢失,你才应该到这个阶段。在这种情况下,需要创建一个新的索引文件。按如下步骤操做: 1. 把数据文件移到安全的地方。 1. 使用表描述文件创建新的(空)数据文件和索引文件: 1. shell> **mysql * db_name*** 1. mysql> **SET AUTOCOMMIT=1;** 1. mysql> **TRUNCATE TABLE *tbl_name*;** 1. mysql> **quit** 如果你的MySQL版本没有TRUNCATE TABLE,则使用DELETE FROM *tbl_name*。 1. 将老的数据文件拷贝到新创建的数据文件之中。(不要只是将老文件移回新文件之中;你要保留一个副本以防某些东西出错。) 回到阶段2。现在**myisamchk -r -q**应该工作了。(这不应该是一个无限循环)。 你还可以使用REPAIR TABLE *tbl_name* USE_FRM,将自动执行整个程序。 **阶段4:非常困难的修复** 只有.frm描述文件也破坏了,你才应该到达这个阶段。这应该从未发生过,因为在表被创建以后,描述文件就不再改变了。 1. 从一个备份恢复描述文件然后回到阶段3。你也可以恢复索引文件然后回到阶段2。对后者,你应该用**myisamchk -r**启动。 1. 如果你没有进行备份但是确切地知道表是怎样创建的,在另一个数据库中创建表的一个拷贝。删除新的数据文件,然后从其他数据库将描述文件和索引文件移到破坏的数据库中。这样提供了新的描述和索引文件,但是让.MYD数据文件独自留下来了。回到阶段2并且尝试重建索引文件。 #### 5.9.5.9. 表优化 为了组合碎片记录并且消除由于删除或更新记录而浪费的空间,以恢复模式运行**myisamchk**: ~~~ shell> myisamchk -r tbl_name ~~~ 你可以用SQL的OPTIMIZE TABLE语句使用的相同方式来优化表,OPTIMIZE TABLE可以修复表并对键值进行分析,并且可以对索引树进行排序以便更快地查找键值。实用程序和服务器之间不可能交互操作,因为当你使用OPTIMIZE TABLE时,服务器做所有的工作。参见[13.5.2.5节,“OPTIMIZE TABLE语法”](# "13.5.2.5. OPTIMIZE TABLE Syntax")。 **myisamchk**还有很多其它可用来提高表的性能的选项: ·         -S, --sort-index ·         -R *index_num*, --sort-records=*index_num* ·         -a, --analyze 关于这些选项的完整的描述,参见[5.9.5节,“myisamchk:MyISAM表维护实用工具”](# "5.9.5. myisamchk — MyISAM Table-Maintenance Utility")。 ### 5.9.6. 建立表维护计划 定期对表进行检查而非等到问题出现后再检查数据库表是一个好主意。检查和修复MyISAM表的一个方式是使用CHECK TABLE和REPAIR TABLE语句。参见[13.5.2.3节,“CHECK TABLE语法”](# "13.5.2.3. CHECK TABLE Syntax")和[13.5.2.6节,“REPAIR TABLE语法”](# "13.5.2.6. REPAIR TABLE Syntax")。 检查表的另一个方法是使用**myisamchk**。为维护目的,可以使用**myisamchk -s**检查表。-s选项(简称--silent)使**myisamchk**以沉默模式运行,只有当错误出现时才打印消息。 在服务器启动时检查表是一个好主意。例如,无论何时机器在更新当中重新启动了,你通常需要检查所有可能受影响的表。(即“预期的破坏了的表”)。要想自动检查MyISAM表,用--myisam-recover选项启动服务器。 一个更好的测试将是检查最后修改时间比“.pid”文件新的表。 你还应该在正常系统操作期间定期检查表。在MySQL AB,我们运行一个**cron**任务,每周一次检查所有重要的表,使用“crontab”文件中这样的行: ~~~ 35 0 * * 0 /path/to/myisamchk --fast --silent /path/to/datadir/*/*.MYI ~~~ 可以打印损坏的表的信息,以便我们在需要时能够检验并且修复它们。 多年了我们还没有发现(的确是真的)都没有任何意外损坏的表时(由于除硬件故障外的其它原因造成损坏的表),每周一次对我们是足够了。 我们建议现在开始,你对所有最后24小时内被更新了的表每晚都执行**myisamchk -s**,直到你变得象我们那样信任**MySQL**。 一般情况,MySQL表很少需要维护。如果你用动态大小的行更改MyISAM表(含VARCHAR、BLOB或TEXT列的表)或有删除了许多行的表,你可能想要不时地(每月一次)整理/组合表的空间。 可以对有问题的表执行OPTIMIZE TABLE来优化。或者是,如果可以停一会**mysqld服务器**,进入数据目录,当服务器停止时使用该命令: shell> **myisamchk -r -s --sort-index -O sort_buffer_size=16M */*.MYI** ### 5.9.7. 获取关于表的信息 为了获得关于一个表的描述或统计,使用下面的命令: ·         ** myisamchk -d *****tbl_name*** 以“描述模式”运行**myisamchk**,生成表的描述。如果用--skip-external-locking选项启动**MySQL**服务器,**myisamchk**可以报告运行的表被更新的错误。然而,既然在描述模式中**myisamchk**不更改表,没有任何破坏数据的风险。 ·         ** myisamchk -d -v *****tbl_name*** 为了生成更多关于**myisamchk**正在做什么的信息,加上-v告诉它以冗长模式运行。 ·         ** myisamchk -eis *****tbl_name*** 仅显示表的最重要的信息。因为必须读取整个表,该操作很慢。 ·         ** myisamchk -eiv *****tbl_name*** 这类似 -eis,只是告诉你正在做什么。 下面为这些命令的输出示例。它们基于含这些数据和索引文件大小的表: ~~~ -rw-rw-r--   1 monty    tcx     317235748 Jan 12 17:30 company.MYD ~~~ ~~~ -rw-rw-r--   1 davida   tcx      96482304 Jan 12 18:35 company.MYM ~~~ **myisamchk -d**输出示例: ~~~ MyISAM file:     company.MYI ~~~ ~~~ Record format:   Fixed length ~~~ ~~~ Data records:    1403698  Deleted blocks:         0 ~~~ ~~~ Recordlength:    226 ~~~ ~~~   ~~~ ~~~ table description: ~~~ ~~~ Key Start Len Index   Type ~~~ ~~~ 1   2     8   unique  double ~~~ ~~~ 2   15    10  multip. text packed stripped ~~~ ~~~ 3   219   8   multip. double ~~~ ~~~ 4   63    10  multip. text packed stripped ~~~ ~~~ 5   167   2   multip. unsigned short ~~~ ~~~ 6   177   4   multip. unsigned long ~~~ ~~~ 7   155   4   multip. text ~~~ ~~~ 8   138   4   multip. unsigned long ~~~ ~~~ 9   177   4   multip. unsigned long ~~~ ~~~     193   1           text ~~~ **myisamchk -d -v**输出示例: ~~~ MyISAM file:         company ~~~ ~~~ Record format:       Fixed length ~~~ ~~~ File-version:        1 ~~~ ~~~ Creation time:       1999-10-30 12:12:51 ~~~ ~~~ Recover time:        1999-10-31 19:13:01 ~~~ ~~~ Status:              checked ~~~ ~~~ Data records:            1403698  Deleted blocks:              0 ~~~ ~~~ Datafile parts:          1403698  Deleted data:                0 ~~~ ~~~ Datafile pointer (bytes):      3  Keyfile pointer (bytes):     3 ~~~ ~~~ Max datafile length:  3791650815  Max keyfile length: 4294967294 ~~~ ~~~ Recordlength:                226 ~~~ ~~~   ~~~ ~~~ table description: ~~~ ~~~ Key Start Len Index   Type                  Rec/key     Root Blocksize ~~~ ~~~ 1   2     8   unique  double                      1 15845376      1024 ~~~ ~~~ 2   15    10  multip. text packed stripped        2 25062400      1024 ~~~ ~~~ 3   219   8   multip. double                     73 40907776      1024 ~~~ ~~~ 4   63    10  multip. text packed stripped        5 48097280      1024 ~~~ ~~~ 5   167   2   multip. unsigned short           4840 55200768      1024 ~~~ ~~~ 6   177   4   multip. unsigned long            1346 65145856      1024 ~~~ ~~~ 7   155   4   multip. text                     4995 75090944      1024 ~~~ ~~~ 8   138   4   multip. unsigned long              87 85036032      1024 ~~~ ~~~ 9   177   4   multip. unsigned long             178 96481280      1024 ~~~ ~~~     193   1           text ~~~ **myisamchk -eis**输出示例: ~~~ Checking MyISAM file: company ~~~ ~~~ Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4 ~~~ ~~~ Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4 ~~~ ~~~ Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4 ~~~ ~~~ Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3 ~~~ ~~~ Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4 ~~~ ~~~ Total:    Keyblocks used:  98%  Packed:   17% ~~~ ~~~   ~~~ ~~~ Records:          1403698    M.recordlength:     226 ~~~ ~~~ Packed:             0% ~~~ ~~~ Recordspace used:     100%   Empty space:          0% ~~~ ~~~ Blocks/Record:   1.00 ~~~ ~~~ Record blocks:    1403698    Delete blocks:        0 ~~~ ~~~ Recorddata:     317235748    Deleted data:         0 ~~~ ~~~ Lost space:             0    Linkdata:             0 ~~~ ~~~   ~~~ ~~~ User time 1626.51, System time 232.36 ~~~ ~~~ Maximum resident set size 0, Integral resident set size 0 ~~~ ~~~ Non physical pagefaults 0, Physical pagefaults 627, Swaps 0 ~~~ ~~~ Blocks in 0 out 0, Messages in 0 out 0, Signals 0 ~~~ ~~~ Voluntary context switches 639, Involuntary context switches 28966 ~~~ **myisamchk -eiv**输出示例: ~~~ Checking MyISAM file: company ~~~ ~~~ Data records: 1403698   Deleted blocks:       0 ~~~ ~~~ - check file-size ~~~ ~~~ - check delete-chain ~~~ ~~~ block_size 1024: ~~~ ~~~ index  1: ~~~ ~~~ index  2: ~~~ ~~~ index  3: ~~~ ~~~ index  4: ~~~ ~~~ index  5: ~~~ ~~~ index  6: ~~~ ~~~ index  7: ~~~ ~~~ index  8: ~~~ ~~~ index  9: ~~~ ~~~ No recordlinks ~~~ ~~~ - check index reference ~~~ ~~~ - check data record references index: 1 ~~~ ~~~ Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4 ~~~ ~~~ - check data record references index: 2 ~~~ ~~~ Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4 ~~~ ~~~ - check data record references index: 3 ~~~ ~~~ Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4 ~~~ ~~~ - check data record references index: 4 ~~~ ~~~ Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3 ~~~ ~~~ - check data record references index: 5 ~~~ ~~~ Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ - check data record references index: 6 ~~~ ~~~ Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ - check data record references index: 7 ~~~ ~~~ Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ - check data record references index: 8 ~~~ ~~~ Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3 ~~~ ~~~ - check data record references index: 9 ~~~ ~~~ Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4 ~~~ ~~~ Total:    Keyblocks used:   9%  Packed:   17% ~~~ ~~~   ~~~ ~~~ - check records and index references ~~~ ~~~ [LOTS OF ROW NUMBERS DELETED] ~~~ ~~~   ~~~ ~~~ Records:         1403698   M.recordlength:   226   Packed:           0% ~~~ ~~~ Recordspace used:    100%  Empty space:        0%  Blocks/Record: 1.00 ~~~ ~~~ Record blocks:   1403698   Delete blocks:      0 ~~~ ~~~ Recorddata:    317235748   Deleted data:       0 ~~~ ~~~ Lost space:            0   Linkdata:           0 ~~~ ~~~   ~~~ ~~~ User time 1639.63, System time 251.61 ~~~ ~~~ Maximum resident set size 0, Integral resident set size 0 ~~~ ~~~ Non physical pagefaults 0, Physical pagefaults 10580, Swaps 0 ~~~ ~~~ Blocks in 4 out 0, Messages in 0 out 0, Signals 0 ~~~ ~~~ Voluntary context switches 10604, Involuntary context switches 122798 ~~~ 下面解释**myisamchk**产生的信息的类型。“keyfile”是索引文件。“记录”和“行”是同义词。 ·         MyISAM file ISAM(索引)文件名。 ·         File-version ISAM格式的版本。当前总是2。 ·         Creation time 数据文件创建的时间。 ·         Recover time 索引/数据文件上次被重建的时间。 ·         Data records 在表中有多少记录。 ·         Deleted blocks 有多少删除的块仍然保留着空间。你可以优化表以使这个空间减到最小。参见[第7章:](#)[*优化*](# "Chapter 7. Optimization")。 ·         Datafile parts 对动态记录格式,这指出有多少数据块。对于一个没有碎片的优化过的表,这与Data records相同。 ·         Deleted data 不能回收的删除数据有多少字节。你可以优化表以使这个空间减到最小。参见[第7章:](#)[*优化*](# "Chapter 7. Optimization")。 ·         Datafile pointer 数据文件指针的大小,以字节计。它通常是2、3、4或5个字节。大多数表用2个字节管理,但是目前这还不能从**MySQL**控制。对固定表,这是一个记录地址。对动态表,这是一个字节地址。 ·         Keyfile pointer 索引文件指针的大小,以字节计。它通常是1、2或3个字节。大多数表用 2 个字节管理,但是它自动由**MySQL**计算。它总是一个块地址。 ·         Max datafile length 表的数据文件(.MYD文件)能够有多长,以字节计。 ·         Max keyfile length 表的键值文件(.MYI文件)能够有多长,以字节计。 ·           Recordlength 每个记录占多少空间,以字节计。 ·         Record format 用于存储表行的格式。上面的例子使用Fixed length。其他可能的值是Compressed和Packed。 ·         table description 在表中所有键值的列表。对每个键,给出一些底层的信息: o        Key 该键的编号。 o        Start 该索引部分从记录的哪里开始。 o        Len 该索引部分是多长。对于紧凑的数字,这应该总是列的全长。对字符串,它可以比索引的列的全长短些,因为你可能会索引到字符串列的前缀。 o        Index unique或multip(multiple)。表明一个值是否能在该索引中存在多次。 o        Type 该索引部分有什么数据类型。这是一个packed、stripped或empty选项的ISAM数据类型。 o        Root 根索引块的地址。 o        Blocksize 每个索引块的大小。默认是1024,但是从源码构建MySQL时,该值可以在编译时改变。 o        Rec/key 这是由优化器使用的统计值。它告诉对该键的每个值有多少条记录。唯一键总是有一个1值。在一个表被装载后(或变更很大),可以用**myisamchk -a**更新。如果根本没被更新,给定一个30的默认值。 在上面例子的表中,第9个键有两个table description行。者说明它是有2个部分的多部键。 ·         Keyblocks used 键块使用的百分比是什么。当在例子中使用的表刚刚用**myisamchk**重新组织时,该值非常高(很接近理论上的最大值)。 ·         Packed ** MySQL**试图用一个通用后缀压缩键。这只能被用于CHAR/VARCHAR/DECIMAL列的键。对于左部分类似的长字符串,能显著地减少使用空间。在上面的第3个例子中,第4个键是10个字符长,可以减少60%的空间。 ·         Max levels 对于该键的B树有多深。有长键的大表有较高的值。 ·         Records 表中有多少行。 ·         M.recordlength 平均记录长度。对于有定长记录的表,这是准确的记录长度,因为所有记录的长度相同。 ·         Packed ** MySQL**从字符串的结尾去掉空格。Packed值表明这样做达到的节约的百分比。 ·         Recordspace used 数据文件被使用的百分比。 ·         Empty space 数据文件未被使用的百分比。 ·         Blocks/Record 每个记录的平均块数(即,一个碎片记录由多少个连接组成)。对固定格式表,这总是1。该值应该尽可能保持接近1.0。如果它变得太大,你可以重新组织表。参见[第7章:](#)[*优化*](# "Chapter 7. Optimization")。 ·         Recordblocks 多少块(链接)被使用。对固定格式,它与记录的个数相同。 ·         Deleteblocks 多少块(链接)被删除。 ·         Recorddata 在数据文件中使用了多少字节。 ·         Deleted data 在数据文件中多少字节被删除(未使用)。 ·         Lost space 如果一个记录被更新为更短的长度,就损失了一些空间。这是所有这样的损失之和,以字节计。 ·         Linkdata 当使用动态表格式,记录碎片用指针连接(每个4 ~ 7字节)。 Linkdata指这样的指针使用的内存量之和。 如果一张表已经用**myisampack**压缩了,**myisamchk -d**打印每个表列的附加信息。对于它的一个例子及其含义的描述,参见[8.2节,“myisampack:生成压缩、只读MyISAM表”](# "8.2. myisampack — Generate Compressed, Read-Only MyISAM Tables")。 ### 5.10. MySQL本地化和国际应用 [ 5.10.1. 数据和排序用字符集](#)[ 5.10.2. 设置错误消息语言](#)[ 5.10.3. 添加新的字符集](#)[ 5.10.4. 字符定义数组](#)[ 5.10.5. 字符串比较支持](#)[ 5.10.6. 多字节字符支持](#)[ 5.10.7. 字符集问题](#)[ 5.10.8. MySQL服务器时区支持](#) 本节描述如何配置服务器来使用不同的字符集。还讨论如何设置服务器的时区并启用各个连接的时区支持。 ### 5.10.1. 数据和排序用字符集 [ 5.10.1.1. 使用德国字符集](#) 默认情况下,MySQL使用cp1252(Latin1)字符集根据Swedish/Finnish规则进行排序。这些 默认值适合美国和西欧大部分国家。 所有MySQL二进制分发版用--with-extra-charsets=complex编译而成。可以在所有标准程序中添加代码,使它们可以处理latin1和所有多字节二进制字符集。其它字符集根据需要从字符集定义文件载入。 字符集确定在名称中使用什么字符。它还确定如何用SELECT语句的ORDER BY和GROUP BY子句对字符串进行排序。 还可以在启动服务器时用--default-character-set选项更改字符集。字符集可以用--with-charset=*charset*和--with-extra-charsets=*list-of-charsets* | complex | all | none选项来**configure**,字符集配置文件列于SHAREDIR/charsets/Index。参见[2.8.2节,“典型配置选项****”](# "2.8.2. Typical configure Options")。 还可以在你启动服务器时用--default-collation选项更改字符集 校对规则。校对规则必须是默认字符集的合法校对规则。(使用SHOW COLLATION语句来确定每个字符集使用哪个校对规则)。 参见[2.8.2节,“典型配置选项****”](# "2.8.2. Typical configure Options")。 如果在运行MySQL时更改字符集,还会更改排序顺序。结果是你必须对所有表运行**myisamchk -r -q --set-character-set=*****charset***,或正确地对索引进行排序。 当客户端连接MySQL服务器时,服务器告诉客户端服务器的默认字符集是什么。客户端切换到该字符集进行连接。 当转义SQL查询的字符串时,你应使用mysql_real_escape_string()。mysql_real_escape_string()等价于旧的mysql_escape_string()函数,不同的是它使用MYSQL连接句柄作为第一个参数,以便转义字符时可以使用相应的字符集。 如果客户端的编译路径不是服务器的安装目录,并且配置MySQL时没有包括MySQL二进制中的所有字符集,如果服务器运行时需要使用客户端设置的字符集之外的其它字符集,你必须告诉客户端从哪里找到更多的字符集。 可以指定--character-sets-dir选项来表示动态MySQL字符集所保存目录的路径。例如,可以将下面的行放入选项文件中: ~~~ [client] ~~~ ~~~ character-sets-dir=/usr/local/mysql/share/mysql/charsets ~~~ 你可以强制客户端使用专用字符集: ~~~ [client] ~~~ ~~~ default-character-set=charset ~~~ 但是一般情况不需要。 #### 5.10.1.1. 使用德国字符集 在MySQL 5.1中,分别指定字符集和 校对规则。这说明如果你想使用German排序顺序,你应选择latin1字符集和latin1_german1_ci或latin1_german2_ci校对规则。例如,要用latin1_german1_ci校对规则启动服务器,应使用--character-set-server=latin1和--collation-server=latin1_german1_ci选项。 关于这两种校对规则的不同之处,参见[10.10.2节,“西欧字符集”](# "10.10.2. West European Character Sets")。 ### 5.10.2. 设置错误消息语言 默认情况下,**mysqld**用英语给出错误消息,但也可以用以下语言显示:Czech、Danish、Dutch、Estonian、French、German、Greek、Hungarian、Italian、Japanese、Korean、Norwegian、Norwegian-ny、Polish、Portuguese、Romanian、Russian、Slovak、Spanish或 Swedish。 要想在启动**mysqld**后用具体语言显示错误消息,使用--language或-L选项。选项值可以为语言名称或错误消息文件的全路径。例如: ~~~ shell> mysqld --language=swedish ~~~ 或: ~~~ shell> mysqld --language=/usr/local/share/swedish ~~~ 语言名应为小写。 语言文件位于(默认情况下)MySQL基本目录的share/*LANGUAGE*目录下。 要想更改错误消息文件,应编辑errmsg.txt文件,然后执行下面的命令以生成errmsg.sys文件: ~~~ shell> comp_err errmsg.txt errmsg.sys ~~~ 如果你升级到新版本的MySQL,记住使用新的errmsg.txt文件来重新更改。 ### 5.10.3. 添加新的字符集 本节讨论在MySQL中添加新字符集的程序。你必须有一个MySQL源码分发版。 要选择正确的程序,先确定字符集是简单字符集还是复杂字符集: ·         如果字符集不需要使用特殊字符串校对规则程序进行排序,并且不需要多字节字符支持,则为简单字符集。 ·         如果需要上述某个特性,则为复杂字符集。 例如,latin1和danish为简单字符集,而big5和czech为复杂字符集。 在下面的程序中,字符集名用*MYSET*表示。 对于简单字符集,应: 1.    在sql/share/charsets/Index文件最后添加*MYSET*。并指定唯一的编号。 2.    创建文件sql/share/charsets/*MYSET*.conf。(你可以使用sql/share/charsets/latin1.conf的备份文件作为该文件的基础)。 **该**文件的语法很简单: ·         注释从‘#’字符开始,一直到该行末尾。 ·         各字之间用任意数量的空格间隔开。 ·         定义字符集时,每个字必须为十六进制格式的数字。 ·         ctype数组占据前257个字。to_lower[]、to_upper[]和sort_order[]数组依次占据256个字。 参见[5.10.4节,“字符定义数组”](# "5.10.4. The Character Definition Arrays")。 3.    将字符集名添加到configurE.in的CHARSETS_AVAILABLE和COMPILED_CHARSETS列。 4.    重新配置、编译并测试。 对于复杂字符集,应: 1.    在MySQL源码分发版中创建文件strings/ctype-*MYSET*.c。 2.    在sql/share/charsets/Index文件最后添加*MYSET*。并指定唯一的编号。 3.    看看已有的ctype-*.c文件(例如strings/ctype-big5.c),看看需要定义什么。请注意文件中的数组名必须为ctype_*MYSET*、to_lower_*MYSET*等等。对应简单字符集的数组。参见[5.10.4节,“字符定义数组”](# "5.10.4. The Character Definition Arrays")。 4.    在文件顶部,添加注释: ~~~ 5.            /* ~~~ ~~~ 6.            * This comment is parsed by configure to create ctype.c, ~~~ ~~~ 7.            * so don't change it unless you know what you are doing. ~~~ ~~~ 8.            * ~~~ ~~~ 9.            * .configure. number_MYSET=MYNUMBER ~~~ ~~~ 10.        * .configure. strxfrm_multiply_MYSET=N ~~~ ~~~ 11.        * .configure. mbmaxlen_MYSET=N ~~~ ~~~ 12.        */ ~~~ **configure**程序使用该注释自动将字符集包括进MySQL库中。 在下面章节中解释strxfrm_multiply和mbmaxlen行。只有需要字符串比较函数或多字节字符集函数时,才需要单独将它们包括进来。 13.然后你应创建下面的函数: - my_strncoll_*MYSET*() - my_strcoll_*MYSET*() - my_strxfrm_*MYSET*() - my_like_range_*MYSET*() 参见[5.10.5节,“字符串比较支持”](# "5.10.5. String Collating Support") 14.将字符集名添加到configurE.in的CHARSETS_AVAILABLE和COMPILED_CHARSETS列。 15.重新配置、编译并测试。 sql/share/charsets/README文件中包括详细的说明。 如果你想要MySQL分发中的字符集,请向MySQL内部邮件系统发邮件。参见[1.7.1.1节,“The MySQL邮件列表”](# "1.7.1.1. The MySQL Mailing Lists")。 ### 5.10.4. 字符定义数组 to_lower[]和to_upper[]是简单数组,含有小写和大写字符,对应字符集的每个成员。例如: ~~~ to_lower['A'] should contain 'a' ~~~ ~~~ to_upper['a'] should contain 'A' ~~~ sort_order[]是一个映射,表示如何排列字符的顺序,以便进行比较和排序。通常(但非对于所有字符集)与to_upper[]相同,说明排序对大小写敏感。MySQL排序字符基于sort_order[]元素的值。对于更加复杂的排序规则,参见[5.10.5节,“字符串比较支持”](# "5.10.5. String Collating Support")的字符串 校对规则讨论。 ctype[]是一个位数组,每个字符为一个元素。(请注意字符值索引to_lower[]、to_upper[]和sort_order[],但用字符值+ 1索引ctype[]。这是传统的转换方法,能够处理EOF)。 m_ctype.h中有下面的位掩码定义: ~~~ #define _U      01      /* Uppercase */ ~~~ ~~~ #define _L      02      /* Lowercase */ ~~~ ~~~ #define _N      04      /* Numeral (digit) */ ~~~ ~~~ #define _S      010     /* Spacing character */ ~~~ ~~~ #define _P      020     /* Punctuation */ ~~~ ~~~ #define _C      040     /* Control character */ ~~~ ~~~ #define _B      0100    /* Blank */ ~~~ ~~~ #define _X      0200    /* heXadecimal digit */ ~~~ 每个字符的ctype[]条目应为相应的描述字符的位掩码值的联合。例如,'A'是大写字符(_U)以及十六进制整数(_X),因此ctype['A'+1]应包含 值: _U + _X = 01 + 0200 = 0201 ### 5.10.5. 字符串比较支持 如果语言的排序规则比较复杂,不能用简单sort_order[]表来处理,需要使用字符串比较函数。 最好的文档是已有字符集。以big5、czech、gbk、sjis和tis160字符集作为例子。 你必须在文件顶部的特殊注释处指定strxfrm_multiply_*MYSET*=*N*值。*N*应设置为字符串在my_strxfrm_*MYSET*过程中可能增长的最大比例(必须为正整数)。 ### 5.10.6. 多字节字符支持 如果你想要添加包括多字节字符的新字符集支持,需要使用多字节字符函数。 最好的文档是已有字符集。以euc_kr、gb2312,gbk、sjis和ujis字符集作为例子。这些字符集位于strings目录的ctype-*charset*.c文件中。 必须在文件顶部的特殊注释处指定mbmaxlen_*MYSET*=*N*值。*N*应设置为字符集内最长字符的字节数。 ### 5.10.7. 字符集问题 如果你想要使用没有编译为二进制的字符集,可能会遇到下面的问题: ·         你的程序的字符集保存路径不正确。(默认为/usr/local/mysql/share/mysql/charsets)。可以在运行有问题的程序时通过--character-sets-dir选项来修复。 ·         字符集为多字节字符集,不能动态载入。在这种情况下,你必须重新编译程序,以支持字符集。 ·         字符集为动态字符集,但你没有对应的配置文件。在这种情况下,你应从新MySQL分发安装该字符集的配置文件。 ·         如果Index文件没有包含字符集名,程序将显示下面的错误消息: ~~~ ·                ERROR 1105: File '/usr/local/share/mysql/charsets/?.conf' ~~~ ~~~ ·                not found (Errcode:2) ~~~ 在这种情况下,你应获得新Index文件或在当前文件中手动添加字符集。 对于MyISAM表,可以用**myisamchk -dvv *****tbl_name***检查表的字符集名和编号。 ### 5.10.8. MySQL服务器时区支持  MySQL服务器有几个时区设置: ·         系统时区。服务器启动时便试图确定主机的时区,用它来设置system_time_zone系统变量。 ·         服务器当前的时区。全局系统变量time_zone表示服务器当前使用的时区。初使值为'SYSTEM',说明服务器时区与系统时区相同。可以用--default-time-zone=*timez*选项显式指定初使值。如果你有SUPER权限,可以用下面的语句在运行时设置全局变量值: ~~~ ·                mysql> SET GLOBAL time_zone = timezone; ~~~ ·         每个连接的时区。每个客户端连接有自己的时区设置,用会话time_zone变量给出。其初使值与全局变量time_zone相同,但可以用下面的语句重设: ~~~ ·                mysql> SET time_zone = timezone; ~~~ 可以用下面的方法查询当前的全局变量值和每个连接的时区: ~~~ mysql> SELECT @@global.time_zone, @@session.time_zone; ~~~ *timezone*值为字符串,表示UTC的偏移量,例如'+10:00'或'-6:00'。如果已经创建并装入mysql数据库中的时区相关表,你还可以使用命名的时区,例如'Europe/Helsinki'、'US/Eastern'或'MET'。值'SYSTEM'说明该时区应与系统时区相同。时区名对大小写不敏感。 MySQL安装程序在mysql数据库中创建时区表,但不装载。你必须手动装载。(如果你正从以前的版本升级到MySQL 4.1.3或更新版本,你应通过升级mysql数据库来创建表。参见[2.10.2节,“升级授权表”](# "2.10.2. Upgrading the Grant Tables")中的说明)。 如果你的系统有自己的时区信息数据库(描述时区的一系列文件),应使用**mysql_tzinfo_to_sql**程序来填充时区表。示例系统如Linux、FreeBSD、Sun Solaris和Mac OS X。这些文件的可能位置为/usr/share/zoneinfo目录。如果你的系统没有时区信息数据库,可以使用本节后面描述的下载的软件包。 ** mysql_tzinfo_to_sql**程序用来装载时区表。在命令行中,将时区信息目录路径名传递到**mysql_tzinfo_to_sql**并输出发送到**mysql**程序。例如: ~~~ shell> mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql ~~~ ** mysql_tzinfo_to_sql**读取系统时区文件并生成SQL语句。**mysql**处理这些语句并装载时区表。 ** mysql_tzinfo_to_sql**还可以用来装载单个时区文件,并生成闰秒信息。 要想装载对应时区*tz_name*的单个时区文件*tz_file*,应这样调用**mysql_tzinfo_to_sql**: ~~~ shell> mysql_tzinfo_to_sql tz_file tz_name | mysql -u root mysql ~~~ 如果你的时区需要计算闰秒,按下面方法初使化闰秒信息,其中*tz_file*是时区文件名: ~~~ shell> mysql_tzinfo_to_sql --leap tz_file | mysql -u root mysql ~~~ 如果你的系统没有时区信息数据库 (例如,Windows或HP-UX),你可以从[http://dev.mysql.com/downloads/timezones.html](http://dev.mysql.com/downloads/timezones.html)下载预构建时区表软件包。该软件包包含MyISAM时区表所用的.frm、.MYD和.MYI文件。这些表应属于mysql数据库,因此应将这些文件放到MySQL服务器数据目录的mysql子目录。操作时应关闭服务器。 **警告!**如果你的系统有时区信息数据库,请不要使用下载的软件包。而应使用**mysql_tzinfo_to_sql**实用工具!否则,MySQL和系统上其它应用程序处理日期时间的方法会有所不同。 关于在复制时时区设置相关请查阅[6.7节,“复制特性和已知问题”](# "6.7. Replication Features and Known Problems")。 ### 5.11. MySQL日志文件 [ 5.11.1. 错误日志](#)[ 5.11.2. 通用查询日志](#)[ 5.11.3. 二进制日志](#)[ 5.11.4. 慢速查询日志](#)[ 5.11.5. 日志文件维护](#) MySQL有几个不同的日志文件,可以帮助你找出**mysqld**内部发生的事情: <table border="1" cellpadding="0" id="table18"><tr><td> <p><strong><span>日志文件</span></strong></p></td> <td> <p><strong><span> 记入文件中的信息类型</span></strong></p></td> </tr><tr><td> <p>错误日志</p></td> <td> <p>记录启动、运行或停止<strong><span>mysqld</span></strong><b>时出</b>现的问题。</p></td> </tr><tr><td> <p>查询日志</p></td> <td> <p>记录建立的客户端连接和执行的语句。</p></td> </tr><tr><td> <p>更新日志</p></td> <td> <p>记录更改数据的语句。不<span>赞成使用该日志。</span></p></td> </tr><tr><td> <p>二进制日志</p></td> <td> <p>记录所有更改数据的语句。还用于复制。</p></td> </tr><tr><td> <p>慢日志</p></td> <td> <p>记录所有执行时间超过<span>long_query_time</span>秒的所有查询或不使用索引的查询。</p></td> </tr></table> 默认情况下,所有日志创建于**mysqld**数据目录中。通过刷新日志,你可以强制 **mysqld**来关闭和重新打开日志文件(或者在某些情况下切换到一个新的日志)。当你执行一个FLUSH LOGS语句或执行**mysqladmin flush-logs**或**mysqladmin refresh**时,出现日志刷新。参见[13.5.5.2节,“FLUSH语法”](# "13.5.5.2. FLUSH Syntax")。 如果你正使用MySQL复制功能,从复制服务器将维护更多日志文件,被称为接替日志。相关讨论参见[第6章:](#)[*MySQL中的复制*](# "Chapter 6. Replication in MySQL")。 ### 5.11.1. 错误日志 错误日志文件包含了当**mysqld**启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。 如果**mysqld**莫名其妙地死掉并且**mysqld_safe**需要重新启动它,**mysqld_safe**在错误日志中写入一条restarted mysqld消息。如果**mysqld**注意到需要自动检查或着修复一个表,则错误日志中写入一条消息。 在一些操作系统中,如果**mysqld**死掉,错误日志包含堆栈跟踪信息。跟踪信息可以用来确定**mysqld**死掉的地方。参见[E.1.4节,“使用堆栈跟踪”](# "E.1.4. Using a Stack Trace")。 可以用--log-error[=*file_name*]选项来指定**mysqld**保存错误日志文件的位置。如果没有给定*file_name*值,**mysqld**使用错误日志名*host_name.err *并在数据目录中写入日志文件。如果你执行FLUSH LOGS,错误日志用-old重新命名后缀并且**mysqld**创建一个新的空日志文件。(如果未给出--log-error选项,则不会重新命名)。 如果不指定--log-error,或者(在Windows中)如果你使用--console选项,错误被写入标准错误输出stderr。通常标准输出为你的终端。 在Windows中,如果未给出--console选项,错误输出总是写入.err文件。 ### 5.11.2. 通用查询日志 如果你想要知道**mysqld**内部发生了什么,你应该用--log[=*file_name*]或-l [*file_name*]选项启动它。如果没有给定*file_name*的值, 默认名是*host_name*.log**。**所有连接和语句被记录到日志文件。当你怀疑在客户端发生了错误并想确切地知道该客户端发送给**mysqld**的语句时,该日志可能非常有用**。** **mysqld**按照它接收的顺序记录语句到查询日志。这可能与执行的顺序不同。这与更新日志和二进制日志不同,它们在查询执行后,但是任何一个锁释放之前记录日志。(查询日志还包含所有语句,而二进制日志不包含只查询数据的语句)。 服务器重新启动和日志刷新不会产生新的一般查询日志文件(尽管刷新关闭并重新打开一般查询日志文件)。在Unix中,你可以通过下面的命令重新命名文件并创建一个新文件: ~~~ shell> mv hostname.log hostname-old.log ~~~ ~~~ shell> mysqladmin flush-logs ~~~ ~~~ shell> cp hostname-old.log to-backup-directory ~~~ ~~~ shell> rm hostname-old.log ~~~ 在Windows中,服务器打开日志文件期间你不能重新命名日志文件。你必须先停止服务器然后重新命名日志文件。然后,重启服务器来创建新的日志文件。 ### 5.11.3. 二进制日志 二进制日志以一种更有效的格式,并且是事务安全的方式包含更新日志中可用的所有信息。 二进制日志包含了所有更新了数据或者已经潜在更新了数据(例如,没有匹配任何行的一个DELETE)的所有语句。语句以“事件”的形式保存,它描述数据更改。 **注**释:二进制日志已经代替了老的更新日志,更新日志在MySQL 5.1中不再使用。 二进制日志还包含关于每个更新数据库的语句的执行时间信息。它不包含没有修改任何数据的语句。如果你想要记录所有语句(例如,为了识别有问题的查询),你应使用一般查询日志。参见[5.11.2节,“通用查询日志”](# "5.11.2. The General Query Log")。 二进制日志的主要目的是在恢复使能够最大可能地更新数据库,因为二进制日志包含备份后进行的所有更新。 二进制日志还用于在主复制服务器上记录所有将发送给从服务器的语句。参见[第6章:](#)[*MySQL中的复制*](# "Chapter 6. Replication in MySQL")。 运行服务器时若启用二进制日志则性能大约慢1%。但是,二进制日志的好处,即用于恢复并允许设置复制超过了这个小小的性能损失。 当用--log-bin[=*file_name*]选项启动时,**mysqld**写入包含所有更新数据的SQL命令的日志文件。如果未给出*file_name*值, 默认名为-bin后面所跟的主机名。如果给出了文件名,但没有包含路径,则文件被写入数据目录。建议指定一个文件名,原因参见[A.8.1节,“MySQL中的打开事宜”](# "A.8.1. Open Issues in MySQL")。 如果你在日志名中提供了扩展名(例如,--log-bin=*file_name.extension*),则扩展名被悄悄除掉并忽略。 **mysqld**在每个二进制日志名后面添加一个数字扩展名。每次你启动服务器或刷新日志时该数字则增加。如果当前的日志大小达到max_binlog_size,还会自动创建新的二进制日志。如果你正使用大的事务,二进制日志还会超过max_binlog_size:事务全写入一个二进制日志中,绝对不要写入不同的二进制日志中。 为了能够知道还使用了哪个不同的二进制日志文件,**mysqld**还创建一个二进制日志索引文件,包含所有使用的二进制日志文件的文件名。默认情况下与二进制日志文件的文件名相同,扩展名为'.index'。你可以用--log-bin-index[=*file_name*]选项更改二进制日志索引文件的文件名。当**mysqld**在运行时,不应手动编辑该文件;如果这样做将会使**mysqld**变得混乱。 可以用RESET MASTER语句删除所有二进制日志文件,或用PURGE MASTER LOGS只删除部分二进制文件。参见[13.5.5.5节,“RESET语法”](# "13.5.5.5. RESET Syntax")和[13.6.1节,“用于控制主服务器的SQL语句”](# "13.6.1. SQL Statements for Controlling Master Servers")。 二进制日志格式有一些已知限制,会影响从备份恢复。参见[6.7节,“复制特性和已知问题”](# "6.7. Replication Features and Known Problems")。 保存程序和触发器的二进制日志的描述参见[20.4节,“存储子程序和触发程序的二进制日志功能”](# "20.4. Binary Logging of Stored Routines and Triggers")。 可以使用下面的**mysqld**选项来影响记录到二进制日志知的内容。又见选项后面的讨论。 ·         --binlog-do-db=*db_name* 告诉主服务器,如果当前的数据库(即USE选定的数据库)是*db_name*,应将更新记录到二进制日志中。其它所有没有明显指定的数据库  被忽略。如果使用该选项,你应确保只对当前的数据库进行更新。 对于CREATE DATABASE、ALTER DATABASE和DROP DATABASE语句,有一个例外,即通过操作的数据库来决定是否应记录语句,而不是用当前的数据库。 一个不能按照期望执行的例子:如果用binlog-do-db=sales启动服务器,并且执行USE prices; UPDATE sales.january SET amount=amount+1000;,该语句不写入二进制日志。 ·         --binlog-ignore-db=*db_name* 告诉主服务器,如果当前的数据库(即USE选定的数据库)是*db_name*,不应将更新保存到二进制日志中。如果你使用该选项,你应确保只对当前的数据库进行更新。 一个不能按照你期望的执行的例子:如果服务器用binlog-ignore-db=sales启动,并且执行USE prices; UPDATE sales.january SET amount=amount+1000;,该语句不写入二进制日志。 类似于--binlog-do-db,对于CREATE DATABASE、ALTER DATABASE和DROP DATABASE语句,有一个例外,即通过操作的数据库来决定是否应记录语句,而不是用当前的数据库。 要想记录或忽视多个数据库,使用多个选项,为每个数据库指定相应的选项。 服务器根据下面的规则对选项进行评估,以便将更新记录到二进制日志中或忽视。请注意对于CREATE/ALTER/DROP DATABASE语句有一个例外。在这些情况下,根据以下规则,所*创建、*修改或删除的**数据库将代替当前的数据库。 1.    是否有binlog-do-db或binlog-ignore-db规则? ·         没有:将语句写入二进制日志并退出。 ·         有:执行下一步。 2.    有一些规则(binlog-do-db或binlog-ignore-db或二者都有)。当前有一个数据库(USE是否选择了数据库?)? ·         没有:*不要*写入语句,并退出。 ·         有:执行下一步。 3.    有当前的数据库。是否有binlog-do-db规则? ·         有:当前的数据库是否匹配binlog-do-db规则? o        有:写入语句并退出。 o        没有:不要写入语句,退出。 ·         No:执行下一步。 4.    有一些binlog-ignore-db规则。当前的数据库是否匹配binlog-ignore-db规则? ·         有:不要写入语句,并退出。 ·         没有:写入查询并退出。 例如,只用binlog-do-db=sales运行的服务器不将当前数据库不为sales的语句写入二进制日志(换句话说,binlog-do-db有时可以表示“忽视其它数据库”)。 如果你正进行复制,应确保没有从服务器在使用旧的二进制日志文件,方可删除它们。一种方法是每天一次执行**mysqladmin flush-logs**并删除三天前的所有日志。可以手动删除,或最好使用PURGE MASTER LOGS(参见[13.6.1节,“用于控制主服务器的SQL语句”](# "13.6.1. SQL Statements for Controlling Master Servers")),该语句还会安全地更新二进制日志索引文件(可以采用日期参数)。 具有SUPER权限的客户端可以通过SET SQL_LOG_BIN=0语句禁止将自己的语句记入二进制记录。参见[13.5.3节,“SET语法”](# "13.5.3. SET Syntax")。 你可以用**mysqlbinlog**实用工具检查二进制日志文件。如果你想要重新处理日志止的语句,这很有用。例如,可以从二进制日志更新MySQL服务器,方法如下: ~~~ shell> mysqlbinlog log-file | mysql -h server_name ~~~ 关于**mysqlbinlog**实用工具的详细信息以及如何使用它,参见[8.6节,“mysqlbinlog:用于处理二进制日志文件的实用工具”](# "8.6. mysqlbinlog — Utility for Processing Binary Log Files")。 如果你正使用事务,必须使用MySQL二进制日志进行备份,而不能使用旧的更新日志。 查询结束后、锁定被释放前或提交完成后则立即记入二进制日志。这样可以确保按执行顺序记入日志。 对非事务表的更新执行完毕后立即保存到二进制日志中。对于事务表,例如BDB或InnoDB表,所有更改表的更新(UPDATE、DELETE或INSERT) 被缓存起来,直到服务器接收到COMMIT语句。在该点,执行完COMMIT之前,**mysqld**将整个事务写入二进制日志。当处理事务的线程启动时,它为缓冲查询分配binlog_cache_size大小的内存。如果语句大于该值,线程则打开临时文件来保存事务。线程结束后临时文件被删除。 Binlog_cache_use状态变量显示了使用该缓冲区(也可能是临时文件)保存语句的事务的数量。Binlog_cache_disk_use状态变量显示了这些事务中实际上有多少必须使用临时文件。这两个变量可以用于将binlog_cache_size调节到足够大的值,以避免使用临时文件。 max_binlog_cache_size(默认4GB)可以用来限制用来缓存多语句事务的缓冲区总大小。如果某个事务大于该值,将会失败并 回滚。 如果你正使用更新日志或二进制日志,当使用CREATE ... SELECT or INSERT ... SELECT时,并行插入被转换为普通插入。这样通过在备份时使用日志可以确保重新创建表的备份。 请注意MySQL 5.1值的二进制日志格式与以前版本的MySQL不同,因为复制改进了。参见[6.5节,“不同MySQL版本之间的复制兼容性”](# "6.5. Replication Compatibility Between MySQL Versions")。 默认情况下,并不是每次写入时都将二进制日志与硬盘同步。因此如果操作系统或机器(不仅仅是MySQL服务器)崩溃,有可能二进制日志中最后的语句丢失了。要想防止这种情况,你可以使用sync_binlog全局变量(1是最安全的值,但也是最慢的),使二进制日志在每*N*次二进制日志写入后与硬盘同步。参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。即使sync_binlog设置为1,出现崩溃时,也有可能表内容和二进制日志内容之间存在不一致性。例如,如果使用InnoDB表,MySQL服务器处理COMMIT语句,它将整个事务写入二进制日志并将事务提交到InnoDB中。如果在两次操作之间出现崩溃,重启时,事务被InnoDB回滚,但仍然存在二进制日志中。可以用--innodb-safe-binlog选项解决该问题,可以增加InnoDB表内容和二进制日志之间的一致性。(注释:在MySQL 5.1中不需要--innodb-safe-binlog;由于引入了XA事务支持,该选项作废了)。 该选项可以提供更大程度的安全,还应对MySQL服务器进行配置,使每个事务的二进制日志(sync_binlog =1)和(默认情况为真)InnoDB日志与硬盘同步。该选项的效果是崩溃后重启时,在滚回事务后,MySQL服务器从二进制日志剪切 回滚的InnoDB事务。这样可以确保二进制日志反馈InnoDB表的确切数据等,并使从服务器保持与主服务器保持同步(不接收 回滚的语句)。 请注意即使MySQL服务器更新其它存储引擎而不是InnoDB,也可以使用--innodb-safe-binlog。在InnoDB崩溃恢复时,只从二进制日志中删除影响InnoDB表的语句/事务。如果崩溃恢复时MySQL服务器发现二进制日志变短了(即至少缺少一个成功提交的InnoDB事务),如果sync_binlog =1并且硬盘/文件系统的确能根据需要进行同步(有些不需要)则不会发生,则输出错误消息 ("二进制日志<名>比期望的要小")。在这种情况下,二进制日志不准确,复制应从主服务器的数据快照开始。 写入二进制日志文件和二进制日志索引文件的方法与写入MyISAM表相同。参见[A.4.3节,“MySQL处理磁盘满的方式”](# "A.4.3. How MySQL Handles a Full Disk")。 ### 5.11.4. 慢速查询日志 用--log-slow-queries[=*file_name*]选项启动时,**mysqld**写一个包含所有执行时间超过long_query_time秒的SQL语句的日志文件。获得初使表锁定的时间不算作执行时间。 如果没有给出*file_name*值, 默认未主机名,后缀为-slow.log。如果给出了文件名,但不是绝对路径名,文件则写入数据目录。 语句执行完并且所有锁释放后记入慢查询日志。记录顺序可以与执行顺序不相同。 慢查询日志可以用来找到执行时间长的查询,可以用于优化。但是,检查又长又慢的查询日志会很困难。要想容易些,你可以使用**mysqldumpslow**命令获得日志中显示的查询摘要来处理慢查询日志。 在MySQL 5.1的慢查询日志中,不使用索引的慢查询同使用索引的查询一样记录。要想防止不使用索引的慢查询记入慢查询日志,使用--log-short-format选项。参见[5.3.1节,“**mysqld**命令行选项”](# "5.3.1. mysqld Command-Line Options")。 在MySQL 5.1中,通过--log-slow-admin-statements服务器选项,你可以请求将慢管理语句,例如OPTIMIZE TABLE、ANALYZE TABLE和 ALTER TABLE写入慢查询日志。 用查询缓存处理的查询不加到慢查询日志中,因为表有零行或一行而不能从索引中受益的查询也不写入慢查询日志。 ### 5.11.5. 日志文件维护 MySQL服务器可以创建各种不同的日志文件,从而可以很容易地看见所进行的操作。参见[5.11节,“MySQL日志文件”](# "5.11. The MySQL Log Files")。但是,你必须定期清理这些文件,确保日志不会占用太多的硬盘空间。 当启用日志使用MySQL时,你可能想要不时地备份并删除旧的日志文件,并告诉MySQL开始记入新文件。参见[5.9.1节,“数据库备份”](# "5.9.1. Database Backups")。 在 Linux (Redhat)的安装上,你可为此使用mysql-log-rotate脚本。如果你从RPM分发安装**MySQL**,脚本应该自动被安装了。 在其它系统上,你必须自己安装短脚本,你可从**cron**等入手处理日志文件。 你可以通过**mysqladmin flush-logs**或SQL语句FLUSH LOGS来强制**MySQL**开始使用新的日志文件。 日志清空操作做下列事情: - 如果使用标准日志(--log)或慢查询日志(--log-slow-queries),关闭并重新打开日志文件。(默认为mysql.log和`hostname`-slow.log)。 - 如果使用更新日志(--log-update)或二进制日志(--log-bin),关闭日志并且打开有更高序列号的新日志文件。 如果你只使用更新日志,你只需要重新命名日志文件,然后在备份前清空日志。例如,你可以这样做: ~~~ shell> cd mysql-data-directory ~~~ ~~~ shell> mv mysql.log mysql.old ~~~ ~~~ shell> mysqladmin flush-logs ~~~ 然后做备份并删除“mysql.old”。 ### 5.12. 在同一台机器上运行多个MySQL服务器 [ 5.12.1. 在Windows下运行多个服务器](#)[ 5.12.2. 在Unix中运行多个服务器](#)[ 5.12.3. 在多服务器环境中使用客户端程序](#) 在一些情况下,你可能想要在同一台机器上运行多个**mysqld服务器**。你可能想要测试一个新的MySQL发布,同时不影响现有产品的设置。或者,你可能想使不同的用户访问来访问不同的**mysqld服务器**以便他们自己来管理。(例如,你可能是一个Internet服务提供商,希望为不同的客户来提供独立的MySQL安装)。 要想在一个单独的机器上运行多个服务器,每个服务器必须有唯一的各运行参数值。这些值可以在命令行中设置或在选项文件中设置。参见[4.3节,“指定程序选项”](# "4.3. Specifying Program Options")。 至少下面的选项对每个服务器必须是不同的: ·         --port=*port_num* --port控制着TCP/IP连接的端口号。 ·         --socket=*path* --socket控制Unix中的Unix套接字文件路径和在Windows中的命名管道名称。在Windows中,只有支持命名管道连接的服务器才需要明确指定管道名称。 ·         --shared-memory-base-name=*name* 该选项当前只在Windows中使用。它指定Windows服务器使用的、允许客户端通过共享内存来连接的共享内存名。 ·         --pid-file=*path* 该选项只在Unix中使用。它指出服务器在其中写入进程ID的文件名。 如果你使用下面的日志文件选项,对于每个服务器来说,它们必须是不同的: ·           --log=*path* ·         --log-bin=*path* ·         --log-update=*path* ·         --log-error=*path* ·         --bdb-logdir=*path* 日志文件选项的描述参见[5.11.5节,“日志文件维护”](# "5.11.5. Log File Maintenance")。 为了提高性能,你可以为每个服务器指定下面选项的不同的值,以便在物理磁盘之间平均分配负荷: ·         --tmpdir=*path* ·         --bdb-tmpdir=*path* 还推荐使用不同的临时目录,以便容易地确定哪个MySQL服务器创建了给定的临时文件。 一般情况,每个服务器应还使用不同的数据目录,可以通过--datadir=path选项来指定。 **警告:**一般情况,你决不要让两个服务器更新相同数据库中的数据。否则,如果你的操作系统不支持故障排除系统锁定,该可能会导致非常奇怪的结果。如果(不理会该警告)运行的多个服务器使用相同的数据目录并且启用了日志记录,你必须使用适当的选项来为每个服务器指定唯一的日志文件名。否则,服务器尝试用相同的文件来记录日志。请注意这种类型的设置只能在MyISAM和MERGE表上工作,对其它任何存储引擎不起作用。 多个服务器共享一个数据目录的警告也适用于NFS环境。允许多个MySQL服务器通过NFS访问一个共同的数据目录是一个*非常不好的主义*。 ·         主要问题是NFS存在速度瓶颈。它不是用于这种用途。 ·         用NFS的另一个冒险是你必须提出一个方法来确保两个或多个服务器不会相互干扰。NFS文件的锁定通常由lockd后台程序处理,但是目前,没有一个运行平台能够在每种情况下100%可靠地进行锁定。 使你更加容易:忘记在服务器之间通过NFS共享数据目录。一个较好的解决方案是使用包含几个CPU并且和使用有效处理多线程的操作系统的机器。 如果在不同的位置有多个MySQL的安装,一般情况可以用--basedir=path选项为每个服务器指定基本安装目录,使每个服务器使用不同的数据目录、日志文件和PID文件。(所有这些值的 默认值相对于根目录来确定)。那样的话, 你唯一需要指定的其它选项是--socket和--port选项。例如,假如使用tar文件二进制分发版安装不同的MySQL版本。这些安装在不同的位置,因此可以使用各个安装服务器相应的根目录中的**bin/mysqld_safe**命令**来**启动服务器。**mysqld_safe**确定正确的--basedir选项传递给**mysqld**,你仅需要为**mysqld_safe**指定--socket和--port选项。 正如下面几节所讨论的那样,可以通过设置环境变量或用指定的命令行选项来启动更多的服务器。但是,如果你需要在一个更稳定的基础上运行多个服务器,一个更方便的方法是使用选项文件来为每个服务器指定那些选项值,它对每个服务器必须是唯一的。 ### 5.12.1. 在Windows下运行多个服务器 [ 5.12.1.1. 在命令行中启动多个Windows服务器](#)[ 5.12.1.2. 做为服务启动多个Windows服务器](#) 在Windows中,可以从命令行手动启动来运行多个服务器,每个服务器使用合适的操作参数。在基于Windows NT的系统中,安装几个服务器时,你还有将多个服务器安装为Windows服务并运行的选项。关于从命令行运行MySQL服务器或作为服务运行的一般说明在 [ 2.3节,“在Windows上安装MySQL”](# "2.3. Installing MySQL on Windows")中给出。本节描述怎样确保你用不同的启动选项值(对于每个服务器必须是唯一的,例如数据目录)启动各个服务器。这些选项的描述见[5.12节,“在同一台机器上运行多个MySQL服务器”](# "5.12. Running Multiple MySQL Servers on the Same Machine")。 #### 5.12.1.1. 在命令行中启动多个Windows服务器 为了从命令行手动启动多个服务器,可以在命令行中或在选项文件中指定适当的选项。把选项放在选项文件中比较方便,但是需要确保每个服务器可以获得自己的选项。为了实现,为每个创建一个选项文件,并且运行服务时通过--defaults-file选项告诉服务器选项文件名。 假设你想要在端口3307使用数据目录C:\mydata1运行**mysqld**,并且想在端口3308使用数据目录C:\mydata1运行**mysqld-max**。(要想这样做,启动服务器之前要确保,每个数据目录存在并且有自己的mysql数据库拷贝,它包含 授权表)。 然后创建两个选项文件。例如,创建一个文件名为C:\my-opts1.cnf的配置文件,它看起来象这个样子: ~~~ [mysqld] ~~~ ~~~ datadir = C:/mydata1 ~~~ ~~~ port = 3307 ~~~ 创建第二个文件名为C:\my-opts1.cnf的配置文件,它看起来象这个样子: ~~~ mysqld] ~~~ ~~~ datadir = C:/mydata2 ~~~ ~~~ port = 3308 ~~~ 然后,用它们自己的选项文件启动每个服务器: ~~~ C:\> C:\mysql\bin\mysqld --defaults-file=C:\my-opts1.cnf ~~~ ~~~ C:\> C:\mysql\bin\mysqld-max --defaults-file=C:\my-opts2.cnf ~~~ 在NT中,每个服务器在前台启动(服务器退出前,不会显示新的提示符);需要在两个控制台窗口中执行这两个命令。 要想关闭服务器,必须连接到相应的端口号: C:\> **C:\mysql\bin\mysqladmin --port=3307 shutdown** C:\> **C:\mysql\bin\mysqladmin --port=3308 shutdown** 如刚才所讨论的,服务器配置允许客户端通过TCP/IP来连接。如果你的Windows版本支持命名管道并且你想允许命名管道连接,使用**mysqld-nt**或**mysqld-max-nt**服务器并指定启用命名管道并且指定管道名的选项。支持命名管道连接的每个服务器必须使用一个唯一的管道名。例如,C:\my-opts1.cnf文件可能象这样来书写: ~~~ [mysqld] ~~~ ~~~ datadir = C:/mydata1 ~~~ ~~~ port = 3307 ~~~ ~~~ enable-named-pipe ~~~ ~~~ socket = mypipe1 ~~~ 然后,这样启动服务器: ~~~ C:\> C:\mysql\bin\mysqld-nt --defaults-file=C:\my-opts1.cnf ~~~ 同样修改第2个服务器使用的C:\my-opts2.cnf文件。 #### 5.12.1.2. 做为服务启动多个Windows服务器 在基于NT的系统中,MySQL服务器可以以Windows服务的方式来运行。安装、控制和删除单个MySQL服务的过程描述见[2.3.12节,“以Windows服务方式启动MySQL”](# "2.3.12. Starting MySQL as a Windows Service")。 你还可以以服务的方式安装多个MySQL服务器。此时,除了所有参数对每个服务器必须是唯一的,你还必须确保每个服务器使用不同的服务名。 在下面的说明中,假设你想要运行**mysqld-nt**服务器的两个不同的版本,它们分别安装在C:\mysql-4.1.8和C:\mysql-5.1.2-alpha目录中。(可能存在这种情况,如果你正在运行版本4.1.8作为你的产品服务器,还想使用5.1.2-alpha版本来进行测试)。 当用--install或--install-manual选项安装一个MySQL服务时,应遵从以下原则: ·         如果你没有指定服务名,服务器使用默认的MySQL服务名,从标准选项文件的[mysqld]组中读取选项。 ·         如果你在--install选项后指定了服务名,服务器忽略[mysqld]选项组,从具有相同名的组中读取选项作为服务名。服务器从标准选项文件中读取选项。 ·         如果你在服务名后面指定一个--defaults-file选项,服务器忽略标准选项文件,只从命名的文件的[mysqld]组读取选项。 **注**释:MySQL 4.0.17之前,只有使用默认服务名(MySQL)安装的一个服务器或使用服务名**mysqld**显式安装的一个服务器从标准选项文件读[mysqld]组。到4.0.17时,如果服务器读标准选项文件,则它们均读[mysqld]组,即使它们安装时使用了另一个服务名。这样允许你为选项使用[mysqld]组,用于所有MySQL服务器,并将根据每个服务器命名的选项组用于该服务器,即使用那个服务名安装的服务器。 根据前面叙述,你可以通过几个方法来设置多个服务器。下面的说明描述了一些示例。在尝试之前,应确保你首先关闭并且卸载了所有已有的MySQL服务器。 ·         **方法1:**在一个标准选项文件中指定所有服务器选项。要想这样做,为每个服务器使用不同的服务名。假设你想使用服务名mysqld1运行4.1.8版的**mysqld-nt并**使用服务名mysqld2运行5.1.2-alpha版的**mysqld-n****t**。在这种情况下,你可以为4.1.8使用[mysqld1]组,为5.1.2-alpha使用[mysqld2]组。例如,你可以象这样建立 C:\my.cnf文件: ~~~ ·                # options for mysqld1 service ~~~ ~~~ ·                [mysqld1] ~~~ ~~~ ·                basedir = C:/mysql-4.1.8 ~~~ ~~~ ·                port = 3307 ~~~ ~~~ ·                enable-named-pipe ~~~ ~~~ ·                socket = mypipe1 ~~~ ~~~ ·                  ~~~ ~~~ ·                # options for mysqld2 service ~~~ ~~~ ·                [mysqld2] ~~~ ~~~ ·                basedir = C:/mysql-5.1.2-alpha ~~~ ~~~ ·                port = 3308 ~~~ ~~~ ·                enable-named-pipe ~~~ ~~~ ·                socket = mypipe2 ~~~ 如下面所示安装服务器,使用服务器的全路径名来确保Windows为每个服务注册正确的可执行程序: ~~~ C:\> C:\mysql-4.1.8\bin\mysqld-nt --install mysqld1 ~~~ ~~~ C:\> C:\mysql-5.1.2-alpha\bin\mysqld-nt --install mysqld2 ~~~ 为了启动服务器,使用服务管理器,或用带有适当的服务名的**NET START**: C:\> **NET START mysqld1** C:\> **NET START mysqld2** 要想停止服务,使用服务管理器,或用带有适当的服务名的**NET STOP**: ~~~ C:\> NET STOP mysqld1 ~~~ ~~~ C:\> NET STOP mysqld2 ~~~ ·         **方法2:**为每个服务器用不同的文件指定选项,当你安装服务时使用--defaults-file告诉每个服务器使用什么文件。此时,每个文件应用一个[mysqld]组列出选项。 使用这种方法为4.1.8版本的**mysqld-nt**指定选项,应象这样创建一个C:\my-opts1.cnf文件: ~~~ [mysqld] ~~~ ~~~ basedir = C:/mysql-4.1.8 ~~~ ~~~ port = 3307 ~~~ ~~~ enable-named-pipe ~~~ ~~~ socket = mypipe1 ~~~ 对于5.1.2-alpha版的**mysqld-nt**,象这样创建一个C:\my-opts2.cnf文件: ~~~ [mysqld] ~~~ ~~~ basedir = C:/mysql-5.1.2-alpha port = 3308 ~~~ ~~~ enable-named-pipe ~~~ ~~~ socket = mypipe2 ~~~ 安装服务如下(在一个单一行中输入每个命令): ~~~ C:\> C:\mysql-4.1.8\bin\mysqld-nt -- installmysqld1 ~~~ ~~~            --defaults-file=C:\my-opts1.cnf ~~~ ~~~ C:\> C:\mysql-5.1.2-alpha\bin\mysqld-nt -- installmysqld2 ~~~ ~~~            --defaults-file=C:\my-opts2.cnf ~~~ 当你作为服务安装一个MySQL服务器时,要想使用--defaults-file选项,你必须在此选项之前加服务名。 安装服务后,按照与前面的示例相同的方法启动和停止。 要想卸载多个服务,对每个服务使用**mysqld --remove**,在--remove选项后指定服务名。如果服务名是 默认的(MySQL),你可以不指定。 ### 5.12.2. 在Unix中运行多个服务器 在Unix中运行多个服务器最容易的方法是使用不同的TCP/IP端口s和Unix套接字文件编译,因此每个实例在不同的网络接口侦听。另外,每个安装应在不同的基础目录中编译,那将自动为你的每个服务器产生使用不同的编译进来的数据目录、日志文件和PID文件位置。 假设一个现有的4.1.8版本服务器配置为默认TCP/IP端口号(3306)和Unix套接字文件(/tmp/mysql.sock)。要想配置一个新的5.1.2-alpha版的服务器来使用不同的操作参数,使用一个**configure**命令,大概象这样使用: ~~~ shell> ./configure --with-tcp-port=port_number \ ~~~ ~~~              --with-unix-socket-path=file_name \ ~~~ ~~~              --prefix=/usr/local/mysql-5.1.2-alpha ~~~ 这里,*port_number*和*file_name*必须不同于默认TCP/IP端口号和Unix套接字文件路径名,并且--prefix值应指定一个不同于现有MySQL安装目录的安装目录。 如果你有一个MySQL服务器正侦听一个给定的端口号,你可以使用下面的命令来找出针对一些重要配置变量它使用了那些操作参数,包括基础目录和Unix套接字文件名: ~~~ shell> mysqladmin --host=host_name --port=port_number variables ~~~ 通过该命令显示的信息,当配置其它服务器时,你可以告诉服务器该选项没有使用的值。 请注意,如果你指定localhost作为一个主机名,**mysqladmin**默认使用Unix套接字文件连接,而不是TCP/IP。从 MySQL 4.1开始,通过--protocol= TCP | SOCKET | PIPE | MEMORY}选项,你可以显示地指定连接协议。 如果只是用一个不同的Unix套接字文件和TCP/IP端口号启动,不必编译新的MySQL服务器。还可以在运行时指定这些值。这样做的一个方法是使用命令行选项: ~~~ shell> mysqld_safe --socket=file_name --port=port_number ~~~ 要启动第二个服务器,提供不同的--socket和--port选项值,并且传递一个--datadir=path选项给**mysqld_safe**,以便服务器使用一个不同的数据目录。 达到相似效果的另一个方法是使用环境变量来设置 Unix套接字文件名和TCP/IP端口号: ~~~ shell> MYSQL_UNIX_PORT=/tmp/mysqld-new.sock ~~~ ~~~ shell> MYSQL_TCP_PORT=3307 ~~~ ~~~ shell> export MYSQL_UNIX_PORT MYSQL_TCP_PORT ~~~ ~~~ shell> mysql_install_db --user=mysql ~~~ ~~~ shell> mysqld_safe --datadir=/path/to/datadir & ~~~ 这是一个快速启动第二个服务器以用于测试的方法。该方法的最大好处是环境变量设定值适用于你从相同的shell调用的任何客户端程序。因而,那些客户端连接自动指向第二个服务器! [ 附录F:*环境变量*](# "Appendix F. Environment Variables")包括你可以使用的影响**mysqld**的其它环境变量列表**。** 对于自动服务器启动,对于每个服务器,机器引导时执行的启动脚本应执行下面的命令,每个命令用一个相应的选项文件路径: ~~~ mysqld_safe --defaults-file=path ~~~ 每个选项文件应包含一个给定服务器特定的选项值。 在Unix中,**mysqld_multi**脚本是启动多个服务器的另一个方法。参见[5.1.5节,“mysqld_multi:管理多个MySQL服务器的程序”](# "5.1.5. mysqld_multi — Program for Managing Multiple MySQL Servers")。 ### 5.12.3. 在多服务器环境中使用客户端程序 当你想要用一个客户端程序连接一个MySQL服务器时,该服务器侦听不同的网络接口,而不是编译到你的客户端的网络接口,你可以使用下面的方法: ·         启动客户端,用--host=*host_name* --port=*port_number*通过TCP/IP来连接一个远程服务器,用--host=127.0.0.1 --port=*port_number*通过TCP/IP来连接一个本地服务器,或者用--host=localhost --socket=*file_name*通过一个Unix套接字文件或一个Windows命名管道来连接一个本地服务器。 ·         从MySQL 4.1起,启动客户端时用--protocol=tcp通过TCP/IP来连接,用--protocol=socket通过一个Unix套接字文件来连接,用--protocol=pipe通过一个命名管道来连接,或用--protocol=memory通过共享内存来连接。对于TCP/IP连接,你可能还需要指定--host和--port选项。对于其它类型的连接,你可能需要指定一个--socket选项来指定一个Unix套接字文件或命名管道名,或者一个--shared-memory-base-name选项来指定共享内存名。共享内存连接仅在Windows中支持。 ·         在Unix中,在你启动客户端之前,设置MYSQL_UNIX_PORT和MYSQL_TCP_PORT环境变量来指定Unix套接字文件和TCP/IP端口号。如果你经常使用具体的套接字文件或端口号,你可以在.login文件中放置命令来设置环境变量以便你每次登录时该命令起作用。参见[附录F:*环境变量*](# "Appendix F. Environment Variables")。 ·         在一个选项文件的[client]组中指定默认Unix套接字文件和TCP/IP端口号。例如,你可以在Windows中使用C:\my.cnf文件,或在Unix中主目录内使用.my.cnf文件。参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。 ·         在C程序中,在mysql_real_connect()调用时,你可以指定套接字文件或端口号参数。通过调用mysql_options(),你还可以有程序读选项文件。参见[25.2.3节,“C API函数描述”](# "25.2.3. C API Function Descriptions")。 ·         如果你正在使用Perl DBD::mysql模块,你可以从MySQL选项文件中读取选项。例如: ~~~ ·                $dsn = "DBI:mysql:test;mysql_read_default_group=client;" ~~~ ~~~ ·                        . "mysql_read_default_file=/usr/local/mysql/data/my.cnf"; ~~~ ~~~ ·                    $dbh = DBI->connect($dsn, $user, $password); ~~~ 参见[25.4节,“MySQL Perl API”](# "25.4. MySQL Perl API")。 其它程序接口可以为读选项文件提供相似的功能。 ### 5.13. MySQL查询高速缓冲 [ 5.13.1. 查询高速缓冲如何工作](#)[ 5.13.2. 查询高速缓冲SELECT选项](#)[ 5.13.3. 查询高速缓冲配置](#)[ 5.13.4. 查询高速缓冲状态和维护](#) 查询缓存存储SELECT查询的文本以及发送给客户端的相应结果。如果随后收到一个相同的查询,服务器从查询缓存中重新得到查询结果,而不再需要解析和执行查询。 如果你有一个不经常改变的表并且服务器收到该表的大量相同查询,查询缓存在这样的应用环境中十分有用。对于许多Web服务器来说存在这种典型情况,它根据数据库内容生成大量的动态页面。 **注**释:查询缓存不返回旧的数据。当表更改后,查询缓存值的相关条目被清空。 **注**释:如果你有许多**mysqld**服务器更新相同的MyISAM表,在这种情况下查询缓存不起作用。 **注**释:查询缓存不适用于服务器方编写的语句。如果正在使用服务器方编写的语句,要考虑到这些语句将不会应用查询缓存。参见 [ 25.2.4节,“C API预处理语句”](# "25.2.4. C API Prepared Statements")。 下面是查询缓存的一些性能数据。这些结果是在Linux Alpha 2 x 500MHz系统(2GB RAM,64MB查询缓存)上运行MySQL基准组件产生的。 ·         如果执行的所有查询是简单的(如从只有一行数据的表中选取一行),但查询是不同的,查询不能被缓存,查询缓存激活率是13%。这可以看作是最坏的情形。在实际应用中,查询要复杂得多,因此,查询缓存使用率一般会很低。 ·         从只有一行的表中查找一行数据时,使用查询缓存比不使用速度快238%。这可以看作查询使用缓存时速度提高最小的情况。 服务器启动时要禁用查询缓存,设置query_cache_size系统变量为0。禁用查询缓存代码后,没有明显的速度提高。编译MySQL时,通过在**configure中**使用--without-query-cache选项,可以从服务器中彻底去除查询缓存能力。 ### 5.13.1. 查询高速缓冲如何工作 本节描述查询缓存的工作原理。[5.13.3节,“查询高速缓冲配置”](# "5.13.3. Query Cache Configuration")描述了怎样控制是否使用查询缓存。 查询解析之前进行比较,因此下面的两个查询被查询缓存认为是不相同的: ~~~ SELECT * FROM tbl_name ~~~ ~~~ Select * from tbl_name ~~~ 查询必须是完全相同的(逐字节相同)才能够被认为是相同的。另外,同样的查询字符串由于其它原因可能认为是不同的。使用不同的数据库、不同的协议版本或者不同 默认字符集的查询被认为是不同的查询并且分别进行缓存。 从查询缓存中提取一个查询之前,MySQL检查用户对所有相关数据库和表的SELECT权限。如果没有权限,不使用缓存结果。 如果从查询缓存中返回一个查询结果,服务器把Qcache_hits状态变量的值加一,而不是Com_select变量。参见[5.13.4节,“查询高速缓冲状态和维护”](# "5.13.4. Query Cache Status and Maintenance")。 如果一个表被更改了,那么使用那个表的所有缓冲查询将不再有效,并且从缓冲区中移出。这包括那些映射到改变了的表的使用MERGE表的查询。一个表可以被许多类型的语句更改,例如INSERT、UPDATE、DELETE、TRUNCATE、ALTER TABLE、DROP TABLE或DROP DATABASE。 COMMIT执行完后,被更改的事务InnoDB表不再有效。 使用InnoDB表时,查询缓存也在事务中工作,使用该表的版本号来检测其内容是否仍旧是当前的。 在MySQL 5.1中,视图产生的查询被缓存。 SELECT SQL_CALC_FOUND_ROWS ...和SELECT FOUND_ROWS() type类型的查询使用查询缓存。即使因创建的行数也被保存在缓冲区内,前面的查询从缓存中提取,FOUND_ROWS()也返回正确的值。 如果一个查询包含下面函数中的任何一个,它不会被缓存: <table border="1" cellpadding="0" id="table19"><tr><td> <p> <span>BENCHMARK()</span></p></td> <td> <p> <span>CONNECTION_ID()</span></p></td> <td> <p> <span>CURDATE()</span></p></td> </tr><tr><td> <p> <span>CURRENT_DATE()</span></p></td> <td> <p> <span>CURRENT_TIME()</span></p></td> <td> <p> <span> CURRENT_TIMESTAMP()</span></p></td> </tr><tr><td> <p> <span>CURTIME()</span></p></td> <td> <p> <span>DATABASE()</span></p></td> <td> <p>带一个参数的<span>ENCRYPT()</span></p></td> </tr><tr><td> <p> <span>FOUND_ROWS()</span></p></td> <td> <p> <span>GET_LOCK()</span></p></td> <td> <p> <span>LAST_INSERT_ID()</span></p></td> </tr><tr><td> <p> <span>LOAD_FILE()</span></p></td> <td> <p> <span>MASTER_POS_WAIT()</span></p></td> <td> <p> <span>NOW()</span></p></td> </tr><tr><td> <p> <span>RAND()</span></p></td> <td> <p> <span>RELEASE_LOCK()</span></p></td> <td> <p> <span>SYSDATE()</span></p></td> </tr><tr><td> <p>不带参数的<span>UNIX_TIMESTAMP()</span></p></td> <td> <p> <span>USER()</span></p></td> <td> <p><span> </span></p></td> </tr></table> 在下面的这些条件下,查询也不会被缓存: ·         引用自定义函数(UDFs)。 ·         引用自定义变量。 ·         引用mysql系统数据库中的表。 ·         下面方式中的任何一种: ~~~ SELECT ...IN SHARE MODE ~~~ ~~~ SELECT ...FOR UPDATE ~~~ ~~~ SELECT ...INTO OUTFILE ... ~~~ ~~~ SELECT ...INTO DUMPFILE ... ~~~ ~~~ SELECT * FROM ...WHERE autoincrement_col IS NULL ~~~ 最后一种方式不能被缓存是因为它被用作为ODBC工作区来获取最近插入的ID值。参见[26.1.14.1节,“如何在ODBC中获取AUTO_INCREMENT列的值``”](# "26.1.14.1. How to Get the Value of an AUTO_INCREMENT Column in ODBC")。 ·          被作为编写好的语句,即使没有使用占位符。例如,下面使用的查询: ~~~ char *my_sql_stmt = "SELECT a,b FROM table_c"; ~~~ ~~~    /* ...*/ ~~~ ~~~ mysql_stmt_prepare(stmt,my_sql_stmt,strlen(my_sql_stmt)); ~~~ 不被缓存。参见[25.2.4节,“C API预处理语句”](# "25.2.4. C API Prepared Statements")。 ·         使用TEMPORARY表。 ·         不使用任何表。 ·         用户有某个表的列级权限。 ### 5.13.2. 查询高速缓冲SELECT选项 可以在SELECT语句中指定查询缓存相关选项: ·          SQL_CACHE 如果query_cache_type系统变量的值是ON或DEMAND,查询结果被缓存。 ·          SQL_NO_CACHE 查询结果不被缓存。 示例: ~~~ SELECT SQL_CACHE id, name FROM customer; ~~~ ~~~ SELECT SQL_NO_CACHE id, name FROM customer; ~~~ ### 5.13.3. 查询高速缓冲配置 通过have_query_cache服务器系统变量指示查询缓存是否可用: ~~~ mysql> SHOW VARIABLES LIKE 'have_query_cache'; ~~~ ~~~ +------------------+-------+ ~~~ ~~~ | Variable_name    | Value | ~~~ ~~~ +------------------+-------+ ~~~ ~~~ | have_query_cache | YES   | ~~~ ~~~ +------------------+-------+ ~~~ 即使禁用查询缓存,当使用标准 MySQL二进制时,这个值总是YES。 其它几个系统变量控制查询缓存操作。当启动**mysqld**时,这些变量可以在选项文件或者命令行中设置。所有查询缓存系统变量名以query_cache_ 开头。它们的详细描述见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables"),还给出了额外的配置信息。 为了设置查询缓存大小,设置query_cache_size系统变量。设置为0表示禁用查询缓存。 默认缓存大小设置为0;也就是禁用查询缓存。 当设置query_cache_size变量为非零值时,应记住查询缓存至少大约需要40KB来分配其数据结构。(具体大小取决于系统结构)。如果你把该值设置的太小,将会得到一个警告,如本例所示: mysql> **SET GLOBAL query_cache_size = 40000;** Query OK, 0 rows affected, 1 warning (0.00 sec)   mysql> **SHOW WARNINGS\G** *************************** 1. row ***************************   Level: Warning    Code: 1282 Message: Query cache failed to set size 39936; new query cache size is 0   mysql> **SET GLOBAL query_cache_size = 41984;** Query OK, 0 rows affected (0.00 sec)   mysql> **SHOW VARIABLES LIKE 'query_cache_size';** +------------------+-------+ | Variable_name    | Value | +------------------+-------+ | query_cache_size | 41984 | +------------------+-------+ 如果查询缓存大小设置为大于0,query_cache_type变量影响其工作方式。这个变量可以设置为下面的值: ·         0或OFF将阻止缓存或查询缓存结果。 ·         1或ON将允许缓存,以SELECT SQL_NO_CACHE开始的查询语句除外。 ·         2或DEMAND,仅对以SELECT SQL_CACHE开始的那些查询语句启用缓存。 设置query_cache_type变量的GLOBAL值将决定更改后所有连接客户端的缓存行为。具体客户端可以通过设置query_cache_type变量的会话值控制它们本身连接的缓存行为。例如,一个客户可以禁用自己的查询缓存,方法如下: mysql> **SET SESSION query_cache_type = OFF;** 要控制可以被缓存的具体查询结果的最大值,应设置query_cache_limit变量。 默认值是1MB。 当一个查询结果(返回给客户端的数据)从查询缓冲中提取期间,它在查询缓存中排序。因此,数据通常不在大的数据块中处理。查询缓存根据数据排序要求分配数据块,因此,当一个数据块用完后分配一个新的数据块。因为内存分配操作是昂贵的(费时的),所以通过query_cache_min_res_unit系统变量给查询缓存分配最小值。当查询执行时,最新的结果数据块根据实际数据大小来确定,因此可以释放不使用的内存。根据你的服务器执行查询的类型,你会发现调整query_cache_min_res_unit变量的值是有用的: ·         query_cache_min_res_unit默认值是4KB。这应该适合大部分情况。 ·         如果你有大量返回小结果数据的查询,默认数据块大小可能会导致内存碎片,显示为大量空闲内存块。由于缺少内存,内存碎片会强制查询缓存从缓存内存中修整(删除)查询。这时,你应该减少query_cache_min_res_unit变量的值。空闲块和由于修整而移出的查询的数量通过Qcache_free_blocks和Qcache_lowmem_prunes变量的值给出。 ·          如果大量查询返回大结果(检查 Qcache_total_blocks和Qcache_queries_in_cache状态变量),你可以通过增加query_cache_min_res_unit变量的值来提高性能。但是,注意不要使它变得太大(参见前面的条目)。 ### 5.13.4. 查询高速缓冲状态和维护 可以使用下面的语句检查MySQL服务器是否提供查询缓存功能: mysql> **SHOW VARIABLES LIKE 'have_query_cache';** +------------------+-------+ | Variable_name    | Value | +------------------+-------+ | have_query_cache | YES   | +------------------+-------+ 可以使用FLUSH QUERY CACHE语句来清理查询缓存碎片以提高内存使用性能。该语句不从缓存中移出任何查询。 RESET QUERY CACHE语句从查询缓存中移出所有查询。FLUSH TABLES语句也执行同样的工作。 为了监视查询缓存性能,使用SHOW STATUS查看缓存状态变量: ~~~ mysql> SHOW STATUS LIKE 'Qcache%'; ~~~ ~~~ +-------------------------+--------+ ~~~ ~~~ |变量名                   |值 | ~~~ ~~~ +-------------------------+--------+ ~~~ ~~~ | Qcache_free_blocks      | 36     | ~~~ ~~~ | Qcache_free_memory      | 138488 | ~~~ ~~~ | Qcache_hits             | 79570  | ~~~ ~~~ | Qcache_inserts          | 27087  | ~~~ ~~~ | Qcache_lowmem_prunes    | 3114   | ~~~ ~~~ | Qcache_not_cached       | 22989  | ~~~ ~~~ | Qcache_queries_in_cache | 415    | ~~~ ~~~ | Qcache_total_blocks     | 912    | ~~~ ~~~ +-------------------------+--------+ ~~~ 这些变量的描述见[5.3.4节,“服务器状态变量”](# "5.3.4. Server Status Variables")。这里描述它们的一些应用。 SELECT查询的总数量等价于: ~~~ Com_select ~~~ ~~~ + Qcache_hits ~~~ ~~~ + queries with errors found by parser ~~~ Com_select的值等价于: ~~~ Qcache_inserts ~~~ ~~~ + Qcache_not_cached ~~~ ~~~ + queries with errors found during columns/rights check ~~~ 查询缓存使用长度可变块,因此Qcache_total_blocks和Qcache_free_blocks可以显示查询缓存内存碎片。执行FLUSH QUERY CACHE后,只保留一个空闲块。 每个缓存查询至少需要两个块(一个块用于查询文本,一个或多个块用于查询结果)。并且,每一个查询使用的每个表需要一个块。但是,如果两个或多个查询使用相同的表,仅需要分配一个块。 Qcache_lowmem_prunes状态变量提供的信息能够帮助你你调整查询缓存的大小。它计算为了缓存新的查询而从查询缓冲区中移出到自由内存中的查询的数目。查询缓冲区使用最近最少使用(LRU)策略来确定哪些查询从缓冲区中移出。调整信息在[5.13.3节,“查询高速缓冲配置”](# "5.13.3. Query Cache Configuration")中给出。 这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问[dev.mysql.com](http://dev.mysql.com/doc/mysql/en)。 原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。