վÄÚËÑË÷: ÇëÊäÈëËÑË÷¹ؼü´Ê
µ±ǰҳÃæ: ÔÚÏßÎĵµÊ×ҳ > MySQL 5.1²ο¼ÊֲáÖÐÎİæ

Appendix A. Problems and Common Errors - MySQL 5.1²ο¼ÊֲáÖÐÎİæ

附录A:问题和常见错误

目录

A.1. 如何确定导致问题的原å›�
A.2. 使用MySQL程序时的常见错误
A.2.1. 拒绝访问
A.2.2. 无法连接到[local] MySQL服务å™�
A.2.3. 客户端不支持鉴定协议
A.2.4. 输入密码时出现密码错è¯�
A.2.5. 主机的host_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_name不存åœ�
A.2.16. 无法初始化字符集
A.2.17. 文件未找åˆ�
A.3. 与安装有关的事宜
A.3.1. 与MySQL客户端库的链接问é¢�
A.3.2. 如何以普通用户身份运行MySQL
A.3.3. 与文件许可有关的问题
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.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.6. 与优化器有关的事å®�
A.7. 与表定义有关的事å®�
A.7.1. 与ALTER TABLE有关的问é¢�
A.7.2. 如何更改表中的列顺序
A.7.3. TEMPORARY TABLE问题
A.8. MySQL中的已知事宜
A.8.1. MySQL中的打开事宜
在本附录中,列出了一些你可能会遇到的常见问题和错误消息。并介绍了确定故障原因的方法,以及为解决问题所应采取的措施ã€�

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日志文件â€�ã€�

·         如果你不认为存在硬件问题,应尝试找出导致问题的原因。请使用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节,“请教问题或通报缺陷â€�中给出的说明ã€�

A.2. 使用MySQL程序时的常见错误

本节列出了用户运è¡�MySQL服务器时常会遇到的一些错误。尽管问题是在你尝试运行客户端时出现的,但对很多问题的解决方案来说,需要更æ”�MySQL服务器的配置ã€�

A.2.1. 拒绝访问

导致拒绝访问错误的原因很多。该错误常与连接时服务器允许客户端使用的MySQL账户有关。请参见5.7.8节,“拒绝访问错误的原因â€�。请参见5.7.2节,“权限系统工作原理â€�ã€�

A.2.2. 无法连接到[local] 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服务器以及其故障诊断和排除â€�ã€�

如果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服务器的连接失败â€�,以找出规避方法ã€�

3.    你正在使ç”�MIT-pthreads的系统上运行。如果你正在运行不具有固有线程的操作系统ï¼�mysqld将使ç”�MIT-pthreads软件包。请参见2.1.1节,“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â€�ã€�

6.    你使ç”�--socket=/path/to/socket选项启动äº�mysqld服务器,当忘记将套接字文件的新名称通知客户端程åº�。如果更改了关于服务器的套接字路径,也必须通知MySQL客户端。可在运行客户端程序时使用相同的—socket选项来完成该任务。此外,你还应确保客户端具有访问文件mysql.sock的权限。要想找出套接字文件的位置,可使用:

7.           shell> netstat -ln | grep mysql

请参è§�A.4.5节,“如何保护或更改MySQL套接字文ä»�/tmp/mysql.sockâ€�ã€�

8.    你正在使ç”�Linux而且1个服务器线程已死亡(内核已清除)。在此情况下,在重启MySQL服务器之前,必须杀死其ä»�mysqld线程(例如,使用killæˆ�mysql_zap脚本)ã€�请参è§�A.4.2节,“如果MySQL依然崩溃,应作些什么â€�ã€�

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/ã€�

·         启动注册表编辑器ï¼�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ã€�

关于密码混编和鉴定功能的额外背景知识,请参见5.7.9节,“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. 主机的host_name被屏è”�

如果遇到下述错误,表ç¤�mysqld已收到来来自主机â€�host_name”的很多连接请求,但该主机却在中途中断ã€�

由于出现很多连接错误,主æœ�'host_name'被屏蔽ã€�
可使ç”�'mysqladmin flush-hosts'解除屏蔽ã€�

允许的中断连接请求的数目ç”�max_connect_errors系统变量的值决定ã€�当超å‡�max_connect_errors规定的连接请求时ï¼�mysqld将认为某处出错(例如,某人正试图插入),并屏蔽主机的进一步连接请求,直至执行äº�mysqladmin flush-hosts命令,或发出äº�FLUSH HOSTS语句为止。请参见5.3.3节,“服务器系统变量â€�ã€�

在默认情况下ï¼�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语法â€�ã€�

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服务器不可用错误的最常见原因是服务器超时以及连接已关闭。在该情况下,通常能见到下述错误代码之一(具体的错误代码与操作系统有关)ï¼�

错误代码

描述

CR_SERVER_GONE_ERROR

客户端无法将问题发送至服务器ã€�

CR_SERVER_LOST

写入服务器时客户端未收到错误,但也未获得问题的完整答案(或任何答案)ã€�

在默认情况下,如果未发生任何事,8小时后服务器将关闭连接。也可以在启åŠ�mysqld时,通过设置wait_timeout变量更改时间限制。请参见5.3.3节,“服务器系统变量â€�.

如果æœ�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节,“信息包过大â€�ã€�

·         如果你的客户端低äº�4.0.8而且你的服务器高äº�4.0.8,当你接æ”�16MB或更大的信息包时,可能会丢失连接ã€�

·         如果MySQL是用â€�--skip-networking”选项启动的,也会见到MySQL服务器不可用错误ã€�

·         你遇到了执行查询时服务器宕机的缺陷ã€�

通过执行mysqladmin version并检查服务器的正常工作时间,可检查服务器是否宕机并重启。如果客户端连接是因mysqld崩溃和重启而断开的,应将重点放在查找崩溃你方靀€‚首先应再次检查发出的查询是否再次杀死了服务器。请参见A.4.2节,“如果MySQL依然崩溃,应作些什么â€�ã€�

用â€�--log-warnings=2â€�选项启动mysqld,可获得关于连接的更多信息。这样,就能将某些断开连接错误记录åˆ�hostname.err文件ä¸�。请参见5.11.1节,“错误日志â€�ã€�

如果你打算创建与该问题有关的缺陷报告,务必包含下述信息:

1.    指明MySQL服务器是否宕机。通过服务器错误日志可发现这方面的信息。请参见A.4.2节,“如果MySQL依然崩溃,应作些什么â€�ã€�

2.    如果特定查询杀死了mysqld,而且在运行查询前ç”�CHECK TABLE检查了涉及的表,你是否能提供可重复的测试范例?请参è§�E.1.6节,“如果出现表崩溃,请生成测试案例â€�ã€�

3.    åœ�MySQL服务器中,系统变é‡�wait_timeout的值是什么?ï¼�mysqladmin variables给出了该变量的值)ã€�

4.    你是否尝试使用â€�--log”选项来运è¡�mysqld,以确定是否在日志中出现问题ï¼�

另请参见A.2.10节,“通信错误和失效连接â€�ã€�

请参è§�1.7.1.2节,“请教问题或通报缺陷â€�ã€�

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节,“错误日志â€�。如果服务器是用â€�--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节,“服务器系统变量â€�ã€�

3.    客户端在数据传输中途突然结束ã€�

出现这类情况时,服务器将增加â€�Aborted_clientsâ€�(放弃客户端)状态变量ã€�

出现下述情况时,服务器将增加â€�Aborted_clientsâ€�(放弃客户端)状态变量ã€�

·         客户端不具有连接至数据库的权限ã€�

·         客户端采用了不正确的密码ã€�

·         连接信息包不含正确信息ã€�

·         获取连接信息包的时间超过connect_timeout秒ã€�请参è§�5.3.3节,“服务器系统变量â€�ã€�

如果出现这类情况,可能表明某人正试图侵入你的服务器!

对于放弃客户端或放弃连接问题,其他可能的源应包括ï¼�

·         ä¸�Linux一起使用以太网协议,半双工或全双工。很å¤�Linux以太网驱动均存在该缺陷。应通过FTP在客户端和服务器机器之间传输大文件来测试该缺陷。如果传输处äº�burst-pause-burst-pause(爆å��-暂停-爆发-暂停)模式,表明你遇到了Linux双工故障。唯一的解决方法是,将网卡å’�Hub/交换器的双工模式切换为全双工或半双工,并对结果进行测试以确定最佳设置ã€�

·         与线程库有关的某些问题导致读取中断ã€�

·         配置不良çš�TCP/IPã€�

·         有问题的以太网ã€�Hub、交换器、电缆等。仅能通过更换硬件才能恰当诊断ã€�

·         变量max_allowed_packet过小æˆ�查询要求的内存超过为mysqld分配的内存。请参见A.2.9节,“信息包过大â€�ã€�

另请参见A.2.8节,“MySQL服务器不可用â€�ã€�

A.2.11. 表已æ»�

表已满错误出现的方式有数种:

·         你正在使用低äº�3.23版的MySQL服务器,而且“内存中”临时表超过äº�tmp_table_size字节ã€�要想避免该问题,可使用â€�-O tmp_table_size=val”选项以便mysqld增加临时表的大小,或在发出有问题的查询之前,使用SQL选项SQL_BIG_TABLESã€�请参è§�13.5.3节,“SET语法â€�ã€�

也可以使用â€�--big-tables”选项启动mysqld。它与使用针对所有查询的SQL_BIG_TABLES完全相同ã€�

è‡�MySQL 3.23起,该问题应不再出现。如果“内存中”临时表超过tmp_table_size,服务器会自动将其转换为基于磁盘çš�MyISAM表ã€�

·         你正在使ç”�InnoDB表,并超出了InnoDB表空间ã€�在该情况下,解决方法是增åŠ�InnoDB表空间。请参见15.2.7节,“添加和删除InnoDB数据和日志文ä»�â€�ã€�

·         你正在仅支持2GB文件的操作系统上使用ISAMæˆ�MyISAM表,数据文件或索引文件达到了该限制值ã€�

·         你正在使ç”�MyISAM表,而且表所需的空间超过内部指针允许的大小。如果在创建表时未指å®�MAX_ROWS表,MySQL将使ç”�myisam_data_pointer_size系统变量ã€�默认值为6字节,它足以容纳65536TB数据。请参见5.3.3节,“服务器系统变量â€�ã€�

使用该语句,可检查最大数æ��/索引大小ï¼�

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节,“使用选项文件â€�ã€�

该错误的另一个原因可能是许可事宜。请确认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_name不存åœ�

如果遇到下述错误之一,通常意味着当前数据库中不存在具有给定名称的表:

è¡�'tbl_name'不存åœ�
无法找到文件ï¼�'tbl_name' (errno: 2)

在某些情况下,表或许存在,但未正确引用它ï¼�

·         由于MySQL使用目录和文件来保存数据库和表,如果它们位于区分文件名大小写的文件系统上,数据库和表名也区分文件大小写ã€�

·         即使对于不区分大小写的文件系统,å¦�Windows,在查询内对给定表的所有引用必须使用相同的大小写ã€�

可以使用SHOW TABLES检查位于当前数据库中的è¡�。请参见13.5.4节,“SHOW语法â€�ã€�

A.2.16. 无法初始化字符集

如果存在字符集问题,可能会遇到下述错误:

MySQL连接失败:无法初始化字符é›�charset_nameã€�

导致该错误的原因ï¼�

·         字符集为多字节字符集,但客户端不支持该字符集。在该情况下,需要使用â€�--with-charset=charset_name”或â€�--with-extra-charsets=charset_name”选项运行configure以重新编译客户端。请参见2.8.2节,“典型配置选项â€�ã€�

所有的标准MySQL二进制文件均是采用â€�--with-extra-character-sets=complex”编译的,能够支持所有的多字节字符集。请参见5.10.1节,“数据和排序用字符集â€�ã€�

·         字符集是未编译到mysqld中的简单字符集,而且字符集定义文件不在客户端预期的位置ã€�

在该情况下,需要采取下述方法之一解决问题ï¼�

1.    重新编译客户端,使之支持字符集。请参见2.8.2节,“典型配置选项â€�ã€�

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节,“服务器系统变量â€�。设置这些值的最简单方式是在选项文件中增åŠ�1个选项。请参见4.3.2节,“使用选项文件â€�。如æž�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客户端库的链接问é¢�

当你链接到应用程序以使用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â€�ã€�

当你试图执行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节,“安装后的设置和测试â€�ã€�

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ï¼�环境变量ã€�

A.4. 与管理有关的事宜

A.4.1. 如何复位根用户密ç �

如果你从未为MySQL设置根用户密码,服务器在以根用户身份进行连接时不需要密码。但是,建议你为每个账户设置密码。请参见5.6.1节,“通用安全指南â€�ã€�

如果你以前设置了根用户密码,但却忘记了该密码,可设置新的密码。下述步骤是针对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节,“错误日志â€�ã€�

在某些系统上,在错误日志中,可发çŽ�mysqld宕机的堆栈跟踪,可使ç”�resolve_stack_dump程序解决å®�。请参见E.1.4节,“使用堆栈跟踪â€�。注意,错误日志中的变量值并非始终是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章:数据库管ç��ã€�

使用â€�--log”选项启动mysqld,并根据写入日志的信息确定是否某些特殊的查询杀死了服务器。约95%的缺陷与特定的查询有关。正常情况下,这是服务器重启前日志文件中最够数个查询中çš�1个。请参见5.11.2节,“通用查询日志â€�。如果能够用特殊查询重复杀æ­�MySQL,即使在发出查询前检查了所有表的情况下也同样,那么你就应能确定缺陷,并应提交关于该缺陷的缺陷报告。请参见1.7.1.3节,“如何通报缺陷和问题â€�ã€�

尝试提供一个测试范例,我们应能利用该范例重复问题。请参见E.1.6节,“如果出现表崩溃,请生成测试案例â€�ã€�

请在mysql-test目录下并根据MySQL基准进行测试ã€�请参è§�27.1.2节,“MySQL测试套件â€�。它们能相当良好地测è¯�MySQL。你也可以为基准测试增加代码,以模拟你的应用程序。基准测试可在源码分发版çš�sql-bench目录下找到,对于二进制分发版,可åœ�MySQL安装目录下的sql-bench目录下找到ã€�

尝试使用fork_big.pl脚本(它位于源码分发版的测试目录下)ã€�

如果你将MySQL配置为调试模式,如果某事出错,可更为容易地搜集关于可能错误的信息。如果将MySQL配置为调试模式,可生æˆ�1个安全的内存分配程序,可使用它发现某些错误。此外,它还提供了很多输出,这类输出与出现的问题相关。在configure上使用â€�--with-debug”或â€�--with-debug=full”选项重新配置MySQL,然后再编译它。请参见E.1节,“调试MySQL服务器â€�ã€�

确保为你的操作系统应用了最新的补丁ã€�

å¯�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环境下调试mysqldâ€�ã€�

运行测试脚本ã€�

åœ�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节,“如何通报缺陷和问题â€�。应比通常的报告更详细。由äº�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节,“使用选项文件â€�ã€�

在运行客户端程序时,在命令行上为mysqld_safe指定â€�--socketâ€�选项ã€�

å°�MYSQL_UNIX_PORT环境变量设置ä¸�Unix套接字文件的路径ã€�

重新从源码编è¯�MySQL,以使用不同的默è®�Unix套接字文件位置。运è¡�configure时,用â€�--with-unix-socket-path”选项定义文件路径。请参见2.8.2节,“典型配置选项â€�ã€�

用下述命令连接服务器,能够测试新的套接字位置是否工作ï¼�

shell> mysqladmin --socket=/path/to/socket version

A.4.6. 时区问题

如果遇到ä¸�SELECT NOW()有关的问题,它返å›�GMT值而不是当地时间,就应通知服务器你的当前失去。如æž�UNIX_TIMESTAMP()返回错误值,上述方式同样适用。应为服务器所运行的环境进行这类设置,例如,在mysqld_safeæˆ�mysql.server中。请参见附录Fï¼�环境变量ã€�

也可以对mysqld_safe使用â€�--timezone=timezone_name”选项,为服务器设置失去。也可以在启åŠ�mysqld之前,通过设置TZ环境变量完成该设置ã€�

â€�--timezone”或TZ的允许值与系统有关。关于可接受的值,请参见操作系统文档ã€�

A.5. 与查询有关的事宜

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语法â€�ã€�

简单的比较操作ï¼�>=, >, =, <, <=, 排序和分组)基于每个字符的“排序值”。具有相同排序值的字符(如â€�Eâ€�, â€�eâ€�,和â€�é’)将被当作相同的写字符ã€�

A.5.2. 使用DATE列方面的问题

DATE值的格式æ˜�'YYYY-MM-DD'ã€�按照标准çš�SQL,不允许其他格式。在UPDATE表达式以å��SELECT语句çš�WHERE子句中应使用该格式。例如:

mysql> SELECT * FROM tbl_name WHERE date >= '2003-05-05';

为了方便,如果日期是在数值环境下使用的,MySQL会自动将日期转换为数值(反之亦然)。它还具有相当的智能,在更新时或在与TIMESTAMPã€�DATEæˆ�DATETIME列比较日期的WHERE子句中,允许â€�宽松çš�â€�字符串形式(â€�宽松形式â€�表示,任何标点字符均能用作各部分之间的分隔符。例如,'2004-08-15'å’�'2004#08#15'是等同的)ã€�MySQL还能转换不含任何分隔符的字符串(å¦�'20040815'),前体是它必须是有意义的日期ã€�

使用<ã€�<=ã€�=ã€�>=ã€�>、或BETWEEN操作符将DATEã€�TIMEã€�DATETIMEæˆ�TIMESTAMP与常量字符串进行比较时,MySQL通常会将字符串转换为内部长整数,以便进行快速比较(以及略为“宽松”的字符串检查)。但是,该转换具有下述例外:

比较两列æ—�

å°�DATEã€�TIMEã€�DATETIMEæˆ�TIMESTAMP列与表达式进行比较时

使用其他比较方法时,å¦�INæˆ�STRCMP()ã€�

对于这些例外情形,会将对象转换为字符串并执行字符串比较,采用该方式进行比较ã€�

为了保持安全,假定按字符串比较字符串,如果你打算比较临时值和字符串,将使用恰当的字符串函数ã€�

对于特殊日期'0000-00-00',能够以'0000-00-00'形式保存和检紀€‚在MyODBC中使ç”�'0000-00-00'日期时,对于MyODBC 2.50.12或更高版本,该日期将被自动转换为NULL,这是因ä¸�ODBC不能处理这类日期ã€�

由于MySQL能够执行前面所介绍的转换,下述语句均能正常工作ï¼�

mysql> INSERT INTO tbl_name (idate) VALUES (19970505);
mysql> INSERT INTO tbl_name (idate) VALUES ('19970505');
mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00');
 
mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT MOD(idate,100) FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';

但是,下述语句不能正常工作:

mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'20030505')=0;

STRCMP()是一种字符串函数,它能将idate转换ä¸�'YYYY-MM-DD'格式的字符串ï¼�并执行字符串比较。它不能å°�'20030505'转换ä¸�日期'2003-05-05'并进行日期比较ã€�

如果你正在使ç”�ALLOW_INVALID_DATES SQL模式ï¼�MySQL允许以仅执行给定的有限检查方式保存日期:MySQL仅保证天位于1ï½�31的范围内,月位于1ï½�12的范围内ã€�

这样就使å¾�MySQL很适合äº�Web应用程序,其中,你能获得三个不同字段中的年、月、日值,也能准确保存用户插入的值(无日期验证)ã€�

如果未使ç”�NO_ZERO_IN_DATE SQL模式,“天”和“月”部分可能为0。如果你打算将生日保存在DATE列而且仅知道部分日期,它十分方便ã€�

如果未使ç”�NO_ZERO_DATE SQL模式ï¼�MySQL也允许你å°�'0000-00-00'保存为“伪日期”。在某些情况下,它比使用NULL值更方便ã€�

如果无法将日期转换为任何合理值,â€�0”将保存åœ�DATE列中,并被检索为'0000-00-00'。这是兼顾速度和便利性的事宜。我们认为,数据库服务器的职责是检索与你保存的日期相同的日æœ�(即使在任何情况下,数据在逻辑上不正确也同样)。我们认为,对日期的检查应由应用程序而不是服务器负责ã€�

如果你希æœ�MySQL检查所有日期并仅接受合法日期(除非ç”�IGNORE覆盖),应将sql_mode设置ä¸�"NO_ZERO_IN_DATE,NO_ZERO_DATE"ã€�

A.5.3. 与NULL值有关的问题

对于SQL的新手,NULL值的概念常常会造成混淆,他们常认为NULL是与空字符串''相同的事ã€�情况并非如此。例如,下述语句是完全不同的ï¼�

mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ('');

这两条语句均会将值插å…�phone(电话)列,但第1条语句插入的æ˜�NULL值,ç¬�2条语句插入的是空字符串。第1种情况的含义可被解释为“电话号码未知”,而第2种情况的含义可被解释为“该人员没有电话,因此没有电话号码”ã€�

为了进行NULL处理,可使用IS NULLå’�IS NOT NULL操作符以å��IFNULL()函数ã€�

åœ�SQL中,NULLå€�与任何其它值的比较(即使是NULL)永远不会为“真”。包å��NULL的表达式总是会导å‡�NULL值,除非在关于操作符的文档中以及表达式的函数中作了其他规定。下述示例中的所有列均返å›�NULLï¼�

mysql> SELECT NULL, 1+NULL, CONCAT('Invisible',NULL);

如果打算搜索列值为NULL的列,不能使ç”�expr = NULL测试。下述语句不返回任何行,这是因为,对于任何表达式ï¼�expr = NULL永远不为â€�çœ�â€�ï¼�

mysql> SELECT * FROM my_table WHERE phone = NULL;

要想查找NULL值,必须使用IS NULL测试ã€�在下面的语句中,介绍了查æ‰�NULL电话号码和空电话号码的方式:

mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = '';

更多信息和示例,请参è§�3.3.4.6节,“使用NULL值â€�ã€�

如果你正在使ç”�MyISAMã€�InnoDBã€�BDB、或MEMORY存储引擎,能够在可能具有NULL值的列上增加1条索引。如不然,必须声明索引列ä¸�NOT NULL,而且不能å°�NULL插入到列中ã€�

ç”�LOAD DATA INFILE读取数据时,对于空的或丢失的列,将用''更新它们。如果希望在列中具有NULL值,应在数据文件中使ç”�\N。在某些情况下,也可以使用文字性单词â€�NULL”。请参见13.2.5 â€�LOAD DATA INFILE语法â€�ã€�

使用DISTINCTã€�GROUP BYæˆ�ORDER BY时,所æœ�NULL值将被视为等同的ã€�

使用ORDER BY时,首先将显ç¤�NULL值,如果指定äº�DESC按降序排列,NULL值将最后显示ã€�

对于聚合(累计)函数,如COUNT()ã€�MIN()å’�SUM(),将忽略NULL值ã€�对此的例外是COUNT(*),它将计数行而不是单独的列值。例如,下述语句产生两个计数。首先计数表中的行数,其次计æ•�age列中的非NULL值数目:

mysql> SELECT COUNT(*), COUNT(age) FROM person;

对于某些列类型,MySQL将对NULL值进行特殊处理。如果将NULL插入TIMESTAMP列,将插入当前日期和时间。如果将NULL插入具有AUTO_INCREMENT属性的整数列,将插入序列中的下一个编号ã€�

A.5.4. 与列别名有关的问é¢�

可以使用别名来引ç”�GROUP BYã€�ORDER BYæˆ�HAVING子句中的列。别名也能用于为列提供更好的名称ï¼�
SELECT SQRT(a*b) AS root FROM tbl_name GROUP BY root HAVING root > 0;
SELECT id, COUNT(*) AS cnt FROM tbl_name GROUP BY id HAVING cnt > 0;
SELECT id AS 'Customer identity' FROM tbl_name;

标准SQL不允许在WHERE子句中已用列别名。这是因为,执行WHERE代码时,可能尚未确定列值。例如,下述查询是非法的ï¼�

SELECT id, COUNT(*) AS cnt FROM tbl_name WHERE cnt > 0 GROUP BY id;

执行WHERE语句以确å®�哪些行应被包含在GROUP BY部分中,è€�HAVING用于确定应使用结果集中的哪些行ã€�

A.5.5. 非事务表回滚失败

执行ROLLBACK(回滚)时,如果收到下述消息,表示事务中使用çš�1个或多个表不支持事务ï¼�

警告:某些更改的非事务性表不能被回滚ã€�

这些非事务性表不受ROLLBACK语句的影响ã€�

如果在事务中意外地混合了事务性表和非事务性表,导致该消息的最可能原因是,你认为本应是事务性的表实际上不是。如你试图使ç”�mysqld服务器不支持的事务性存储引擎(或用启动选项禁止了它)创建表,就可能出现该情况。如æž�mysqld不支持存储引擎,它将ä»�MyISAM表创建表,这是非事务性表ã€�

可使用下述语句之一检查表的标类型ï¼�

SHOW TABLE STATUS LIKE 'tbl_name';
SHOW CREATE TABLE tbl_name;

请参è§�13.5.4.18节,“SHOW TABLE STATUS语法以及13.5.4.5节,“SHOW CREATE TABLE语法â€�ã€�

使用下述语句,可检æŸ�mysqld服务器支持的存储引擎ï¼�

SHOW ENGINES;

也可以使用下述语句,检查与你感兴趣的存储引擎有关的变量值:

SHOW VARIABLES LIKE 'have_%';

例如,要想确å®�InnoDB存储引擎是否可用,可检æŸ�have_innodb变量的值ã€�

请参è§�13.5.4.8节,“SHOW ENGINES语法â€�å’�13.5.4.21节,“SHOW VARIABLES语法â€�ã€�

A.5.6. 从相关表删除è¡�

如果针对related_tableçš�DELETE语句的总长度超è¿�1MB(系统变é‡�max_allowed_packet的默认值),应将其分为较小的部分,并执行多ä¸�DELETE语句。如æž�related_column是索引列,为每条语句指定100ï½�1000ä¸�related_column值,或许能获得更快的DELETE速度。如æž�related_column不是索引列,速度ä¸�IN子句中的参量数目无关ã€�

A.5.7. 解决与不匹配行有关的问题

如果有使用了很多表的复杂查询,但未返回任何行,应采用下述步骤找出什么出错:

ç”�EXPLAIN测试查询,以检æŸ�是否发现某事显然出错。请参见7.2.1节,“EXPLAIN语法(获取关于SELECT的信息)â€�ã€�

仅选择åœ�WHERE子句中使用的列ã€�

从查询中1次删é™�1个表,直至返回了某些行为歀€‚如果表很大,较好的主意是在查询中使ç”�LIMIT 10ã€�

对于具有与上次从查询中删除的表匹配的行的列,发出SELECT查询ã€�

如果å°�FLOATæˆ�DOUBLE列与具有数值类型的数值进行比较,不能使用等式(=)比较。在大多数计算机语言中,该问题很常见,这是因为,并非所有的浮点值均能以准确的精度保存。在某些情况下,å°�FLOAT更改ä¸�DOUBLE可更正该问题ã€�请参è§�A.5.8节,“与浮点比较有关的问题â€�ã€�

如果仍不能找出问题之所在,请创建能与显示问题的â€�mysql test < query.sql”一起运行的最小测试。通过使用mysqldump --quick db_name tbl_name_1 ... tbl_name_n > query.sql转储表,可创建测试文件。在编辑器中打开文件,删除某些插入的行(如果有超出演示问题所需的行),并在文件末尾添加SELECT语句ã€�

通过执行下述命令,验证测试文件能演示问题ï¼�

shell> mysqladmin create test2
shell> mysql test2 < query.sql

使用mysqlbug将测试文件张贴到哟娜通用MySQL邮件列表。请参见1.7.1.1节,“The MySQL邮件列表â€�ã€�

A.5.8. 与浮点比较有关的问题

注意,下述部分主要与DOUBLEå’�FLOAT列相关,原因在于浮点数的不准确本质ã€�MySQL使用64位十进制数值的精度执行DECIMAL操作,当处理DECIMAL列时,应能解决大多数常见的不准确问题ã€�

浮点数有时会导致混淆,这是因为它们无法以准确值保存在计算机体系结构中。你在屏幕上所看到的值通常不是数值的准确值。对äº�FLOATå’�DOUBLE列类型,情况就是如此ã€�DECIMAL列能保存具有准确精度的值,这是因为它们是由字符串表示的ã€�

在下面的示例中,介绍了使ç”�DOUBLE时的问题ï¼�

mysql> CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
    -> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
    -> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
    -> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
    -> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
    -> (6, 0.00, 0.00), (6, -51.40, 0.00);
 
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
    -> FROM t1 GROUP BY i HAVING a <> b;
 
+------+-------+------+
| i    | a     | b    |
+------+-------+------+
|    1 |  21.4 | 21.4 |
|    2 |  76.8 | 76.8 |
|    3 |   7.4 |  7.4 |
|    4 |  15.4 | 15.4 |
|    5 |   7.2 |  7.2 |
|    6 | -51.4 |    0 |
+------+-------+------+

结果是正确的。尽管前5个记录看上去不应能进行比较测试(aå’�b的值看上去没有什么不同),但它们能进行比较,这是因为显示的数值间的差异在十分位左右,具体情况取决于计算机的体系结构ã€�

如果åˆ�d1å’�d2定义ä¸�DECIMAL而不æ˜�DOUBLEï¼�SELECT查询的结果仅包含1行,即上面显示的最å��1行ã€�

A.6. 与优化器有关的事å®�

MySQL采用了基于开销的优化器,以确定处理查询的最解方式。在很多情况下,MySQL能够计算最佳的可能查询计划,但在某些情况下ï¼�MySQL没有关于数据的足够信息,不得不就数据进行“有教养”的估测ã€�

å½�MySQL未能做“正确的”事时,可使用下述工具来帮助MySQLï¼�

使用EXPLAIN语句获取关于MySQL如何处理查询的信息。要想使用它,可åœ�SELECT语句前添加关键字EXPLAINï¼�

mysql> EXPLAIN SELECT * FROM t1, t2 WHERE t1.i = t2.i;

关于EXPLAIN的详细讨论,请参è§�7.2.1节,“EXPLAIN语法(获取关于SELECT的信息)â€�ã€�

使用ANALYZE TABLE tbl_name,为已扫描的表更新键分配。请参见13.5.2.1节,“ANALYZE TABLE语法â€�ã€�

为已扫描的表使用FORCE INDEX,通知MySQL:与使用给定的索引相比,表扫描开销昂贵。请参见13.2.7节,“SELECT语法â€�ã€�

SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
WHERE t1.col_name=t2.col_name;

USE INDEXå’�IGNORE INDEX也有一定的帮助ã€�

关于全局和表级别çš�STRAIGHT_JOIN。请参见13.2.7节,“SELECT语法â€�ã€�

你可以调节全局或线程类系统变量。例如,用â€�--max-seeks-for-key=1000â€�选项启动mysqld,或使用“SET max_seeks_for_key=1000â€�来通知优化器:假定任何表扫描均不会导致1000个以上的键搜紀€�请参è§�5.3.3节,“服务器系统变量â€�ã€�

A.7. 与表定义有关的事å®�

A.7.1. 与ALTER TABLE有关的问é¢�

ALTER TABLE将表更改为当前字符集。如果在执行ALTER TABLE操作期间遇到重复键错误,原因在于新的字符集将2个键映射到了相同值,或是表已损坏。在后一种情况下,应在表上运è¡�REPAIR TABLEã€�

如果ALTER TABLE失败并给出下述错误,问题可能是因为在ALTER TABLE操作的早期阶段出çŽ�MySQL崩溃,没有名ä¸�A-xxxæˆ�B-xxx的旧表:

Error on rename of './database/name.frm'
to './database/B-xxx.frm' (Errcode: 17)

在该情况下,进入MySQL数据目录,并删除其名称为ä»�A-æˆ�B-开始的所有文ä»�(或许你希望将它们移动到其他地方而不是删除它们)ã€�

ALTER TABLE的工作方式如下:

  • 用请求的结构变化创建名为A-xxx的新表ã€�
  • 将所有行从原始表拷贝åˆ�A-xxxã€�
  • 将原始表重命名为B-xxxã€�
  • å°�A-xxx重命名为原始表的名称ã€�
  • 删除B-xxxã€�

如果在重命名操作中出错,MySQL将尝试撤销更改。如果错误很严重(尽管这不应出现),MySQL会将旧表保留ä¸�B-xxx。简单地在系统级别上重命名表文件,应能使数据复原ã€�

如果在事务性表上使ç”�ALTER TABLE,或正在使用Windowsæˆ�OS/2操作系统,如果已在表上执行了LOCK TABLE操作ï¼�ALTER TABLE将对表执行解锁操作。这是因ä¸�InnoDB和这类操作系统不能撤销正在使用的表ã€�

A.7.2. 如何更改表中的列顺序

首先,请考虑是否的确需要更改表中的列顺序ã€�SQL的核心要点是从数据存储格式获取应用。总应指定检索数据的顺序。在下面的第1条语句中,以col_name1ã€�col_name2ã€�col_name3顺序返回列;在第2条语句中,以col_name1ã€�col_name3ã€�col_name2顺序返回列:

mysql> SELECT col_name1, col_name2, col_name3 FROM tbl_name;
mysql> SELECT col_name1, col_name3, col_name2 FROM tbl_name;

如果决定更改表列的顺序,可执行下述操作:

  1. 用具有新顺序的列创建新表ã€�
  2. 执行该语句:
mysql> INSERT INTO new_table
    -> SELECT columns-in-new-order FROM old_table;
  1. 撤销或重命名old_tableã€�
  2. 将新表重命名为原始名称:
mysql> ALTER TABLE new_table RENAME old_table;

SELECT *十分适合于测试查诀€‚但是,在应用程序中,永远不要依èµ�SELECT *的使用,不要依赖根据其位置检索列。如果添加、移动或删除了列,所返回的列的顺序和位置不会保持相同。对表结构的简单更改也会导致应用程序失败ã€�

A.7.3. TEMPORARY TABLE问题

下面介绍了对使用TEMPORARY表的限制ï¼�

  • TEMPORARY表只能是HEAPã€�ISAMã€�MyISAMã€�MERGE、或InnoDB类型ã€�
  • 在相同的查询中,不能引用TEMPORARYè¡�1次以上。例如,下例不能正常工作ï¼�
mysql> SELECT * FROM temp_table, temp_table AS t2;
错误1137:不能再次打开表:'temp_table'
  • SHOW TABLES语句不会列出TEMPORARY表ã€�
  • 不能使用RENAME重命å��TEMPORARY表ã€�但能使用ALTER TABLE取而代之:
mysql> ALTER TABLE orig_name RENAME new_name;

A.8. MySQL中的已知事宜

在本节中,列出了当前MySQL版本中的已知事宜ã€�

关于平台相关事宜的更多信息,请参è§�2.12节,“具体操作系统相关的注意事项â€�å’�附录Eï¼�移植到其他系ç»�中的安装和移植说明ã€�

A.8.1. MySQL中的打开事宜

下面列出了已知问题,更正它们具有较高的优先级ï¼�

  • 如果å°�NULL值与使用ALL/ANY/SOME的子查询进行比较,而且子查询返å›�空的结果,比较操作会评估NULL的非标准结果而不æ˜�TRUEæˆ�FALSE。在MySQL 5.1中将更正该问题ã€�
  • 对于IN的线子查询优化不像â€�=”那样有效ã€�
  • 即使使用äº�lower_case_table_names=2(允è®�MySQL记住数据库名和表名使用的大小写),对于函æ•�DATABASE()或在各种日志内(在不区分大小写的系统上)ï¼�MySQL也不会记住数据库名使用的大小写情况ã€�
  • 在复制操作中,撤销FOREIGN KEY约束不工作,这是因为约束可能在从服务器上有另一个名称ã€�
  • REPLACE(以及具æœ�REPLACE选项çš�LOAD DATA)不会触å��ON DELETE CASCADEã€�
  • 如果未使用所有列而且仅使ç”�DISTINCT列表中的列,åœ�GROUP_CONCAT()中,DISTINCT不能ä¸�ORDER BY一起工作ã€�
  • 如果1位用户拥有长时间运行的事务,而且å��1位用户撤销了在事务中更新的æŸ�1表,那么在表用于事务本身之前,存在较小的机会,会在二进制日志中包å��DROP TABLE命令。我们计划更正该问题,方法是è®�DROP TABLE命令等待,直至表未在任何事务中使用为歀€�
  • 将大的整数值(介于263å’�264â€�1之间)插入数值或字符串列时,它将作为负值插入,这是因为该数值是在有符号整数环境下评估的ã€�
  • 如果服务器运行在不具备二进制日志功能的条件下ï¼�FLUSH TABLES WITH READ LOCK不能屏蔽COMMIT,执行完整备份时这可能会导致问题(表间的一致性问题)ã€�
  • 在某些情况下,作用在BDB表上çš�ANALYZE TABLE会导致表不可用,直至重启mysqld为止。如果出现该情况,请åœ�MySQL错误文件中查找下述形式的错误ï¼�
001207 22:07:56  bdb:  log_flush: LSN past current end-of-log
  • 在所有事务完成之前,不要åœ�BDB表(正在其上运行多语句事务)上执è¡�ALTER TABLE(可能会忽略事务)ã€�
  • 对于正在使用INSERT DELAYED的表,在其上执行ANALYZE TABLEã€�OPTIMIZE TABLEå’�REPAIR TABLE时,可能会导致问题ã€�
  • 在表上执è¡�LOCK TABLE ...å’�FLUSH TABLES ...时,不保证没有完成一半的事务ã€�
  • BDBè¡�打开的速度相对较慢。如果你在数据库上有很多BDB表,如果未使ç”�â€�-Aâ€�选项或正使用再混编功能,要想在数据库上使ç”�mysql客户端,需要花费较长的时间。当你有大的表高速缓冲时,这点尤其明显ã€�
  • 复制功能采用了查询级日志功能:主服务器将已执行的查询写入二进制日志。这是一种速度很快、简洁和有效的记录方法,在大多数情况下工作良好ã€�

如果以特定的方式设计查询,使得数据更改是非决定性(通常不推荐,即使在复制之外也同样),主服务器和从服务器上的数据将变得不同ã€�

例如ï¼�

  • å°�0或NULL值插入AUTO_INCREMENT列中的CREATE ... SELECT或INSERT ... SELECT语句ã€�
  • DELETE,如果从具有ON DELETE CASCADE属性的外键的表中删除行ã€�
  • REPLACE ... SELECT、INSERT IGNORE ... SELECT,如果在插入的数据中具有重复键ã€�

当且仅当前述查询没有保证决定行顺序的ORDER BY子句时ã€�

例如,对于不具有ORDER BYçš�INSERT ... SELECTï¼�SELECT可能会以不同的顺序返回行(它会导致具有不同等级的行,从而导è‡�AUTO_INCREMENT列中的不同数值),具体情况取决于优化器在主服务器和从服务器上所作的选择ã€�

在主服务器和从服务器上,查询将进行不同的优化,仅当:

  • 使用不同的存储引擎在主服务器上而不是从服务器上保存表。(能够在主服务器和从服务器上使用不同的存储引擎。例如,如果从服务器具有较少的可用磁盘空间,可以在主服务器上使用InnoDB,但åœ� 从服务器桑使ç”�MyISAM)ã€�
  • 在主服务器和从服务器上,MySQL缓冲区大小是不同的(key_buffer_size等)ã€�
  • 在主服务器和从服务器上运行不同的MySQL版本,版本间的优化器代码也不同ã€�

该问题也会影响使ç”�mysqlbinlog|mysql的数据库恢复ã€�

避免该问题的最简单方法是,为前述的非决定性查询增åŠ�ORDER BY子句,以确保总是以相同的顺序保存或更改行ã€�

在将来的MySQL版本中,需要时,我们将自动增加ORDER BY子句ã€�

下面列出了已知的事宜,这些事宜将在恰当的时候更正:

  • 日志文件名基于服务器主机名(如果未使用启动选项指定文件名的话)。如果更改了主机名,你将不得不使用诸如â€�--log-bin=old_host_name-bin”等选下美国。另一种选择是重命名旧文件,以反映主机名变更情况(如果是二进制日志,需要编辑二进制日志索引文件,并更正binlog名称)。请参见5.3.1节,â€�mysqld命令行选项â€�ã€�
  • Mysqlbinlog不删除执è¡�LOAD DATA INFILE命令后遗留的临时文件。请参见8.6节,“mysqlbinlog:用于处理二进制日志文件的实用工具â€�ã€�
  • RENAME不能ä¸�TEMPORARY表一起工作,也不能与MERGE表中使用的表一起工作ã€�
  • 由于表定义文件的保存方式,不能在表名、列名或枚举中使用字ç¬�255ï¼�CHAR(255))。按照安排,当我们实施了新的表定义格式文件时,将åœ�5.1版中更正该问题ã€�
  • 使用SET CHARACTER SET时,不能在数据库、表和列名中使用转换的字符ã€�
  • 不能åœ�LIKE ... ESCAPE中与ESCAPE一起使ç”�â€�_’或â€�%’ã€�
  • 如果你有1ä¸�DECIMAL列,其中,相同的数值以不同的格式保存(例如ï¼�+01.00ã€�1.00ã€�01.00),GROUP BY可能会将每个值当作不同的值ã€�
  • 使用MIT-pthreads时,不能在另一个目录下创建服务器。这是因为它需要更æ”�MIT-pthreads,我们不太会更正该问题。请参见2.8.5 â€�MIT-pthreads注意事项â€�ã€�
  • åœ�GROUP BYã€�ORDER BYæˆ�DISTINCT中,不能可靠地使ç”�BLOBå’�TEXT值。在这类情况下,ä¸�BLOB值进行比较时,仅使用最前的max_sort_length字节ã€�max_sort_length的默认值是1024,可在服务器启动时或运行时更改它ã€�
  • 数值计算是使用BIGINTæˆ�DOUBLE(正常情况下均为64位长)进行的ã€�你所能获得的精度取决于函数。通用规则是位函数是按BIGINT精度执行的,IFå’�ELT()是按BIGINTæˆ�DOUBLE精度执行的,其余的函数是æŒ�DOUBLE精度执行的。对于除位字段外的其他数,如果大äº�63位(9223372036854775807),应避免使ç”�无符号长long值ã€�
  • åœ�1个表中,最多能æœ�255ä¸�ENUMå’�SET列ã€�
  • åœ�MIN()ã€�MAX()以及其他聚合函数中,MySQL目前会根据其字符串值比è¾�ENUMå’�SET列,而不是根据字符串在集合中的相对位置ã€�
  • mysqld_safe会将来自mysqld的所有消息再定向åˆ�mysqld日志。与之相关的1个问题是,如果你执行mysqladmin refresh关闭并再次打开日志ï¼�stdoutå’�stderr仍会被重定向到旧的日志ã€�如果你以广义方式使用â€�--logâ€�ï¼�应编è¾�mysqld_safe以记录到host_name.err而不æ˜�host_name.log,以便通过删除它并执行mysqladmin refresh,方便地收回为旧日志分配的空间ã€�
  • åœ�UPDATE语句中,列从左向右更新。如果引用了已更新的列,你将得到更新值而不是原始值。例如,下述语句会将KEY增加2,而不æ˜�1ï¼�
mysql> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1;
  • 你可以在相同查询中引用多个临时表,但不能引用任何给定的临时表1次以上。例如,下述语句不能正常工作ï¼�
mysql> SELECT * FROM temp_table, temp_table AS t2;
错误1137:不能再次打开表:'temp_table'
  • 当你在联合操作中使用“隐含”列时,与未使用隐含列相比,优化器将以不同的方式处理DISTINCT。在联合操作中,隐含列将作为结果的组成部份计数(即使未显示),但在正常查询中,隐含列不参ä¸�DISTINCT比较。在以后,我们可能会更改该情况,在执è¡�DISTINCT时不比较隐含列ã€�

例如ï¼�

SELECT DISTINCT mp3id FROM band_downloads
       WHERE userid = 9 ORDER BY id DESC;

以及

SELECT DISTINCT band_downloads.mp3id
       FROM band_downloads,band_mp3
       WHERE band_downloads.userid = 9
       AND band_mp3.id = band_downloads.mp3id
       ORDER BY band_downloads.id DESC;

在第2种情况下,使ç”�MySQL服务å™�3.23.x,可在结果集中获å¾�2个等同行(这是因为,隐藏ID列中的值可能不同)ã€�

注意,在结果集中,仅对不å��ORDER BY列的查询才会出现该情况ã€�

  • 如果在返回空集的查询上执è¡�PROCEDURE,在某些情况下,PROCEDURE不转换列ã€�
  • 创建具有MERGE类型的表时,不检查基本表是否具有兼容的类型ã€�
  • 如果使用ALTER TABLEä¸�MERGE表中使用的表增加äº�UNIQUE索引,然后在MERGE表上增加了正常索引,如果在表中存在旧的、非UNIQUE键,对于这些表,键顺序是不同的。这是因为,ALTER TABLE会将UNIQUE索引放在正常索引之前,以便能尽早检测到重复的键ã€�
 

这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访é—�dev.mysql.com。原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的ã€�