### 附录A:问题和常见错误
在本附录中,列出了一些你可能会遇到的常见问题和错误消息。并介绍了确定故障原因的方法,以及为解决问题所应采取的措施。
### A.1. 如何确定导致问题的原因
当你遇到问题时,首先要做的是找出导致问题的程序和设备部件:
· 如果遇到下述征兆之一,或许是因为硬件问题(如内存、主板、CPU或硬盘)或内核问题:
1. 键盘不工作。正常情况下可通过按Caps Lock建进行检查。如果Caps Lock的点亮状态未改变,就需要更换键盘(在此之前,应尝试重启计算机,并检查与键盘相连的所有电缆)。
2. 鼠标指针不移动。
3. 机器未对远程机器的Ping命令做出应答。
4. 与MySQL无关的其他程序工作不正常。
5. 系统意外重启(有问题的用户级程序应不能使系统出现严重问题)。
在该情况下,应检查所有的电缆并运行某些诊断工具,对你的硬件进行检查!此外,还应检查是否有能够解决问题的、适用于你的操作系统的补丁、更新或服务包。请检查所有的库(如glibc)是否是最新的。
使用配备ECC内存的机器以便尽早发现问题总是个好主意。
· 如果键盘已锁定,可从另一台机器登录到你的机器,并执行kbd_mode –a,或许能恢复。
· 请检查系统的日志文件(/var/log/messages或类似物)以找出问题的原因。如果你认为问题出在MySQL中,应检查MySQL的日志文件。请参见[5.11节,“MySQL日志文件”](# "5.11. The MySQL Log Files")。
· 如果你不认为存在硬件问题,应尝试找出导致问题的原因。请使用**top**、**ps**、任务管理器或类似程序,以检查哪个程序占用了所有CPU时间或锁定了机器。
· 使用**top**、**df**或类似程序检查是否内存不够、磁盘空间不足、文件描述符缺乏、或其他关键资源缺少。
· 如果问题是失去控制的进程,应尝试杀死它。如果杀不死进程,或许是因为操作系统中存在缺陷。
如果在检查了所有其他可能性之后,并得出结论问题是由MySQL服务器或MySQL客户端导致的,应创建提供给我方的邮件列表或支持团队的缺陷报告。在缺陷报告中,请详细描述系统的行为,以及你认为发生了什么情况。+3.
还应阐明为什么你认为是MySQL导致了问题。请考虑本章介绍的所有情况。准确阐明当你检查系统时问题是如何出现的。对于程序和日志文件的任何输出和错误消息,请使用“复制和粘贴”方法。
尽量详细描述不工作的程序,以及你所见到的所有征兆。我们过去收到过很多仅说明“系统不工作”的缺陷报告。这不会为我们提供有助于解决问题的信息。
如果程序失败,了解下述信息总是有用的:
· 有嫌疑的程序是否出现了分段故障(是否转储内核)?
· 程序是否占用了所有可用的CPU时间?用**top**.进行检查。让程序运行一段时间,或许能简单地评估某些事是否是计算密集性的。
· 如果问题是因**mysqld**服务器导致的,使用**mysqladmin -u root ping**或**mysqladmin -u root processlist**是否能获得服务器的响应?
· 当你尝试连接到MySQL服务器(例如,mysql)时,客户端程序给出的信息是什么?客户端是否堵塞?是否获得了来自程序的任何输出?
发送缺陷报告时,请遵循[1.7.1.2节,“请教问题或通报缺陷”](# "1.7.1.2. Asking Questions or Reporting Bugs")中给出的说明。
### A.2. 使用MySQL程序时的常见错误
[A.2.1. 拒绝访问](#)[A.2.2. 无法连接到[local] MySQL服务器](#)[A.2.3. 客户端不支持鉴定协议](#)[ A.2.4. 输入密码时出现密码错误](#)[A.2.5. 主机的hos_t_name被屏蔽_](#)[A.2.6. 连接数过多](#)[A.2.7. 内存溢出](#)[A.2.8. MySQL服务器不可用](#)[A.2.9. 信息包过大](#)[ A.2.10. 通信错误和失效连接](#)[A.2.11. 表已满](#)[A.2.12. 无法创建文件/写入文件](#)[A.2.13. 命令不同步](#)[A.2.14. 忽略用户](#)[A.2.15. 表tbl_na_me不存在_](#)[A.2.16. 无法初始化字符集](#)[ A.2.17. 文件未找到](#)
本节列出了用户运行MySQL服务器时常会遇到的一些错误。尽管问题是在你尝试运行客户端时出现的,但对很多问题的解决方案来说,需要更改MySQL服务器的配置。
### A.2.1. 拒绝访问
导致拒绝访问错误的原因很多。该错误常与连接时服务器允许客户端使用的MySQL账户有关。请参见[5.7.8节,“拒绝访问错误的原因``”](# "5.7.8. Causes of Access denied Errors")。请参见[5.7.2节,“权限系统工作原理”](# "5.7.2. How the Privilege System Works")。
### A.2.2. 无法连接到[local] MySQL服务器
[A.2.2.1. 在Windows上与MySQL服务器的连接失败](#)
Unix平台上的MySQL客户端能够以两种不同的方式连接到**mysqld**服务器:通过文件系统中的文件(默认为/tmp/mysql.sock)使用Unix套接字进行连接,或通过端口号使用TCP/IP进行连接。Unix套接字文件的连接速度比TCP/IP快,但仅能在与相同计算机上的服务器相连时使用。如果未指定指定主机名或指定了特殊的主机名localhost,将使用Unix套接字。
如果MySQL服务器运行在Windows 9x或Me上,仅能通过TCP/IP进行连接。如服务器运行在Windows NT、2000、XP或2003上,而且使用--enable-named-pipe选项启动,如果在运行服务器的机器上运行客户端,也能使用命名管道进行连接。默认情况下,命名管道的名称为MySQL。如果在连接到mysqld时未给定主机名,MySQL客户端首先会尝试连接到命名管道。如果不能工作,将连接到TCP/IP端口。使用“.”作为主机名,可在Windows平台上强制使用命名管道。
错误(2002)“无法连接到…”通常意味着在系统没有运行的MySQL服务器,或在连接到服务器时使用了不正确的Unix套接字文件名或TCP/IP端口号。
首先检查服务器主机上是否有名为mysqld的进程(在Unix平台上使用**ps xa | grep mysqld**,或在Windows平台上使用任务管理器)。如果没有这类进程,应启动服务器。请参见[2.9.2.3节,“启动MySQL服务器以及其故障诊断和排除”](# "2.9.2.3. Starting and Troubleshooting the MySQL Server")。
如果**mysqld**进程正在运行,可使用下述命令检查。在你的具体设置中,端口号或Unix套接字文件名可能会有所不同。host_ip代表运行服务器的机器的IP编号。
shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h host_ip version
shell> mysqladmin --protocol=socket --socket=/tmp/mysql.sock version
注意,应与主机名命令一起使用“`”而不是“’”,这会使主机名输出(当前主机名)被代入**mysqladmin**命令。如果没有主机名命令或正运行在Windows平台上,应以手动方式输入机器的主机名(无“`”符号),后跟-h选项。也可以使用TCP/IP协议用-h 127.0.0.1连接到本地主机。
下面给出了一些“无法连接到本地MySQL服务器”错误的可能原因:
1. **Mysqld**未运行。请检查操作系统的进程列表以确保**mysqld**进程正在运行。
2. 你正在具有很多TCP/IP连接的Windows平台上运行MySQL服务器。如果你的客户端经常出现错误,请参见[A.2.2.1节,“在Windows上与MySQL服务器的连接失败”](# "A.2.2.1. Connection to MySQL Server Failing on Windows"),以找出规避方法。
3. 你正在使用MIT-pthreads的系统上运行。如果你正在运行不具有固有线程的操作系统,**mysqld**将使用MIT-pthreads软件包。请参见[2.1.1节,“MySQL支持的操作系统”](# "2.1.1. Operating Systems Supported by MySQL")。但是,并非所有的MIT-pthreads版本均支持Unix套接字文件。在不支持套接字文件的系统上,连接到服务器时,必须明确指定主机名。请使用下述命令来检查是否连接到了服务器:
4. shell> mysqladmin -h `hostname` version
5. 某人移动了**mysqld使用的**Unix套接字文件(默认为/tmp/mysql.sock)。例如,你可能执行了将旧文件从/tmp目录删除的**cron**任务。你总能执行**mysqladmin version**来检查**mysqladmin试图**使用的Unix套接字文件是否的确存在。在该情况下,更正方式是更改**cron**任务,不删除mysql.sock文件,或将套接字文件置于其他地方。请参见[A.4.5节,“如何保护或更改MySQL套接字文件/tmp/mysql.sock``”](# "A.4.5. How to Protect or Change the MySQL Socket File /tmp/mysql.sock")。
6. 你使用--socket=/path/to/socket选项启动了**mysqld**服务器,当忘记将套接字文件的新名称通知客户端程序。如果更改了关于服务器的套接字路径,也必须通知MySQL客户端。可在运行客户端程序时使用相同的—socket选项来完成该任务。此外,你还应确保客户端具有访问文件mysql.sock的权限。要想找出套接字文件的位置,可使用:
7. shell> netstat -ln | grep mysql
请参见[A.4.5节,“如何保护或更改MySQL套接字文件/tmp/mysql.sock``”](# "A.4.5. How to Protect or Change the MySQL Socket File /tmp/mysql.sock")。
8. 你正在使用Linux而且1个服务器线程已死亡(内核已清除)。在此情况下,在重启MySQL服务器之前,必须杀死其他**mysqld**线程(例如,使用kill或mysql_zap脚本)。请参见[A.4.2节,“如果MySQL依然崩溃,应作些什么”](# "A.4.2. What to Do If MySQL Keeps Crashing")。
9. 服务器或客户端程序不具有访问包含Unix套接字文件的目录或套接字文件本身的恰当权限。在该情况下,必须更改目录或套接字文件的访问权限,以便服务器或客户端程序能够访问它们,或用–socket选项重启**mysqld**,在该选项中指定服务器能创建、而且客户端可访问的目录下的套接字文件名。
如果遇到错误消息“无法连接到some_host上的MySQL服务器”,可尝试采取下述步骤以找出问题所在:
· 执行“telnet some_host 3306”并按两次回车键,检查服务器是否运行在该主机上(3306是默认的MySQL端口号。如果你的服务器正在监听不同的端口,请更改该值)。如果有1个MySQL服务器正在运行并监听该端口,你应收到包含服务器版本号的回应。如果遇到错误,如“telnet:无法连接到远程主机:拒绝连接”,表示在该定端口上没有运行的服务器。
· 如果服务器正运行在本地主机上,请使用Unix套接字文件,并使用**mysqladmin -h localhost variables**进行连接。验证服务器监听的TCP/IP端口号(它是port变量的值)。
· 确保你的**mysqld**服务器未用--skip-networking选项启动。如果使用了该选项,将无法使用TCP/IP连接到它。
· 检查并确认不存在屏蔽了对MySQL访问的防火墙。需要配置诸如ZoneAlarm和Windows XP个人防火墙等应用程序,以允许对MySQL服务器的外部访问。
#### A.2.2.1. 在Windows上与MySQL服务器的连接失败
当你在具有很多TCP/IP连接的Windows上运行MySQL服务器,并经常在客户端上遇到“无法连接到MySQL服务器”错误时,可能是因为Windows不允许足够的临时(短命)端口用于这类连接。
默认情况下,Windows允许用于使用5000个临时(短命)TCP端口。任何端口关闭后,它将在TIME_WAIT状态保持120秒。与重新初始化全新的连接相比,该状态允许以更低的开销重新使用连接。但是,在该时间逝去前,无法再次使用该端口。
对于小的可用TCP端口堆栈(5000),以及具有TIME_WAIT状态的大量在短时间内打开和关闭的TCP端口,你很可能遇到端口耗尽问题。处理该问题的方法有两种:
· 通过调查连接池以及可能的持久连接,减少快速消耗的TCP端口数。
· 调整Windows注册表中的某些设置(请参见下面)。
**要点:下述步骤涉及更改Windows 注册表。更改注册表之前,请备份注册表,并确认你已掌握在出现问题时恢复注册表的方法。关于备份年、恢复和编辑注册表的更多信息,请请参见Microsoft知识库中的下述文献:[http://support.microsoft.com/kb/256986/EN-US/](http://support.microsoft.com/kb/256986/EN-US/)。**
· 启动注册表编辑器(Regedt32.exe)。
· 在注册表中确定下述键值的位置:
· HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
· 在“编辑”菜单上点击“添加值”,然后增加下述注册值:
· Value Name: MaxUserPort
· Data Type: REG_DWORD
· Value: 65534
它用于设置为任何用户提供的临时端口数。有效范围介于5000和65534之间(十进制)。默认值为0x1388(5000,十进制)。
· 在“编辑”菜单上点击“添加值”,然后增加下述注册值:
· Value Name: TcpTimedWaitDelay
· Data Type: REG_DWORD
· Value: 30
它用于设置关闭之前将TCP端口连接保持在TIME_WAIT状态的秒数。有效范围介于0秒和300秒之间。默认值为0x78(120秒)。
· 退出注册表编辑器。
· 重新引导机器。
注释:撤销上述设置十分简单,就像删除你创建的注册表一样。
### A.2.3. 客户端不支持鉴定协议
MySQL 5.1采用了基于密码混编算法的鉴定协议,它与早期客户端(4.1之前)使用的协议不兼容。如果你将服务器升级到4.1之上,用早期的客户端进行连接可能失败,并给出下述消息:
shell> mysql
客户端不支持服务器请求的鉴定协议:请考虑升级MySQL客户端。
要想解决该问题,应使用下述方法之一:
· 升级所有的客户端程序,以使用4.1.1或更新的客户端库。
· 用4.1版之前的客户端连接到服务器时,请使用仍具有4.1版之前风格密码的账户。
· 对于需要使用4.1版之前的客户端的每位用户,将密码恢复为4.1版之前的风格。可以使用SET PASSWORD语句和OLD_PASSWORD()函数完成该任务:
· mysql> SET PASSWORD FOR
· -> 'some_user'@'some_host' = OLD_PASSWORD('newpwd');
也可以使用UPDATE和FLUSH PRIVILEGES:
mysql> UPDATE mysql.user SET Password = OLD_PASSWORD('newpwd')
-> WHERE Host = 'some_host' AND User = 'some_user';
mysql> FLUSH PRIVILEGES;
用你打算使用的密码替换前例中的“_newpwd_”。MySQL不能告诉你原来的密码是什么,因此,你需要选择新的密码。
· 通知服务器使用旧的密码混编算法:
1. 使用“--old-passwords”选项启动**mysqld**。
2. 对于已将密码更新为较长4.1格式的每个账户,为其指定具有旧格式的密码。可以使用下述查询确定这些账户:
3. mysql> SELECT Host, User, Password FROM mysql.user
4. -> WHERE LENGTH(Password) > 16;
对于查询显示的每个账户记录,请使用Host和User值,并使用OLD_PASSWORD()函数以及SET PASSWORD或UPDATE之一指定密码,如前面所介绍的那样。
**注释:**在早期的PHP版本中,mysql扩展不支持MySQL 4.1.1和更高版中的鉴定协议。无论使用的PHP版本是什么,它均是正确的。如果你打算与MySQL 4.1或更高版本一起使用mysql扩展,需要使用前面介绍的选项之一,配置MySQL,以便与较早的客户端一起使用。mysqli扩展(支持“改进的MySQL”,在PHP 5中增加)与MySQL 4.1和更高版本中使用的改进的密码混编算法兼容,不需要对MySQL进行特殊配置就能使用该MySQL客户端库。关于mysqli扩展的更多信息,请参见[http://php.net/mysqli](http://php.net/mysqli)。
关于密码混编和鉴定功能的额外背景知识,请参见[5.7.9节,“MySQL 4.1中的密码哈希处理”](# "5.7.9. Password Hashing in MySQL 4.1")。
### A.2.4. 输入密码时出现密码错误
使用无下述密码值的“—password”或“-p”选项调用时,MySQL客户端程序将提示输入密码: shell> mysql -u user_name -p
Enter password:
在某些系统上,当你在选项文件或命令行上指定时,你可能会发现密码能够工作,但是当你在“Enter password:”提示下以交互方式输入密码时,你可能会发现输入的密码不工作。当系统所提供的用于读取密码的库将密码值限定在少数字符时(典型情况下为8个),就会出现该问题。这是与系统库有关的问题,与MySQL无关。要想处理该问题,可将MySQL密码更改为由8个字符或更少字符构成的值,或将密码置于选项文件中。
### A.2.5. 主机的hos_t_name被屏蔽_
如果遇到下述错误,表示**mysqld**已收到来来自主机“_host_name_”的很多连接请求,但该主机却在中途中断。
由于出现很多连接错误,主机'host_name'被屏蔽。
可使用'mysqladmin flush-hosts'解除屏蔽。
允许的中断连接请求的数目由max_connect_errors系统变量的值决定。当超出max_connect_errors规定的连接请求时,**mysqld**将认为某处出错(例如,某人正试图插入),并屏蔽主机的进一步连接请求,直至执行了**mysqladmin flush-hosts**命令,或发出了FLUSH HOSTS语句为止。请参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。
在默认情况下,**mysqld**会在10次连接错误后屏蔽主机。你可以通过下述方式启动服务器来调整该值:
shell> mysqld_safe --max_connect_errors=10000 &
如果在给定主机上遇到该错误,首先应核实该主机的TCP/IP连接是否正确。如果存在网络问题,增加max_connect_errors变量的值不会有任何好处。
### A.2.6. 连接数过多
当你试图连接到**mysqld**服务器时遇到“过多连接”错误,这表示所有可用的连接均已被其他客户端使用。
允许的连接数由max_connections系统变量控制。默认值为100。如果需要支持更多的连接,应使用该变量的较大值重启**mysqld**。
**mysqld**实际上允许max_connections+1个客户端进行连接。额外的连接保留给具有SUPER权限的账户。通过为系统管理员而不是普通用户授予SUPER权限(普通用户不应具有该权限),系统管理员能够连接到服务器,并使用SHOW PROCESSLIST来诊断问题,即使已连接的无特权客户端数已达到最大值也同样。请参见[13.5.4.16节,“SHOW PROCESSLIST语法”](# "13.5.4.16. SHOW PROCESSLIST Syntax")。
MySQL能支持的最大连接数取决于给定平台上线程库的质量。Linux或Solaris应能支持500-1000个并发连接,具体情况取决于RAM容量,以及客户端正在作什么。MySQL AB提供的静态Linux库能支持高达4000个连接。
### A.2.7. 内存溢出
如果使用**mysql**客户端程序发出了查询,并收到下述错误之一,则表示**mysql**没有足够内存来保存全部查询结果:
mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
错误2008: MySQL client ran out of memory
要想更正该问题,首先应检查查询是否正确。返回这么多行是否合理?如果不合理,更正查询并再次尝试。否则,应使用“--quick”选项调用**mysql**。这样,将使用mysql_use_result() C API函数来检索结果集,这类函数能够降低客户端上的负载(但会加重服务器上的负载)。
### A.2.8. MySQL服务器不可用
在本节中,还介绍了出现查询错误期间,与丢失了服务器连接有关的事宜。
MySQL服务器不可用错误的最常见原因是服务器超时以及连接已关闭。在该情况下,通常能见到下述错误代码之一(具体的错误代码与操作系统有关):
<table border="1" cellpadding="0" id="table1"><tr><td> <p><strong><span> 错误代码</span></strong></p></td> <td> <p><strong><span> 描述</span></strong></p></td> </tr><tr><td> <p> <span>CR_SERVER_GONE_ERROR</span></p></td> <td> <p>客户端无法将问题发送至服务器。</p></td> </tr><tr><td> <p> <span>CR_SERVER_LOST</span></p></td> <td> <p>写入服务器时客户端未收到错误,但也未获得问题的完整答案(或任何答案)。</p></td> </tr></table>
在默认情况下,如果未发生任何事,8小时后服务器将关闭连接。也可以在启动**mysqld**时,通过设置wait_timeout变量更改时间限制。请参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables").
如果有1个脚本,你仅需要再次发出查询,让客户端再次进行自动连接即可。其中,假定在客户端中启用了自动再连接功能(对于mysql命令行客户端,这是默认设置)。
MySQL服务器不可用错误的一些其他常见原因如下:
· 你(或db系统管理员)使用KILL语句或**mysqladmin kill**命令杀死了正在运行的线程。
· 你试图在关闭了与服务器的连接后运行查询。这表明应更正应用程序中的逻辑错误。
· 你在客户端一侧遇到TCP/IP连接超时错误。如果你使用了命令:mysql_options(..., MYSQL_OPT_READ_TIMEOUT,...)或mysql_options(..., MYSQL_OPT_WRITE_TIMEOUT,...),就可能出现该问题。在该情况下,增加超时值可能有助于问题的解决。
· 你在服务器端遇到超时错误,而且禁止了客户端中的自动再连接功能(MYSQL结构中的再连接标志等于0)。
· 你正在使用Windows客户端,而且在发出命令之前服务器撤销了连接(或许是因为已超过wait_timeout)。
在Windows平台上出现问题的原因,在某些情况下,将TCP/IP连接写入服务器时,MySQL未收到来自操作系统的错误,但当试图从连接读取答案时出现错误。
在该情况下,即使MYSQL结构中的再连接标志等于1,MySQL也不会执行自动再连接并再次发出查询,这是因为它不知道服务器是否收到原始查询。
对此的解决方式是:如果自上一次查询以来经过了较长时间,在连接上执行mysql_ping(正是MyODBC所作的);或在**mysqld**服务器上将wait_timeout设置得很高,使之实际上不存在超时。
· 如果你向服务器发出了不正确或过大的查询,也会遇到这类问题。如果**mysqld**收到过大或无序的信息包,它会认为客户端出错,并关闭连接。如果需要执行较大的查询(例如,正在处理大的BLOB列),可通过设置服务器的max_allowed_packet变量,增加查询限制值,该变量的默认值为1MB。或许,你还需增加客户端上的最大信息包大小。关于设置信息包大小的更多信息,请参见[A.2.9节,“信息包过大”](# "A.2.9. Packet too large")。
· 如果你的客户端低于4.0.8而且你的服务器高于4.0.8,当你接收16MB或更大的信息包时,可能会丢失连接。
· 如果MySQL是用“--skip-networking”选项启动的,也会见到MySQL服务器不可用错误。
· 你遇到了执行查询时服务器宕机的缺陷。
通过执行**mysqladmin version**并检查服务器的正常工作时间,可检查服务器是否宕机并重启。如果客户端连接是因**mysqld**崩溃和重启而断开的,应将重点放在查找崩溃你方面。首先应再次检查发出的查询是否再次杀死了服务器。请参见[A.4.2节,“如果MySQL依然崩溃,应作些什么”](# "A.4.2. What to Do If MySQL Keeps Crashing")。
用“--log-warnings=2”选项启动mysqld,可获得关于连接的更多信息。这样,就能将某些断开连接错误记录到hostname.err文件中。请参见[5.11.1节,“错误日志”](# "5.11.1. The Error Log")。
如果你打算创建与该问题有关的缺陷报告,务必包含下述信息:
1. 指明MySQL服务器是否宕机。通过服务器错误日志可发现这方面的信息。请参见[A.4.2节,“如果MySQL依然崩溃,应作些什么”](# "A.4.2. What to Do If MySQL Keeps Crashing")。
2. 如果特定查询杀死了**mysqld**,而且在运行查询前用CHECK TABLE检查了涉及的表,你是否能提供可重复的测试范例?请参见[E.1.6节,“如果出现表崩溃,请生成测试案例”](# "E.1.6. Making a Test Case If You Experience Table Corruption")。
3. 在MySQL服务器中,系统变量wait_timeout的值是什么?(**mysqladmin variables**给出了该变量的值)。
4. 你是否尝试使用“--log”选项来运行**mysqld**,以确定是否在日志中出现问题?
另请参见[A.2.10节,“通信错误和失效连接”](# "A.2.10. Communication Errors and Aborted Connections")。
请参见[1.7.1.2节,“请教问题或通报缺陷”](# "1.7.1.2. Asking Questions or Reporting Bugs")。
### A.2.9. 信息包过大
通信信息包是发送至MySQL服务器的单个SQL语句,或发送至客户端的单一行。
在MySQL 5.1服务器和客户端之间最大能发送的可能信息包为1GB。
当MySQL客户端或**mysqld**服务器收到大于max_allowed_packet字节的信息包时,将发出“信息包过大”错误,并关闭连接。对于某些客户端,如果通信信息包过大,在执行查询期间,了能回遇到“丢失与MySQL服务器的连接”错误。
客户端和服务器均有自己的max_allowed_packet变量,因此,如你打算处理大的信息包,必须增加客户端和服务器上的该变量。
如果你正在使用**mysql**客户端程序,其max_allowed_packet变量的默认值为16MB。要想设置较大的值,可用下述方式启动**mysql**:
mysql> mysql --max_allowed_packet=32M
它将信息包的大小设置为32MB。
服务器的默认max_allowed_packet值为1MB。如果服务器需要处理大的查询,可增加该值(例如,如果准备处理大的BLOB列)。例如,要想将该设置为16MB,可采用下述方式启动服务器:
mysql> mysqld --max_allowed_packet=16M
也能使用选项文件来设置max_allowed_packet。要想将服务器的该变量设置为16MB,可在选项文件中增加下行内容:
[mysqld]
max_allowed_packet=16M
增加该变量的值十分安全,这是因为仅当需要时才会分配额外内存。例如,仅当你发出长查询或**mysqld**必须返回大的结果行时**mysqld**才会分配更多内存。该变量之所以取较小默认值是一种预防措施,以捕获客户端和服务器之间的错误信息包,并确保不会因偶然使用大的信息包而导致内存溢出。
如果你正是用大的BLOB值,而且未为**mysqld**授予为处理查询而访问足够内存的权限,也会遇到与大信息包有关的奇怪问题。如果怀疑出现了该情况,请尝试在**mysqld_safe**脚本开始增加**ulimit -d 256000**,并重启**mysqld**。
### A.2.10. 通信错误和失效连接
对于连接问题,服务器错误日志是有用的信息源。请参见[5.11.1节,“错误日志”](# "5.11.1. The Error Log")。如果服务器是用“--log-warnings”选项启动的,在错误日志中可能会发现下述消息:
010301 14:38:23 Aborted connection 854 to db: 'users' user: 'josh'
如果“Aborted connections”(放弃连接)消息出现在错误日志中,可能的原因是:
1. 客户端程序在退出之前未调用mysql_close()。
2. 客户端的空闲时间超过wait_timeout或interactive_timeout秒,未向服务器发出任何请求。请参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。
3. 客户端在数据传输中途突然结束。
出现这类情况时,服务器将增加“Aborted_clients”(放弃客户端)状态变量。
出现下述情况时,服务器将增加“Aborted_clients”(放弃客户端)状态变量。
· 客户端不具有连接至数据库的权限。
· 客户端采用了不正确的密码。
· 连接信息包不含正确信息。
· 获取连接信息包的时间超过connect_timeout秒。请参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。
如果出现这类情况,可能表明某人正试图侵入你的服务器!
对于放弃客户端或放弃连接问题,其他可能的源应包括:
· 与Linux一起使用以太网协议,半双工或全双工。很多Linux以太网驱动均存在该缺陷。应通过FTP在客户端和服务器机器之间传输大文件来测试该缺陷。如果传输处于burst-pause-burst-pause(爆发-暂停-爆发-暂停)模式,表明你遇到了Linux双工故障。唯一的解决方法是,将网卡和Hub/交换器的双工模式切换为全双工或半双工,并对结果进行测试以确定最佳设置。
· 与线程库有关的某些问题导致读取中断。
· 配置不良的TCP/IP。
· 有问题的以太网、Hub、交换器、电缆等。仅能通过更换硬件才能恰当诊断。
· 变量max_allowed_packet过小或查询要求的内存超过为**mysqld**分配的内存。请参见[A.2.9节,“信息包过大”](# "A.2.9. Packet too large")。
另请参见[A.2.8节,“MySQL服务器不可用”](# "A.2.8. MySQL server has gone away")。
### A.2.11. 表已满
表已满错误出现的方式有数种:
· 你正在使用低于3.23版的MySQL服务器,而且“内存中”临时表超过了tmp_table_size字节。要想避免该问题,可使用“-O tmp_table_size=_val_”选项以便**mysqld**增加临时表的大小,或在发出有问题的查询之前,使用SQL选项SQL_BIG_TABLES。请参见[13.5.3节,“SET语法”](# "13.5.3. SET Syntax")。
也可以使用“--big-tables”选项启动**mysqld**。它与使用针对所有查询的SQL_BIG_TABLES完全相同。
自MySQL 3.23起,该问题应不再出现。如果“内存中”临时表超过tmp_table_size,服务器会自动将其转换为基于磁盘的MyISAM表。
· 你正在使用InnoDB表,并超出了InnoDB表空间。在该情况下,解决方法是增加InnoDB表空间。请参见[15.2.7节,“添加和删除InnoDB数据和日志文件``”](# "15.2.7. Adding and Removing InnoDB Data and Log Files")。
· 你正在仅支持2GB文件的操作系统上使用ISAM或MyISAM表,数据文件或索引文件达到了该限制值。
· 你正在使用MyISAM表,而且表所需的空间超过内部指针允许的大小。如果在创建表时未指定MAX_ROWS表,MySQL将使用myisam_data_pointer_size系统变量。默认值为6字节,它足以容纳65536TB数据。请参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。
使用该语句,可检查最大数据/索引大小:
SHOW TABLE STATUS FROM database LIKE 'tbl_name';
也可以使用**myisamchk -dv /path/to/table-index-file**。
如果指针大小过小,可使用ALTER TABLE更正该问题:
ALTER TABLE tbl_name MAX_ROWS=1000000000 AVG_ROW_LENGTH=nnn;
仅应为具有BLOB或TEXT列的表指定AVG_ROW_LENGTH。在该情况下,MySQL不能仅根据行数优化所需的空间。
### A.2.12. 无法创建文件/写入文件
如果对某些查询遇到下述类型的错误,它意味着MySQL不能为临时目录下的结果集创建临时文件:
无法创建/写入文件'\\sqla3fe_0.ism'。
前述错误是Windows平台上的典型消息,Unix平台上的消息与之类似。
一种更正方式是使用“--tmpdir”选项启动**mysqld**,或在选项文件的[mysqld]部分增加该选项。例如,要想指定目录C:\temp,可使用:
[mysqld]
tmpdir=C:/temp
目录C:\temp必须存在,并有足够的空间允许MySQL写入它。请参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。
该错误的另一个原因可能是许可事宜。请确认MySQL服务器能够写入tmpdir目录。
此外,还用使用**perror**检查错误代码。服务器无法写入表的一个原因是文件系统已满。
shell> perror 28
错误代码28:磁盘上无剩余空间。
### A.2.13. 命令不同步
如果遇到“命令不同步”错误,将无法在你的客户端代码中运行该命令,你正在以错误顺序调用客户端函数。
例如,如果你正使用mysql_use_result(),并打算在调用mysql_free_result()之前执行新查询,就会出现该问题。如果你试图执行两次查询,但并未在两次查询之间调用mysql_use_result()或mysql_store_result(),也会出现该问题。
### A.2.14. 忽略用户
如果遇到下述错误,表示当启动**mysqld**时或重新加载授权表时,在用户表中发现具有非法密码的账户。
发现用户'_some_user_'@'_some_host_'密码错误:忽略用户。
作为其结果,许可系统将简单忽略账户。
在下面的介绍中,指明了可能的原因和问题的更正措施:
1. 或许,你正打算用旧的用户表运行新版本的**mysqld**。执行**mysqlshow mysql user**检查Password(密码)列是否短于16个字符,通过该方式可检查该问题。如果结果是肯定的,可运行脚本/add_long_password脚本更正该问题。
2. 账户具有旧的密码(8字符长),而且未使用“--old-protocol”选项启动**mysqld**。更新用户表中的账户,使之具有新的密码,或使用“--old-protocol”选项重启**mysqld**。
3. 在用户表中未使用PASSWORD()函数指定了密码。使用**mysql**用新密码更新用户表中的账户,务必使用PASSWORD()函数:
4. mysql> UPDATE user SET Password=PASSWORD('newpwd')
5. -> WHERE User='some_user' AND Host='some_host';
### A.2.15. 表tbl_na_me不存在_
如果遇到下述错误之一,通常意味着当前数据库中不存在具有给定名称的表:
表'tbl_name'不存在
无法找到文件:'tbl_name' (errno: 2)
在某些情况下,表或许存在,但未正确引用它:
· 由于MySQL使用目录和文件来保存数据库和表,如果它们位于区分文件名大小写的文件系统上,数据库和表名也区分文件大小写。
· 即使对于不区分大小写的文件系统,如Windows,在查询内对给定表的所有引用必须使用相同的大小写。
可以使用SHOW TABLES检查位于当前数据库中的表。请参见[13.5.4节,“SHOW语法”](# "13.5.4. SHOW Syntax")。
### A.2.16. 无法初始化字符集
如果存在字符集问题,可能会遇到下述错误:
MySQL连接失败:无法初始化字符集charset_name。
导致该错误的原因:
· 字符集为多字节字符集,但客户端不支持该字符集。在该情况下,需要使用“--with-charset=_charset_name_”或“--with-extra-charsets=_charset_name_”选项运行**configure**以重新编译客户端。请参见[2.8.2节,“典型配置选项****”](# "2.8.2. Typical configure Options")。
所有的标准MySQL二进制文件均是采用“--with-extra-character-sets=complex”编译的,能够支持所有的多字节字符集。请参见[5.10.1节,“数据和排序用字符集”](# "5.10.1. The Character Set Used for Data and Sorting")。
· 字符集是未编译到**mysqld**中的简单字符集,而且字符集定义文件不在客户端预期的位置。
在该情况下,需要采取下述方法之一解决问题:
1. 重新编译客户端,使之支持字符集。请参见[2.8.2节,“典型配置选项****”](# "2.8.2. Typical configure Options")。
2. 为客户端指定字符集定义文件所在的目录。对于很多客户端,可使用“--character-sets-dir”选项完成该任务。
3. 将字符集定义文件复制到客户端预期的位置。
### A.2.17. 文件未找到
如果遇到“ERROR '...'未发现(errno: 23)”,“无法打开文件:... (errno: 24)”,或来自MySQL的具有errno 23或errno 24的其它错误,它表示未为MySQL服务器分配足够的文件描述符。你可以使用**perror**实用工具来了解错误编号的含义:
shell> perror 23
错误代码23:文件表溢出
shell> perror 24
错误代码24:打开文件过多
shell> perror 11
错误代码11:资源暂时不可用
这里的问题是,**mysqld**正试图同时打开过多的文件。你可以通知**mysqld**不要一次打开过多文件,或增加**mysqld**可用文件描述符的数目。
要想通知**mysqld**将一次打开的文件控制在较小的数目上,可降低table_cache系统变量的值(),从而减少表高速缓冲(默认值为64)。降低max_connections的值也能降低打开文件的数目(默认值为100)。
要想更改**mysqld**可用的文件描述符的数目,可在**mysqld_safe**上使用“--open-files-limit”选项或设置(自MySQL 3.23.30开始)open_files_limit系统变量。请参见[5.3.3节,“服务器系统变量”](# "5.3.3. Server System Variables")。设置这些值的最简单方式是在选项文件中增加1个选项。请参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。如果**mysqld**的版本较低,不支持设置打开文件的数目,可编辑**mysqld_safe**脚本。在脚本中有1个注释掉的行**ulimit -n 256。你可以删除**‘#’字符取消对该行的注释,更改数值256,以设置**mysqld**可用的文件描述符数目。
“--open-files-limit”和**ulimit**能够增加文件描述符的数目,但最高不能超过操作系统限制的数目。此外还有1个“硬”限制,仅当以根用户身份启动**mysqld_safe**或**mysqld**时才能覆盖它(请记住,在该情况下,还需使用“--user”选项启动服务器,以便在启动后不再以根用户身份继续运行)。如果需要增加操作系统限制的对各进程可用文件描述符的数目,请参阅系统文档。
**注释:**如果运行**tcsh** shell,**ulimit**不工作!请求当前限制值时,**tcsh**还能通报不正确的值。在该情况下,应使用**sh**启动**mysqld_safe。**
### A.3. 与安装有关的事宜
[ A.3.1. 与MySQL客户端库的链接问题](#)[ A.3.2. 如何以普通用户身份运行MySQL](#)[ A.3.3. 与文件许可有关的问题](#)
### A.3.1. 与MySQL客户端库的链接问题
当你链接到应用程序以使用MySQL客户端库时,可能会遇到以mysql_开始的未定义引用错误,如下所示:
/tmp/ccFKsdPa.o: 在函数`main'中:
/tmp/ccFKsdPa.o(.text+0xb): 对`mysql_init'的未定义引用。
/tmp/ccFKsdPa.o(.text+0x31): 对`mysql_real_connect'的未定义引用。
/tmp/ccFKsdPa.o(.text+0x57): 对`mysql_real_connect'的未定义引用。
/tmp/ccFKsdPa.o(.text+0x69): 对`mysql_error'的未定义引用。
/tmp/ccFKsdPa.o(.text+0x9a): 对`mysql_close'的未定义引用。
通过在链接命令后增加“-Ldir_path -lmysqlclient”选项,应能解决该问题,其中,dir_path代表客户端库所在目录的路径名。要想确定正确的目录,可尝试下述命令:
shell> mysql_config --libs
来自**mysql_config**的输出可能会指明应在链接命令上指定的其他库。
对于非压缩或压缩函数,如果遇到未定义引用错误,可在链接命令后添加-lz,并再次尝试。
对于应在系统上存在的函数(如connect),如果遇到未定义引用错误,请检查相关函数的手册页,以便确定应在链接命令上增加哪些库。
对于系统上不存在的函数,可能会遇到未定义引用错误,如下所示:
mf_format.o(.text+0x201): 对`__lxstat'的未定义引用。
它通常意味着你的MySQL客户端库是在与你的系统不100%兼容的系统上编译的。在该情况下,应下载最新的MySQL源码分发版,并自己编译MySQL。请参见[2.8节,“使用源码分发版安装MySQL”](# "2.8. MySQL Installation Using a Source Distribution")。
当你试图执行MySQL程序时,可能会遇到运行时未定义引用错误。如果这类错误指明了以mysql_开始的符号,或指明未发现mysqlclient库,这意味着你的系统无法找到共享的libmysqlclient.so库。对其的更正方式是,通知系统在库所在位置搜索共享库。请使用与系统相适应的下述方法:
· 将libmysqlclient.so所在目录的路径添加到LD_LIBRARY_PATH环境变量中。
· 将libmysqlclient.so所在目录的路径添加到LD_LIBRARY环境变量中。
· 将libmysqlclient.so拷贝到可被系统搜索的目录下,如/lib,然后通过执行ldconfig更新共享库信息。
解决该问题的另一种方法是,以静态方式将你的程序与“-static”选项链接在一起,或在链接代码之前删除动态MySQL库。使用第2种方法之前,应确保没有使用动态库的其它程序。
### A.3.2. 如何以普通用户身份运行MySQL
在Windows平台上,能够使用普通用户账户以Windows服务方式运行服务器。
在Unix平台上,不是任何用户都能启动并运行MySQL服务器**mysqld的**。但是,处于安全方面的原因,应避免以Unix根用户身份运行服务器。要想更改**mysqld**,使之能以正常的无特权Unix用户_user_name_身份运行,必须采取下述步骤:
如果服务器正在运行,停止它(使用**mysqladmin shutdown**)。
更改数据库目录和文件,允许_user_name_读写其中的文件(可能需要以Unix根用户身份完成这类设置):
shell> chown -R user_name /path/to/mysql/datadir
如果未这样做,当以_user_name_身份运行时,服务器无法访问数据库或表。
如果MySQL数据目录下的目录或文件采用的是符号链接,还需跟踪这些链接,并更改它们指向的目录和文件。chown –R可帮助你跟踪符号链接。
以_user_name_身份启动服务器。如果你正在使用MySQL 3.22或更高版本,另一种可选方式是,以Unix根用户身份启动**mysqld**,并使用--user=_user_name_选项。**mysqld**启动,然后在接受任何连接前,切换至Unix用户_user_name_并以该用户身份运行。
要想在系统启动时自动以给定的用户身份启动服务器,可在服务器数据目录下的/etc/my.cnf选项文件或my.cnf选项文件的[mysqld]组中,通过增加用户选项来指定用户名。。例如:
[mysqld]
user=user_name
如果你的Unix机器本身并不安全,应在授权表中为MySQL根账户指定密码。如不然,任何在该机器上具有登录账户的用户都能使用“--user=root”选项运行**mysql**客户端,并执行任何操作。在任何情况下均应为MySQL账户指定密码,这是个好主意,尤其是在服务器主机上存在其他登录账户时,更是如此。请参见[2.9节,“安装后的设置和测试”](# "2.9. Post-Installation Setup and Testing")。
### A.3.3. 与文件许可有关的问题
如果遇到与文件许可有关的问题,可能数启动mysqld时UMASK环境变量设置得不正确。例如,当你创建表时,MySQL可能会发出下述错误消息:
ERROR: 无法找到文件:'path/with/filename.frm' (Errcode: 13)
UMASK的默认值是0660。通过下述方式启动**mysqld_safe**,可改变该情况:
shell> UMASK=384 # = 600 in octal
shell> export UMASK
shell> mysqld_safe &
在默认情况下,MySQL用0700的许可创建数据库和RAID目录。你可以通过设置UMASK_DIR变量更改该行为。如果你设置了它的值,将使用组合的UMASK和UMASK_DIR值创建新目录。例如,如果你打算为所有新的目录授予组访问权限,可:
shell> UMASK_DIR=504 # = 770 in octal
shell> export UMASK_DIR
shell> mysqld_safe &
在MySQL 3.23.25和更高版本中,如果是以0开始的,MySQL将认为UMASK和UMASK_DIR的值均采用八进制形式。
请参见[附录F:](#)[_环境变量_](# "Appendix F. Environment Variables")。
### A.4. 与管理有关的事宜
[A.4.1. 如何复位根用户密码](#)[A.4.2. 如果MySQL依然崩溃,应作些什么](#)[A.4.3. MySQL处理磁盘满的方式](#)[A.4.4. MySQL将临时文件储存在哪里](#)[A.4.5. 如何保护或更改MySQL套接字文件/tmp/mysql.sock``](#)[A.4.6. 时区问题](#)
### A.4.1. 如何复位根用户密码
如果你从未为MySQL设置根用户密码,服务器在以根用户身份进行连接时不需要密码。但是,建议你为每个账户设置密码。请参见[5.6.1节,“通用安全指南”](# "5.6.1. General Security Guidelines")。
如果你以前设置了根用户密码,但却忘记了该密码,可设置新的密码。下述步骤是针对Windows平台的。在本节后面的内容中,介绍了针对Unix平台的步骤。
在Windows平台下,该步骤是:
以系统管理员身份登录到系统。
如果MySQL服务器正在运行,停止它。对于作为Windows服务运行的服务器,进入服务管理器:
开始菜单->控制面板->管理工具->服务
然后在列表中找出MySQL服务器,并停止它。
如果服务器不是作为服务而运行的,可能需要使用任务管理器来强制停止它。
创建1个文本文件,并将下述命令置于单一行中:
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPassword');
用任意名称保存该文件。在本例中,该文件为C:\mysql-init.txt。
打开控制台窗口,进入DOS命令提示:
开始菜单->运行-> cmd
假定你已将MySQL安装到C:\mysql。如果你将MySQL安装到了另一位置,请对下述命令进行相应的调整。
在DOS命令提示符下,执行命令:
C:\> C:\mysql\bin\mysqld-nt --init-file=C:\mysql-init.txt
在服务器启动时,执行由“--init-file”选项命名的文件的内容,更改根用户密码。当服务器成功启动后,应删除C:\mysql-init.txt。
如果你使用MySQL安装向导安装了MySQL,或许需要指定“--defaults-file”选项:
C:\> C:\Program Files\MySQL\MySQL Server 5.1\bin\mysqld-nt.exe
--defaults-file="C:\Program Files\MySQL\MySQL Server 5.1\my.ini"
--init-file=C:\mysql-init.txt
使用服务管理器,可找到恰当的“--defaults-file”设置:
开始菜单->控制面板->管理工具->服务
在列表中找出MySQL服务,右击,并选择“属性”选项。在可执行字段的Path(路径)中包含“--defaults-file”设置。
停止MySQL服务器,然后在正常模式下重启它。如果以服务方式运行服务器,应从Windows服务窗口启动它。如果以手动方式启动了服务器,能够像正常情形下一样使用命令。
应能使用新密码进行连接。
在Unix环境下,重置根用户密码的步骤如下:
以Unix根用户身份、或以运行mysqld服务器的相同身份登录到系统。
找到包含服务器进程ID的.pid文件。该文件的准确位置和名称取决于你的分发版、主机名和配置。常见位置是/var/lib/mysql/、/var/run/mysqld/和/usr/local/mysql/data/。一般情况下,文件名的扩展名为.pid,并以mysqld或系统的主机名开始。
在下述命令中使用.pid文件的路径名,向**mysqld**进程发出正常的kill(而不是kill -9),可停止MySQL服务器:
shell> kill `cat /mysql-data-directory/host_name.pid`
注意,cat命令使用符号“`”而不是“’”:这会使cat的输出代入到kill命令中。
创建文本文件,并将下述命令放在文件内的1行上:
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('MyNewPassword');
用任意名称保存文件。对于本例,文件为~/mysql-init。
用特殊的“--init-file=~/mysql-init”选项重启MySQL服务器:
shell> mysqld_safe --init-file=~/mysql-init &
文件init-file的内容在服务器启动时执行,更改根用户密码。服务器成功启动后,应删除~/mysql-init。
应能使用新密码进行连接。
作为可选方式,在任何平台上,可使用**mysql**客户端设置新密码(但该方法不够安全):
停止**mysqld**,并用“--skip-grant-tables --user=root”选项重启它(Windows用户可省略--user=root部分)。
使用下述命令连接到**mysqld**服务器:
shell> mysql -u root
在**mysql**客户端发出下述语句:
mysql> UPDATE mysql.user SET Password=PASSWORD('newpwd')
-> WHERE User='root';
mysql> FLUSH PRIVILEGES;
用打算使用的实际根用户密码替换“_newpwd_”。
应能使用新密码进行连接。
### A.4.2. 如果MySQL依然崩溃,应作些什么
正式发布之前,每个MySQL版本均在很多平台上进行了测试。这不表示MySQL中不存在缺陷,但是,如果存在缺陷,它们应很少,而且很难发现。如果你遇到问题,如果你尝试找出导致系统崩溃的准确原因,这始终很有帮助,这是因为,如果这样的话,快速解决问题的机会很大。
首先,应尝试找出问题是否与**mysqld**服务器有关,或是否与客户端有关。通过执行**mysqladmin version**,可检查**mysqld**服务器运行了多长时间。如果**mysqld**宕机并重启,应查看服务器的错误日志以找出原因。请参见[5.11.1节,“错误日志”](# "5.11.1. The Error Log")。
在某些系统上,在错误日志中,可发现**mysqld**宕机的堆栈跟踪,可使用resolve_stack_dump程序解决它。请参见[E.1.4节,“使用堆栈跟踪”](# "E.1.4. Using a Stack Trace")。注意,错误日志中的变量值并非始终是100%正确的。
很多服务器崩溃是因损坏的数据文件或索引文件而导致的,每次执行完SQL语句之后并在向客户端通告结果之前,MySQL将使用write()系统调用更新磁盘上的文件(如果你使用了“--delay-key-write”选项,情况并非如此,此时将写入数据文件而不是索引文件)。这意味着,即使mysqld崩溃,数据文件的内容也是安全的,这是因为操作系统能保证将未刷新的数据写入磁盘。使用“--flush”选项启动**mysqld**,这样,每次执行完SQL语句后,可强制MySQL将所有内容写入磁盘。
前述介绍表明,在正常情况下不会出现损坏的表,除非出现了下述情况之一:
在更新过程中,MySQL服务器或服务器主机被停止。
你发现了**mysqld**中存在的1个缺陷,该缺陷导致**mysqld**在更新中途中止。
在**mysqld**操作的同时,某些外部程序正在操控数据文件或索引文件,未恰当锁定表。
你正使用系统上的相同数据目录运行很多**mysqld**服务器,该系统不支持良好的文件系统锁定(通常是由lockd锁定管理器负责的),或使用“--skip-external-locking”选项运行了多个服务器。
崩溃的数据文件或索引文件,其中包含导致mysqld混乱的损坏很严重的数据。
在数据存储节点发现缺陷。这种可能性不大,但至少是可能的。在该情况下,可在修复的表副本上,通过使用ALTER TABLE,尝试将表类型更改为另一种存储引擎。
由于很难得知为什么某事会出现崩溃,首先请检查用于其他方面的事项是否崩溃。请尝试采取下述措施:
用**mysqladmin shutdown**停止**mysqld**服务器,从数据目录运行**myisamchk --silent --force */*.MYI**,检查所有的MyISAM表,并重启**mysqld**。这样,就能确保从干净的状态运行服务器。请参见[第5章:数据库管理](# "Chapter 5. Database Administration")。
使用“--log”选项启动**mysqld**,并根据写入日志的信息确定是否某些特殊的查询杀死了服务器。约95%的缺陷与特定的查询有关。正常情况下,这是服务器重启前日志文件中最够数个查询中的1个。请参见[5.11.2节,“通用查询日志”](# "5.11.2. The General Query Log")。如果能够用特殊查询重复杀死MySQL,即使在发出查询前检查了所有表的情况下也同样,那么你就应能确定缺陷,并应提交关于该缺陷的缺陷报告。请参见[1.7.1.3节,“如何通报缺陷和问题”](# "1.7.1.3. How to Report Bugs or Problems")。
尝试提供一个测试范例,我们应能利用该范例重复问题。请参见[E.1.6节,“如果出现表崩溃,请生成测试案例”](# "E.1.6. Making a Test Case If You Experience Table Corruption")。
请在mysql-test目录下并根据MySQL基准进行测试。请参见[27.1.2节,“MySQL测试套件”](# "27.1.2. MySQL Test Suite")。它们能相当良好地测试MySQL。你也可以为基准测试增加代码,以模拟你的应用程序。基准测试可在源码分发版的sql-bench目录下找到,对于二进制分发版,可在MySQL安装目录下的sql-bench目录下找到。
尝试使用fork_big.pl脚本(它位于源码分发版的测试目录下)。
如果你将MySQL配置为调试模式,如果某事出错,可更为容易地搜集关于可能错误的信息。如果将MySQL配置为调试模式,可生成1个安全的内存分配程序,可使用它发现某些错误。此外,它还提供了很多输出,这类输出与出现的问题相关。在**configure**上使用“--with-debug”或“--with-debug=full”选项重新配置MySQL,然后再编译它。请参见[E.1节,“调试MySQL服务器”](# "E.1. Debugging a MySQL Server")。
确保为你的操作系统应用了最新的补丁。
对**mysqld**使用“--skip-external-locking”选项。在某些系统上,lockd锁定管理器不能正确工作,“--skip-external-locking”选项通知**mysqld**不使用外部锁定。(这意味着,你不能在相同的数据目录上运行2个**mysqld**服务器,如果使用**myisamchk**,必须谨慎。然而,尝试将该选项用作测试也是有益的)。
当mysqld看上去正在运行但并未响应时,是否运行了**mysqladmin -u root processlist**?某些时候,即使你认为**mysqld**处于闲置状态时,实际情况并非如此。问题可能是因为所有连接均已使用,或存在某些内部锁定问题。即使在该情况下,**mysqladmin -u root processlist**通常能够进行连接,并能提供关于当前连接数以及其状态的有用信息。
在运行其他查询的同时,在单独的窗口中运行命令**mysqladmin -i 5 status**或**mysqladmin -i 5 -r status**,以生成统计信息。
尝试采用下述方法:
从gdb(或另一个调试器)启动**mysqld**。请参见[E.1.3节,“在gdb环境下调试m**ysqld**”](# "E.1.3. Debugging mysqld under gdb")。
运行测试脚本。
在3个较低层面上输出backtrace(向后跟踪)和局部变量。在**gdb**中,当mysqld在gdb内崩溃时,可使用下述命令完成该任务:
backtrace
info local
up
info local
up
info local
使用**gdb**,你还能检查与info线程共存的线程,并切换至特定的线程N,其中,N是线程ID。
尝试用Perl脚本模拟你的应用程序,强制MySQL崩溃或行为异常。
发送正常的缺陷报告。请参见[1.7.1.3节,“如何通报缺陷和问题”](# "1.7.1.3. How to Report Bugs or Problems")。应比通常的报告更详细。由于MySQL是为很多人提供服务的,它可能因仅存在于你的计算机上的某事崩溃(例如,与你的特定系统库有关的错误)。
如果你遇到与包含动态长度行的表有关的问题,而且你仅使用VARCHAR列(而不是BLOB或TEXT列),可尝试用ALTER TABLE将所有VARCHAR列更改为CHAR列。这样,就会强制MySQL使用固定大小的行。固定大小的行占用的空间略多,但对损坏的容忍度更高。
目前的动态行代码在MySQL AB已使用多年,很少遇到问题,但从本质上看,动态长度行更倾向于出现错误,因此,不妨尝试采用该策略以查看它是否有帮助,这不失为一个好主意。
诊断问题时不要将你的服务器硬件排除在外。有缺陷的硬件能够导致数据损坏。对硬件进行故障诊断与排除操作时,尤其应注意RAM和硬盘驱动器。
### A.4.3. MySQL处理磁盘满的方式
在本节中,介绍了MySQL响应磁盘满错误的方式(如“设备上无剩余空间”),以及响应超配额错误的方式(如“写入失败”或“达到了用户屏蔽限制”)。
本节介绍的内容与写入MyISAM表有关。它也适用于写入二进制日志文件和二进制索引文件,但对“row”和“record”的应用应被视为“event”。
出现磁盘满状况时,MySQL将:
每分钟检查一次,查看是否有足够空间写入当前行。如果有足够空间,将继续,就像什么也未发生一样。
每10分钟将1个条目写入日志文件,提醒磁盘满状况。
为了减轻问题,可采取下述措施:
要想继续,仅需有足够的磁盘空间以插入所有记录。
要想放弃线程,必须使用**mysqladmin kill**。下次检查磁盘时将放弃线程(1分钟)。
其他线程可能会正在等待导致磁盘满状况的表。如果有数个“已锁定”的线程,杀死正在磁盘满状况下等待的某一线程,以便允许其他线程继续。
对前述行为的例外是,当你使用REPAIR TABLE或OPTIMIZE TABLE时,或当索引是在LOAD DATA INFILE或ALTER TABLE语句后、在批操作中创建的。所有这些语句能创建大的临时文件,如果保留这些文件,会导致系统其他部分出现大问题。如果在MySQL执行这类操作的同时磁盘已满,它将删除大的临时文件,并将表标注为崩溃。但对于ALTER TABLE例外,旧表保持不变。
### A.4.4. MySQL将临时文件储存在哪里
MySQL使用环境变量TMPDIR的值作为保存临时文件的目录的路径名。如果未设置TMPDIR,MySQL将使用系统的默认值,通常为/tmp、/var/tmp或/usr/tmp。如果包含临时文件目录的文件系统过小,可对mysqld使用“—tmpdir”选项,在具有足够空间的文件系统内指定1个目录。
在MySQL 5.1中,“—tmpdir”选项可被设置为数个路径的列表,以循环方式使用。在Unix平台上,路径用冒号字符“:”隔开,在Windows、NetWare和OS/2平台上,路径用分号字符“;”隔开。注意,为了有效分布负载,这些路径应位于不同的物理磁盘上,而不是位于相同磁盘的不同分区中。
如果MySQL服务器正作为复制从服务器使用,不应将“--tmpdir”设置为指向基于内存的文件系统的目录,或当服务器主机重启时将清空的目录。对于复制从服务器,需要在机器重启时仍保留一些临时文件,以便能够复制临时表或执行LOAD DATA INFILE操作。如果在服务器重启时丢失了临时文件目录下的文件,复制将失败。
MySQL会以隐含方式创建所有的临时文件。这样,就能确保中止**mysqld**时会删除所有临时文件。使用隐含文件的缺点在于,在临时文件目录所在的位置中,看不到占用了文件系统的大临时文件。
进行排序时(ORDER BY或GROUP BY),MySQL通常会使用1个或多个临时文件。所需的最大磁盘空间由下述表达式决定:
(length of what is sorted + sizeof(row pointer))
* number of matched rows
* 2
“row pointer”(行指针)的大小通常是4字节,但在以后,对于大的表,该值可能会增加。
对于某些SELECT查询,MySQL还会创建临时SQL表。它们不是隐含表,并具有SQL_*形式的名称。
ALTER TABLE会在与原始表目录相同的目录下创建临时表。
### A.4.5. 如何保护或更改MySQL套接字文件/tmp/mysql.sock``
对于服务器用来与本地客户端进行通信的Unix套接字文件,其默认位置是/tmp/mysql.sock。这有可能导致问题,原因在于,在某些版本的Unix上,任何人都能删除/tmp目录下的文件。
在大多数Unix版本中,可对/tmp目录进行保护,使得文件只能被其所有这或超级用户(根用户)删除。为此,以根用户身份登录,并使用下述命令在/tmp目录上设置粘着位:
shell> chmod +t /tmp
通过执行ls -ld /tmp,可检查是否设置了粘着位。如果最后一个许可字符是“t”,表明设置了粘着位。
另一种方法是改变服务器创建Unix套接字文件的位置。如果进行了这类操作,还应让客户端程序知道文件的位置。能够以多种不同方式指定文件位置:
在全局或局部选项文件中指定路径。例如,将下述行置于文件/etc/my.cnf中:
[mysqld]
socket=/path/to/socket
[client]
socket=/path/to/socket
请参见[4.3.2节,“使用选项文件”](# "4.3.2. Using Option Files")。
在运行客户端程序时,在命令行上为**mysqld_safe指定**“--socket”选项。
将MYSQL_UNIX_PORT环境变量设置为Unix套接字文件的路径。
重新从源码编译MySQL,以使用不同的默认Unix套接字文件位置。运行**configure**时,用“--with-unix-socket-path”选项定义文件路径。请参见[2.8.2节,“典型配置选项****”](# "2.8.2. Typical configure Options")。
用下述命令连接服务器,能够测试新的套接字位置是否工作:
shell> mysqladmin --socket=/path/to/socket version
### A.4.6. 时区问题
如果遇到与SELECT NOW()有关的问题,它返回GMT值而不是当地时间,就应通知服务器你的当前失去。如果UNIX_TIMESTAMP()返回错误值,上述方式同样适用。应为服务器所运行的环境进行这类设置,例如,在**mysqld_safe**或**mysql.server**中。请参见[附录F:](#)[_环境变量_](# "Appendix F. Environment Variables")。
也可以对**mysqld_safe**使用“--timezone=_timezone_name_”选项,为服务器设置失去。也可以在启动mysqld之前,通过设置TZ环境变量完成该设置。
“--timezone”或TZ的允许值与系统有关。关于可接受的值,请参见操作系统文档。
### A.5. 与查询有关的事宜
[ A.5.1. 搜索中的大小写敏感性](#)[ A.5.2. 使用DATE列方面的问题``](#)[ A.5.3. 与NULL值有关的问题``](#)[ A.5.4. 与列别名有关的问题](#)[ A.5.5. 非事务表回滚失败](#)[ A.5.6. 从相关表删除行](#)[ A.5.7. 解决与不匹配行有关的问题](#)[ A.5.8. 与浮点比较有关的问题](#)
### A.5.1. 搜索中的大小写敏感性
在默认情况下,MySQL搜索不区分大小写(但某些字符集始终区分大小写,如czech)。这意味着,如果你使用_col_name_ LIKE 'a%'进行搜索,你将获得以A或a开始的所有列。如果打算使搜索区分大小写,请确保操作数之一具有区分大小写的或二进制校对。例如,如果你正在比较均适用latin1字符集的列和字符串,可使用COLLATE操作符,使1个操作数具有latin1_general_cs或latin1_bin校对特性。例如:
col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin
如果希望总是以区分大小写的方式处理列,可使用区分大小写的或二进制校对声明它。请参见[13.1.5节,“CREATE TABLE语法”](# "13.1.5. CREATE TABLE Syntax")。
简单的比较操作(>=, >, =, <, <=, 排序和分组)基于每个字符的“排序值”。具有相同排序值的字符(如‘E’, ‘e’,和‘Ac’)将被当作相同的写字符。
### A.5.2. 使用DATE列方面的问题``
DATE值的格式是'YYYY-MM-DD'。按照标准的SQ
- 前言
- 1. 一般信息
- 2. 安装MySQL
- 3. 教程
- 4. MySQL程序概述
- 5. 数据库管理
- 6. MySQL中的复制
- 7. 优化
- 8. 客户端和实用工具程序
- 9. 语言结构
- 10. 字符集支持
- 11. 列类型
- 12. 函数和操作符
- 13. SQL语句语法
- 14. 插件式存储引擎体系结构
- 15. 存储引擎和表类型
- 16. 编写自定义存储引擎
- 17. MySQL簇
- 18. 分区
- 19. MySQL中的空间扩展
- 20. 存储程序和函数
- 21. 触发程序
- 22. 视图
- 23. INFORMATION_SCHEMA信息数据库
- 24. 精度数学
- 25. API和库
- 26. 连接器
- 27. 扩展MySQL
- A. 问题和常见错误
- B. 错误代码和消息
- C. 感谢
- D. MySQL变更史
- E. 移植到其他系统
- F. 环境变量
- G. MySQL正则表达式
- H. MySQL中的限制
- I. 特性限制
- J. GNU通用公共许可
- K. MySQL FLOSS许可例外
- 索引