附录B错误,错误代码和常见问题

目录

B.1错误消息源和组件
B.2错误信息接口
B.3错误消息参考
B.3.1服务器错误消息参考
B.3.2客户端错误消息参考
B.3.3全局错误消息参考
B.4问题和常见错误
B.4.1如何确定导致问题的原因
B.4.2使用MySQL程序时的常见错误
B.4.3与管理有关的问题
B.4.4与查询相关的问题
B.4.5与优化器相关的问题
B.4.6表定义相关问题
B.4.7 MySQL中的已知问题

本附录描述了MySQL提供的错误信息类型以及如何获取有关它们的信息。 它还列出了MySQL服务器和MySQL客户端程序生成的错误消息。 最后一节是故障排除。 它描述了可能发生的常见问题和错误以及潜在的解决方案。

其他资源

讨论与错误相关的主题的其他部分包括:

B.1错误消息源和组件

本节讨论错误消息如何在MySQL及其包含的组件中生成。

错误消息源

错误消息可以源自服务器端或客户端:

  • 在服务器端,由于SQL语句执行期间发生的问题等原因,在启动和关闭过程中可能会出现错误消息。

    • MySQL服务器将一些错误消息写入其错误日志。 这些表示数据库管理员感兴趣的问题或需要DBA操作的问题。

    • 服务器将其他错误消息发送到客户端程序。 这些表明仅与特定客户有关的问题。 MySQL客户端库接收从服务器收到的错误,并使它们可用于主机客户端程序。

  • 客户端错误消息是从MySQL客户端库中生成的,通常涉及与服务器通信的问题。

写入错误日志的服务器端错误消息示例:

  • 在启动过程中生成的此消息提供状态或进度指示器:

    2018-10-28T13:01:32.735983Z 0 [注意] [MY-010303] [服务器]跳过
    生成SSL证书作为与SSL相关的选项。
    
  • 此消息表示需要DBA操作的问题:

    2018-10-02T03:20:39.410387Z 768 [错误] [MY-010045] [服务器]事件调度程序:
    [evtuser @ localhost] [myschema.e_daily]未知数据库'mydb'
    

发送到客户端程序的服务器端错误消息示例,如 mysql 客户端所示:

MySQL的> SELECT * FROM no_such_table;
ERROR 1146(42S02):表'test.no_such_table'不存在

源自客户端库的客户端错误消息示例,由 mysql 客户端 显示 :

外壳> mysql -h no-such-host
ERROR 2005(HY000):未知的MySQL服务器主机'no-such-host'(0)

无论错误源自客户端库还是从服务器接收,MySQL客户端程序都可能以不同方式响应。 如图所示,客户端可以显示错误消息,以便用户可以采取纠正措施。 客户端可以在内部尝试解析或重试失败的操作,或采取其他操作。

错误消息组件

发生错误时,错误信息包括几个组件:错误代码,SQLSTATE值和消息字符串。 这些组件具有以下特征:

  • 错误代码:此值为数字。 它是特定于MySQL的,不能移植到其他数据库系统。

    每个错误号都有一个相应的符号值。 例子:

    错误消息中使用的错误代码集被划分为不同的范围; 请参阅 错误代码范围 。

    错误代码在给定MySQL系列的通用可用性(GA)版本中是稳定的。 在系列达到GA状态之前,新代码可能仍处于开发阶段,可能会发生变化。

  • SQLSTATE值:此值是五个字符的字符串(例如, '42S02' )。 SQLSTATE值取自ANSI SQL和ODBC,并且比数字错误代码更标准化。 SQLSTATE值的前两个字符表示错误类:

    • Class = '00' 表示成功。

    • Class = '01' 表示警告。

    • Class = '02' 表示 “ 未找到。 “ 这在游标的上下文中是相关的,用于控制当光标到达数据集末尾时发生的情况。 对于 不检索任何行的语句, 也会出现这种情况 。 SELECT ... INTO var_list

    • Class> '02' 表示异常。

    对于服务器端错误,并非所有MySQL错误号都具有相应的SQLSTATE值。 在这些情况下,使用 'HY000' (一般错误)。

    对于客户端错误,SQLSTATE值始终是 'HY000' (一般错误),因此将一个客户端错误与另一个错误区分开来没有意义。

  • 消息字符串:此字符串提供错误的文本描述。

错误代码范围

错误消息中使用的错误代码集被划分为不同的范围,每个范围都有其自己的用途:

  • 1到999:全局错误代码。 此错误代码范围称为 “ 全局 ”, 因为它是服务器以及客户端使用的共享范围。

    当此范围内的错误源自服务器端时,服务器将其写入错误日志,将错误代码填充为前导零到六位数并添加前缀 MY- 。

    当此范围中的错误源自客户端时,客户端库使其可用于客户端程序而没有零填充或前缀。

  • 1,000到1,999:为发送到客户端的消息保留的服务器错误代码。

  • 2,000到2,999:客户端错误代码保留供客户端库使用。

  • 3,000到4,999:为发送到客户端的消息保留的服务器错误代码。

  • 5,000到5,999:X Plugin为发送给客户端的消息保留的错误代码。

  • 10,000到49,999:为要写入错误日志的消息(未发送到客户端)保留的服务器错误代码。

    当发生此范围内的错误时,服务器将其写入错误日志,将错误代码填充为前导零到六位数并添加前缀 MY- 。

  • 50,000到51,999:保留供第三方使用的错误代码。

服务器处理写入错误日志的错误消息与发送给客户端的错误消息不同:

  • 当服务器将消息写入错误日志时,它会将错误代码填入前导零到六位数,并添加前缀 MY- (例如: MY-000022 , MY-010048 )。

  • 当服务器向客户端程序发送消息时,它不会向错误代码添加零填充或前缀(例如: 1036 , 3013 )。

B.2错误信息接口

错误消息可以源自服务器端或客户端,每条错误消息都包含错误代码,SQLSTATE值和消息字符串,如 第B.1节“错误消息源和组件”中所述 。 有关服务器端,客户端和全局(服务器和客户端之间共享)错误的列表,请参见 第B.3节“错误消息参考” 。

对于程序内的错误检查,请使用错误代码编号或符号,而不是错误消息字符串。 消息字符串不会经常更改,但它是可能的。 此外,如果数据库管理员更改了语言设置,则会影响消息字符串的语言; 请参见 第10.11节“设置错误消息语言” 。

MySQL中的错误信息可在服务器错误日志,SQL级别,客户端程序和命令行中找到。

错误日志

在服务器端,某些消息用于错误日志。 有关配置服务器写入日志的位置和方式的信息,请参见 第5.4.2节“错误日志” 。

其他服务器错误消息旨在发送到客户端程序,并且可以按 客户端错误消息接口中的 描述获得 。

特定错误代码所在的范围决定了服务器是将错误消息写入错误日志还是将其发送给客户端。 有关这些范围的信息,请参阅 错误代码范围 。

SQL错误消息接口

在SQL级别,MySQL中有几个错误信息源:

客户端错误消息接口

客户端程序从两个来源收到错误:

  • 从MySQL客户端库中发起的客户端错误。

  • 源自服务器端并由服务器发送到客户端的错误。 这些是在客户端库中接收的,这使它们可用于主机客户端程序。

特定错误代码所在的范围确定它是源自客户端库还是客户端从服务器接收。 有关这些范围的信息,请参阅 错误代码范围 。

无论错误是来自客户端库还是从服务器接收,MySQL客户端程序通过调用客户端库中的C API函数来获取错误代码,SQLSTATE值,消息字符串和其他相关信息:

有关客户端库错误函数的描述,请参见 第28.7节“MySQL C API” 。

MySQL客户端程序可以以不同方式响应错误。 客户端可能会显示错误消息,以便用户可以采取纠正措施,在内部尝试解决或重试失败的操作,或采取其他操作。 例如,(使用 mysql 客户端),连接到服务器失败可能会导致此消息:

外壳> mysql -h no-such-host
ERROR 2005(HY000):未知的MySQL服务器主机'no-such-host'(0)

命令行错误消息接口

该 PERROR 程序提供从约错误号命令行信息。 请参见 第4.8.2节“ perror - 显示MySQL错误消息信息” 。

外壳> perror 1231
MySQL错误代码MY-001231(ER_WRONG_VALUE_FOR_VAR):变量'% -  .64s'
不能设置为'% - 。200s'的值

对于MySQL NDB Cluster错误,请使用 ndb_perror 。 请参见 第22.4.16节“ ndb_perror - 获取NDB错误消息信息” 。

外壳> ndb_perror 323
NDB错误代码323:节点组ID无效,节点组已存在:
永久错误:应用程序错误

B.3错误消息参考

本节提供MySQL中各种类型的错误消息的参考:

B.3.1服务器错误消息参考

MySQL服务器将一些错误消息写入其错误日志,并将其他错误消息发送到客户端程序。

写入错误日志的服务器端错误消息示例:

2018-10-28T13:01:32.735983Z 0 [注意] [MY-010303] [服务器]跳过
生成SSL证书作为与SSL相关的选项。

2018-10-02T03:20:39.410387Z 768 [错误] [MY-010045] [服务器]事件调度程序:
[evtuser @ localhost] [myschema.e_daily]未知数据库'mydb'

发送到客户端程序的服务器端错误消息示例,如 mysql 客户端所示:

MySQL的> SELECT * FROM no_such_table;
ERROR 1146(42S02):表'test.no_such_table'不存在

每个服务器错误消息都包含错误代码,SQLSTATE值和消息字符串,如 第B.1节“错误消息源和组件”中所述 。 这些组件可用于 第B.2节“错误信息接口”中所述 。

除了以下列表中的错误外,服务器还可以生成错误代码范围为1到999的 错误消息。 请参见 第B.3.3节“全局错误消息参考”

B.3.2客户端错误消息参考

客户端错误消息源自MySQL客户端库。 这是一个示例客户端错误消息,由 mysql 客户端 显示 :

外壳> mysql -h no-such-host
ERROR 2005(HY000):未知的MySQL服务器主机'no-such-host'(0)

每个客户端错误消息都包含错误代码,SQLSTATE值和消息字符串,如 第B.1节“错误消息源和组件”中所述 。 这些组件可用于 第B.2节“错误信息接口”中所述 。 对于客户端错误,SQLSTATE值始终为 'HY000' (一般错误),因此将一个客户端错误与另一个错误区分开来没有意义。

客户端库还可以向客户端程序提供源自服务器端的任何错误,并由客户端从服务器接收。 有关服务器端错误的列表,请参见 第B.3.1节“服务器错误消息参考” 。

除了以下列表中的错误之外,客户端库还可以生成错误代码范围为1到999的 错误消息。 请参见 第B.3.3节“全局错误消息参考”

  • 错误号码: 2000 ; 符号: CR_UNKNOWN_ERROR ;

    消息:未知的MySQL错误

  • 错误号码: 2001 ; 符号: CR_SOCKET_CREATE_ERROR ;

    消息:无法创建UNIX套接字(%d)

  • 错误号码: 2002 ; 符号: CR_CONNECTION_ERROR ;

    消息:无法通过套接字'%s'连接到本地MySQL服务器(%d)

  • 错误号码: 2003 ; 符号: CR_CONN_HOST_ERROR ;

    消息:无法连接到'%s'上的MySQL服务器(%d)

  • 错误号码: 2004 ; 符号: CR_IPSOCK_ERROR ;

    消息:无法创建TCP / IP套接字(%d)

  • 错误号码: 2005 ; 符号: CR_UNKNOWN_HOST ;

    消息:未知的MySQL服务器主机'%s'(%d)

  • 错误号码: 2006 ; 符号: CR_SERVER_GONE_ERROR ;

    消息:MySQL服务器已经消失

  • 错误号码: 2007 ; 符号: CR_VERSION_ERROR ;

    消息:协议不匹配; 服务器版本=%d,客户端版本=%d

  • 错误号码: 2008 ; 符号: CR_OUT_OF_MEMORY ;

    消息:MySQL客户端内存不足

  • 错误号码: 2009 ; 符号: CR_WRONG_HOST_INFO ;

    消息:主机信息错误

  • 错误号码: 2010 ; 符号: CR_LOCALHOST_CONNECTION ;

    消息:通过UNIX套接字的Localhost

  • 错误号码: 2011 ; 符号: CR_TCP_CONNECTION ;

    消息:%s通过TCP / IP

  • 错误号码: 2012 ; 符号: CR_SERVER_HANDSHAKE_ERR ;

    消息:服务器握手错误

  • 错误号码: 2013 ; 符号: CR_SERVER_LOST ;

    消息:查询期间与MySQL服务器的连接丢失

  • 错误号码: 2014 ; 符号: CR_COMMANDS_OUT_OF_SYNC ;

    消息:命令不同步; 你现在不能运行这个命令

    命令以不正确的顺序执行。 调用不适合当前连接状态的函数时会发生此错误。 例如,如果 mysql_stmt_fetch() 未调用足够的时间来读取整个结果集(即返回的时间足够多 MYSQL_NO_DATA ),则以下C API调用可能会发生此错误。

  • 错误号码: 2015 ; 符号: CR_NAMEDPIPE_CONNECTION ;

    消息:命名管道:%s

  • 错误号码: 2016 ; 符号: CR_NAMEDPIPEWAIT_ERROR ;

    消息:不能等待命名管道到主机:%s管道:%s(%lu)

  • 错误号码: 2017 ; 符号: CR_NAMEDPIPEOPEN_ERROR ;

    消息:无法打开命名管道到主机:%s管道:%s(%lu)

  • 错误号码: 2018 ; 符号: CR_NAMEDPIPESETSTATE_ERROR ;

    消息:无法将命名管道的状态设置为主机:%s管道:%s(%lu)

  • 错误号码: 2019 ; 符号: CR_CANT_READ_CHARSET ;

    消息:无法初始化字符集%s(路径:%s)

  • 错误号码: 2020 ; 符号: CR_NET_PACKET_TOO_LARGE ;

    消息:得到的数据包大于'max_allowed_pa​​cket'字节

  • 错误号码: 2021 ; 符号: CR_EMBEDDED_CONNECTION ;

    消息:嵌入式服务器

  • 错误号码: 2022 ; 符号: CR_PROBE_SLAVE_STATUS ;

    消息:SHOW SLAVE STATUS出错:

  • 错误号码: 2023 ; 符号: CR_PROBE_SLAVE_HOSTS ;

    消息:显示SHOW SLAVE HOSTS时出错:

  • 错误号码: 2024 ; 符号: CR_PROBE_SLAVE_CONNECT ;

    消息:连接到从站时出错:

  • 错误号码: 2025 ; 符号: CR_PROBE_MASTER_CONNECT ;

    消息:连接到master时出错:

  • 错误号码: 2026 ; 符号: CR_SSL_CONNECTION_ERROR ;

    消息:SSL连接错误:%s

  • 错误号码: 2027 ; 符号: CR_MALFORMED_PACKET ;

    消息:格式错误的数据包

  • 错误号码: 2028 ; 符号: CR_WRONG_LICENSE ;

    消息:此客户端库仅许可用于具有'%s'许可证的MySQL服务器

  • 错误号码: 2029 ; 符号: CR_NULL_POINTER ;

    消息:无效使用空指针

  • 错误号码: 2030 ; 符号: CR_NO_PREPARE_STMT ;

    消息:声明未准备好

  • 错误号码: 2031 ; 符号: CR_PARAMS_NOT_BOUND ;

    消息:没有为预准备语句中的参数提供数据

  • 错误号码: 2032 ; 符号: CR_DATA_TRUNCATED ;

    消息:数据被截断

  • 错误号码: 2033 ; 符号: CR_NO_PARAMETERS_EXISTS ;

    消息:语句中不存在任何参数

  • 错误号码: 2034 ; 符号: CR_INVALID_PARAMETER_NO ;

    消息:参数号无效

    列号 mysql_stmt_fetch_column() 无效。

    参数号 mysql_stmt_send_long_data() 无效。

    密钥名称为空或连接属性数据的数量 mysql_options4() 超过64KB限制。

  • 错误号码: 2035 ; 符号: CR_INVALID_BUFFER_USE ;

    消息:无法为非字符串/非二进制数据类型发送长数据(参数:%d)

  • 错误号码: 2036 ; 符号: CR_UNSUPPORTED_PARAM_TYPE ;

    消息:使用不支持的缓冲区类型:%d(参数:%d)

  • 错误号码: 2037 ; 符号: CR_SHARED_MEMORY_CONNECTION ;

    消息:共享内存:%s

  • 错误号码: 2038 ; 符号: CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR ;

    消息:无法打开共享内存; 客户端无法创建请求事件(%lu)

  • 错误号码: 2039 ; 符号: CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR ;

    消息:无法打开共享内存; 从服务器收到无应答事件(%lu)

  • 错误号码: 2040 ; 符号: CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR ;

    消息:无法打开共享内存; 服务器无法分配文件映射(%lu)

  • 错误号码: 2041 ; 符号: CR_SHARED_MEMORY_CONNECT_MAP_ERROR ;

    消息:无法打开共享内存; 服务器无法获取指向文件映射的指针(%lu)

  • 错误号码: 2042 ; 符号: CR_SHARED_MEMORY_FILE_MAP_ERROR ;

    消息:无法打开共享内存; 客户端无法分配文件映射(%lu)

  • 错误号码: 2043 ; 符号: CR_SHARED_MEMORY_MAP_ERROR ;

    消息:无法打开共享内存; 客户端无法获取指向文件映射的指针(%lu)

  • 错误号码: 2044 ; 符号: CR_SHARED_MEMORY_EVENT_ERROR ;

    消息:无法打开共享内存; 客户端无法创建%s事件(%lu)

  • 错误号码: 2045 ; 符号: CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR ;

    消息:无法打开共享内存; 没有来自服务器的回答(%lu)

  • 错误号码: 2046 ; 符号: CR_SHARED_MEMORY_CONNECT_SET_ERROR ;

    消息:无法打开共享内存; 无法向服务器发送请求事件(%lu)

  • 错误号码: 2047 ; 符号: CR_CONN_UNKNOW_PROTOCOL ;

    消息:错误或未知的协议

  • 错误号码: 2048 ; 符号: CR_INVALID_CONN_HANDLE ;

    消息:无效的连接句柄

  • 错误号码: 2049 ; 符号: CR_UNUSED_1 ;

    消息:拒绝使用旧(4.1.1之前)身份验证协议的连接(启用客户端选项'secure_auth')

  • 错误号码: 2050 ; 符号: CR_FETCH_CANCELED ;

    消息:mysql_stmt_close()调用取消了行检索

  • 错误号码: 2051 ; 符号: CR_NO_DATA ;

    消息:尝试在没有先前行提取的情况下读取列

  • 错误号码: 2052 ; 符号: CR_NO_STMT_METADATA ;

    消息:Prepared语句不包含元数据

  • 错误号码: 2053 ; 符号: CR_NO_RESULT_SET ;

    消息:在没有与语句关联的结果集时尝试读取行

  • 错误号码: 2054 ; 符号: CR_NOT_IMPLEMENTED ;

    消息:此功能尚未实现

  • 错误号码: 2055 ; 符号: CR_SERVER_LOST_EXTENDED ;

    消息:'%s'与MySQL服务器的连接丢失,系统错误:%d

  • 错误号码: 2056 ; 符号: CR_STMT_CLOSED ;

    消息:语句因前面的%s()调用而间接关闭

  • 错误号码: 2057 ; 符号: CR_NEW_STMT_METADATA ;

    消息:结果集中的列数与绑定缓冲区的数量不同。 您必须重置语句,重新绑定结果集列,然后再次执行该语句

  • 错误号码: 2058 ; 符号: CR_ALREADY_CONNECTED ;

    消息:此句柄已连接。 为每个连接使用单独的句柄。

  • 错误号码: 2059 ; 符号: CR_AUTH_PLUGIN_CANNOT_LOAD ;

    消息:无法加载身份验证插件'%s':%s

  • 错误号码: 2060 ; 符号: CR_DUPLICATE_CONNECTION_ATTR ;

    消息:已存在具有相同名称的属性

    为其指定了重复的连接属性名称 mysql_options4() 。

  • 错误号码: 2061 ; 符号: CR_AUTH_PLUGIN_ERR ;

    消息:身份验证插件'%s'报告错误:%s

  • 错误号码: 2062 ; 符号: CR_INSECURE_API_ERR ;

    消息:不安全的API函数调用:'%s'代替使用:'%s'

    检测到不安全的函数调用。 修改应用程序以使用建议的替代功能。

  • 错误号码: 2063 ; 符号: CR_FILE_NAME_TOO_LONG ;

    消息:文件名太长

    CR_FILE_NAME_TOO_LONG 在8.0.1中添加。

  • 错误号码: 2064 ; 符号: CR_SSL_FIPS_MODE_ERR ;

    消息:将FIPS模式设置为ON / STRICT失败

    CR_SSL_FIPS_MODE_ERR 在8.0.11中添加。

  • 错误号码: 2065 ; 符号: CR_COMPRESSION_NOT_SUPPORTED ;

    消息:异步协议不支持压缩协议

    CR_COMPRESSION_NOT_SUPPORTED 在8.0.16中添加。

B.3.3全局错误消息参考

本节列出 “ 全球 ” 错误消息,它们可以由MySQL服务器或MySQL客户端程序生成。 这些错误的错误代码范围为1到999。

每个全局错误消息都包含错误代码,SQLSTATE值和消息字符串,如 第B.1节“错误消息源和组件”中所述 。 这些组件可用于 第B.2节“错误信息接口”中所述 。 对于全局错误,SQLSTATE值始终是 'HY000' (一般错误),因此将一个客户端错误与另一个错误区分开来没有意义。

如果服务器将消息写入具有全局错误代码的错误日志,则会将错误代码填入前导零到六位数并添加前缀 MY- (示例 :) MY-000022 。 以下列表以该格式显示错误代码。

如果客户端返回带有全局错误代码的消息,则它不会向错误代码添加零填充或前缀。

B.4问题和常见错误

本节列出了您可能遇到的一些常见问题和错误消息。 它描述了如何确定问题的原因以及解决问题的方法。

B.4.1如何确定导致问题的原因

当您遇到问题时,您应该做的第一件事是找出导致它的设备或设备:

  • 如果您有以下症状之一,那么它可能是硬件问题(如内存,主板,CPU或硬盘)或内核问题:

    • 键盘不起作用。 通常可以通过按Caps Lock键来检查。 如果Caps Lock指示灯未更改,则必须更换键盘。 (在此之前,您应该尝试重新启动计算机并检查键盘的所有电缆。)

    • 鼠标指针不移动。

    • 机器无法应答远程机器的ping。

    • 与MySQL无关的其他程序行为不正确。

    • 您的系统意外重启。 (错误的用户级程序永远不能取消您的系统。)

    在这种情况下,您应该首先检查所有电缆并运行一些诊断工具来检查您的硬件! 您还应该检查操作系统是否有任何可能解决问题的修补程序,更新或Service Pack。 还要检查所有库(例如 glibc )是否是最新的。

    使用具有ECC内存的机器来提前发现内存问题总是好的。

  • 如果键盘已锁定,则可以通过从另一台计算机登录计算机并执行来恢复 kbd_mode -a 。

  • 请检查您的系统日志文件( /var/log/messages 或类似 文件 ),以了解您的问题。 如果您认为问题出在MySQL中,您还应该检查MySQL的日志文件。 请参见 第5.4节“MySQL服务器日志” 。

  • 如果您认为自己没有硬件问题,则应该尝试找出导致问题的程序。 尝试使用 top , ps ,任务管理器或某些类似的程序来检查哪个程序正在占用所有CPU或正在锁定机器。

  • 使用 top , df 或类似程序检查是否内存不足,磁盘空间,文件描述符或其他一些关键资源。

  • 如果问题是一些失控的过程,你总是可以尝试杀死它。 如果它不想死,则操作系统中可能存在错误。

如果在检查了所有其他可能性并且您得出结论MySQL服务器或MySQL客户端导致问题之后,是时候为我们的邮件列表或我们的支持团队创建错误报告了。 在错误报告中,尝试详细描述系统的行为方式以及您的想法。 您还应该说明为什么您认为MySQL导致了问题。 考虑本章中的所有情况。 在检查系统时,准确说明它们出现的确切问题。 对 程序和日志文件中的任何输出和错误消息 使用 “ 复制和粘贴 ” 方法。

尝试详细描述哪个程序不起作用以及您看到的所有症状。 我们过去收到过很多错误报告,只说 “ 系统不起作用。 “ 这没有为我们提供有关可能出现问题的信息。

如果程序失败,了解以下信息总是有用的:

  • 有问题的程序是否出现了分段错误(它是否转储核心)?

  • 程序是否占用了所有可用的CPU时间? 检查 顶部 。 让程序运行一段时间,它可能只是评估一些计算密集的东西。

  • 如果 mysqld 服务器导致问题,你可以使用 mysqladmin -u root ping 或 mysqladmin -u root processlist 获得任何响应 吗?

  • 当您尝试连接到MySQL服务器时,客户端程序会说什么? ( 例如, 尝试使用 mysql 。)客户端是否堵塞? 你从程序中得到任何输出吗?

发送错误报告时,应遵循 第1.7节“如何报告错误或问题”中 所述的大纲 。

B.4.2使用MySQL程序时的常见错误

本节列出了用户在运行MySQL程序时经常遇到的一些错误。 虽然当您尝试运行客户端程序时会出现问题,但许多问题的解决方案都涉及更改MySQL服务器的配置。

B.4.2.1访问被拒绝

一个 Access denied 错误可以有许多原因。 通常问题与服务器允许客户端程序在连接时使用的MySQL帐户有关。 请参见 第6.2节“访问控制和帐户管理” 和 第6.2.21节“连接到MySQL的问题疑难解答” 。

B.4.2.2无法连接到[本地] MySQL服务器

Unix上的MySQL客户端可以 通过两种不同的方式 连接到 mysqld 服务器:使用Unix套接字文件通过文件系统中的文件(默认 /tmp/mysql.sock )连接,或者使用通过端口号连接的TCP / IP。 Unix套接字文件连接比TCP / IP快,但只能在连接到同一台计算机上的服务器时使用。 如果未指定主机名或指定特殊主机名,则使用Unix套接字文件 localhost 。

如果MySQL服务器在Windows上运行,则可以使用TCP / IP进行连接。 如果使用该 --enable-named-pipe 选项 启动服务器 ,则还可以在运行服务器的主机上运行客户端时连接命名管道。 MySQL 默认情况下 ,命名管道的名称 。 如果在连接到 mysqld 时没有给出主机名 ,MySQL客户端首先尝试连接到命名管道。 如果这不起作用,它将连接到TCP / IP端口。 您可以使用 . 主机名 强制在Windows上使用命名管道 。

错误(2002) Can't connect to ... 通常意味着系统上没有运行MySQL服务器,或者在尝试连接服务器时使用的是不正确的Unix套接字文件名或TCP / IP端口号。 您还应检查您使用的TCP / IP端口是否未被防火墙或端口阻止服务阻止。

错误(2003) 表示网络连接已被拒绝。 您应检查是否有MySQL服务器正在运行,是否已启用网络连接,以及您指定的网络端口是否是服务器上配置的网络端口。 Can't connect to MySQL server on 'server' (10061)

首先检查 服务器主机上 是否有 运行 名为 mysqld 的进程 。 ( 在Unix上 使用 ps xa | grep mysqld 或在Windows上使用任务管理器。)如果没有这样的进程,则应启动服务器。 请参见 第2.10.2节“启动服务器” 。

如果 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

注意使用 hostname 命令 使用反引号而不是正向引号 ; 这些导致 主机名 的输出 (即当前主机名)被替换为 mysqladmin 命令。 如果您没有 hostname 命令或在Windows上运行,则可以在该 -h 选项 后面手动键入计算机的主机名(不带反引号) 。 您还可以尝试 -h 127.0.0.1 使用TCP / IP连接到本地主机。

确保服务器尚未配置为忽略网络连接或(如果您尝试远程连接)尚未配置为仅在其网络接口上本地侦听。 如果服务器已启动 --skip-networking ,则根本不接受TCP / IP连接。 如果服务器是在 bind_address 系统变量设置为的情况 下启动的 127.0.0.1 ,则它将仅在环回接口上本地侦听TCP / IP连接,并且不接受远程连接。

检查以确保没有防火墙阻止访问MySQL。 可以根据正在执行的应用程序或MySQL用于通信的端口号(默认为3306)来配置防火墙。 在Linux或Unix下,检查IP表(或类似)配置以确保端口未被阻止。 在Windows下,可能需要配置ZoneAlarm或Windows防火墙等应用程序,以阻止MySQL端口。

以下是 Can't connect to local MySQL server 可能发生错误的 一些原因 :

  • mysqld 没有在本地主机上运行。 检查操作系统的进程列表以确保 mysqld 进程存在。

  • 您在Windows上运行MySQL服务器,并且有许多TCP / IP连接。 如果您经常遇到错误,那么您可以在此处找到解决方法: 第B.4.2.2.1节“连接MySQL服务器在Windows上失败” 。

  • 有人删除了 mysqld 使用 的Unix套接字文件 ( /tmp/mysql.sock 默认情况下)。 例如,您可能有一个 cron 作业从 /tmp 目录 中删除旧文件 。 你总是可以运行 mysqladmin版本 来检查 mysqladmin 试图使用 的Unix套接字文件是否 真的存在。 在这种情况下,修复是将 cron 作业 更改 为不删除 mysql.sock 或将套接字文件放在其他位置。 请参见 第B.4.3.6节“如何保护或更改MySQL Unix套接字文件” 。

  • 您已经 使用该 选项 启动了 mysqld 服务器 --socket=/path/to/socket ,但忘记告诉客户端程序套接字文件的新名称。 如果更改服务器的套接字路径名,则还必须通知MySQL客户端。 您可以通过 --socket 在运行客户端程序时 提供相同的 选项 来执行此操作 。 您还需要确保客户端有权访问该 mysql.sock 文件。 要找出套接字文件的位置,您可以执行以下操作:

    外壳> netstat -ln | grep mysql
    

    请参见 第B.4.3.6节“如何保护或更改MySQL Unix套接字文件” 。

  • 您正在使用Linux并且一个服务器线程已经死亡(转储核心)。 在这种情况下,您必须先杀死其他 mysqld 线程(例如,使用 kill ),然后才能重新启动MySQL服务器。 请参见 第B.4.3.3节“如果MySQL不断崩溃该怎么办” 。

  • 服务器或客户端程序可能没有对包含Unix套接字文件或套接字文件本身的目录的适当访问权限。 在这种情况下,您必须更改目录或套接字文件的访问权限,以便服务器和客户端可以访问它们,或者 使用 在服务器可以创建它的目录中指定套接字文件名 的 选项 重新启动 mysqld --socket 客户端程序可以访问它。

如果收到错误消息 Can't connect to MySQL server on some_host ,您可以尝试以下方法来找出问题所在:

  • 通过执行 telnet some_host 3306 并按几次Enter键 检查服务器是否在该主机上运行 。 (3306是默认的MySQL端口号。如果您的服务器正在侦听其他端口,请更改该值。)如果有MySQL服务器正在运行并正在侦听该端口,您应该得到一个包含服务器版本号的响应。 如果出现错误 telnet: Unable to connect to remote host: Connection refused ,则表示给定端口上没有服务器正在运行。

  • 如果服务器在本地主机上运行,​​请尝试使用 mysqladmin -h localhost变量 使用Unix套接字文件进行连接。 验证服务器配置为侦听的TCP / IP端口号(它是 port 变量 的值 。)

  • 如果您在Linux下运行并且启用了安全增强型Linux(SELinux),请确保已禁用该 mysqld 进程的 SELinux保护 。

B.4.2.2.1在Windows上连接MySQL服务器失败

当您在Windows上运行MySQL服务器并且有许多TCP / IP连接,并且您经常遇到客户端 Can't connect to MySQL server 出错时,原因可能是Windows不允许足够的短暂(短期)端口为这些连接提供服务。

目的 TIME_WAIT 是在连接关闭后保持连接接受数据包。 这是因为互联网路由可能导致数据包通往目的地的路径较慢,并且可能在双方同意关闭后到达。 如果端口正在用于新连接,则来自旧连接的该数据包可能会破坏协议或破坏原始连接中的个人信息。 该 TIME_WAIT 延迟防止这种通过确保端口不能到一些时间已经允许的数据包延迟到达后可重复使用。

TIME_WAIT 在LAN连接上大大 减少是安全的, 因为数据包很少有可能在很长的时间内到达,因为它们可以通过具有相对较大距离和延迟的因特网来实现。

Windows允许用户使用临时(短期)TCP端口。 任何端口关闭后,它将保持 TIME_WAIT 120秒 的 状态。 在此时间到期之前,该端口将无法再次使用。 默认的端口号范围取决于Windows的版本,旧版本中的端口数量有限:

  • Windows到Server 2003:端口范围为1025-5000

  • Windows Vista,Server 2008和更新版本:端口范围为49152-65535

通过一小堆可用的TCP端口(5000)和大量TCP端口在短时间内打开和关闭以及 TIME_WAIT 状态,您很有可能用完端口。 有两种方法可以解决此问题:

  • 通过尽可能调查连接池或持久连接,快速减少消耗的TCP端口数

  • 调整Windows注册表中的一些设置(见下文)

重要

以下过程涉及修改Windows注册表。 在修改注册表之前,请确保对其进行备份,并确保在发生问题时了解如何还原注册表。 有关如何备份,还原和编辑注册表的信息,请查看Microsoft知识库中的以下文章: http : //support.microsoft.com/kb/256986/EN-US/ 。

  1. 启动注册表编辑器( Regedt32.exe )。

  2. 在注册表中找到以下项:

    HKEY_LOCAL_MACHINE \系统\ CurrentControlSet \服务\ TCPIP \参数
    
  3. 在 Edit 菜单上,单击 Add Value ,然后添加以下注册表值:

    值名称:MaxUserPort
    数据类型:REG_DWORD
    价值:65534
    

    这设置了任何用户可用的临时端口数。 有效范围介于5000和65534之间(十进制)。 默认值为0x1388(十进制5000)。

  4. 在 Edit 菜单上,单击 Add Value ,然后添加以下注册表值:

    值名称:TcpTimedWaitDelay
    数据类型:REG_DWORD
    价值:30
    

    这将设置 TIME_WAIT 在关闭之前 保持TCP端口连接 状态 的秒数 。 有效范围在30到300之间,尽管您可能希望向Microsoft查询最新允许值。 默认值为0x78(十进制120)。

  5. 退出注册表编辑器。

  6. 重新启动机器。

注意:撤消上述内容应该与删除您创建的注册表项一样简单。

B.4.2.3与MySQL服务器的连接丢失

此错误消息可能有三种原因。

通常它表示网络连接故障,如果频繁发生此错误,您应该检查网络状况。 如果错误消息包含 “ 在查询期间 ”, 则可能是您遇到的情况。

有时, 当在一个或多个查询的一部分中发送数百万行时,会出现 “ 在查询期间 ” 表单。 如果您知道发生这种情况,则应尝试 net_read_timeout 从默认值30秒增加到60秒或更长时间,足以完成数据传输。

更少见的是,当客户端尝试与服务器的初始连接时,可能会发生这种情况。 在这种情况下,如果您的 connect_timeout 值设置为仅几秒钟,您可以通过将其增加到十秒来解决问题,如果您的距离很长或连接速度很慢,可能会更多。 您可以通过使用确定是否遇到这种更常见的原因 SHOW GLOBAL STATUS LIKE 'Aborted_connects' 。 对于服务器中止的每次初始连接尝试,它将增加1。 您可能会看到 “ 读取授权数据包 ” 作为错误消息的一部分; 如果是这样,那也表明这是您需要的解决方案。

如果原因不是刚刚描述的原因,则可能遇到 BLOB 大于值 的问题 max_allowed_packet ,这可能会导致某些客户端出现此错误。 有时您可能会看到 ER_NET_PACKET_TOO_LARGE 错误,并确认您需要增加 max_allowed_packet 。

B.4.2.4交互式输入时密码失败

当使用 没有以下密码值的选项 --password 或 -p 选项 调用时,MySQL客户端程序会提示输入 密码:

外壳> mysql -u user_name -p
输入密码:

在某些系统上,您可能会发现密码在选项文件或命令行中指定时有效,但在 Enter password: 提示 时以交互方式输入时却无效 。 当系统提供的用于读取密码的库将密码值限制为少量字符(通常为八个)时,会发生这种情况。 这是系统库的问题,而不是MySQL。 要解决此问题,请将MySQL密码更改为八个或更少字符长的值,或将密码放在选项文件中。

B.4.2.5主机'host_name'被阻止

如果发生以下错误,则表示 mysqld 已收到来自给定主机的中间中断的许多连接请求:

主持人'host_name由于许多连接错误, '被阻止。
使用'mysqladmin flush-hosts'取消阻止

max_connect_errors 系统变量 的值 确定允许的连续中断连接请求的数量。 在 max_connect_errors 没有成功连接的请求失败 之后 , mysqld 假定出现了问题(例如,有人试图闯入),并阻止主机进一步连接,直到您通过执行 FLUSH HOSTS 语句 来清除主机缓存 ,该 TRUNCATE TABLE 语句将截断性能架构 host_cache 表或 mysqladmin flush-hosts 命令。

要调整允许的连续连接错误数,请 max_connect_errors 在服务器启动时 设置 。 例如,将这些行放在服务器 my.cnf 文件中:

的[mysqld]
max_connect_errors次= 10000

该值也可以在运行时设置:

SET GLOBAL max_connect_errors = 10000;

如果收到 给定主机 的 错误消息,则应首先验证该主机的TCP / IP连接是否有任何问题。 如果您遇到网络问题,那么增加值就没有用了 。 Host 'host_name' is blocked max_connect_errors

有关主机缓存如何工作的更多信息,请参见 第8.12.4.2节“DNS查找优化和主机缓存” 。

B.4.2.6连接太多

如果客户端 Too many connections 在尝试连接到 mysqld 服务器 时 遇到 错误 ,则其他客户 端正 在使用所有可用连接。

允许的连接数由 max_connections 系统变量 控制 。 当MySQL与Apache Web服务器一起使用时,默认值为151以提高性能。 要支持更多连接,请设置 max_connections 为更大的值。

mysqld 实际上允许 max_connections + 1个客户端连接。 额外连接保留供具有 CONNECTION_ADMIN 或 SUPER 特权的 帐户使用 。 通过向管理员而不是普通用户(不应该使用它)授予权限,管理员可以连接到服务器并用于 SHOW PROCESSLIST 诊断问题,即使连接了最大数量的非特权客户端也是如此。 请参见 第13.7.6.29节“SHOW PROCESSLIST语法” 。

服务器还允许在专用接口上进行管理连接。 有关服务器如何处理客户端连接的更多信息,请参见 第8.12.4.1节“MySQL如何处理客户端连接” 。

B.4.2.7内存不足

如果使用 mysql 客户端程序 发出查询 并收到类似下面的错误,则表示 mysql 没有足够的内存来存储整个查询结果:

mysql:第42行的内存不足,'malloc.c'
mysql:需要8136字节(8k),正在使用的内存:12481367字节(12189k)
ERROR 2008:MySQL客户端内存不足

要解决此问题,请先检查您的查询是否正确。 应该返回这么多行是否合理? 如果没有,请更正查询并再试一次。 否则,您可以 使用该 选项 调用 mysql --quick 。 这导致它使用 mysql_use_result() C API函数来检索结果集,这会减少客户端上的负载(但更多的是在服务器上)。

B.4.2.8 MySQL服务器已经消失

本节还介绍了相关的 Lost connection to server during query 错误。

导致 MySQL server has gone away 错误 的最常见原因 是服务器超时并关闭连接。 在这种情况下,您通常会得到以下错误代码之一(您获得的错误代码与操作系统有关)。

错误代码 描述
CR_SERVER_GONE_ERROR 客户端无法向服务器发送问题。
CR_SERVER_LOST 写入服务器时客户端没有收到错误,但是没有得到问题的完整答案(或任何答案)。

默认情况下,如果没有发生任何事情,服务器会在八小时后关闭连接。 您可以通过 wait_timeout 在启动 mysqld 时 设置 变量 来更改时间限制 。 请参见 第5.1.8节“服务器系统变量” 。

如果您有脚本,则只需再次发出查询,客户端就可以自动重新连接。 这假设您在启用的客户端中具有自动重新连接(这是 mysql 命令行客户端 的默认设置 )。

此 MySQL server has gone away 错误的 其他一些常见原因 是:

  • 您(或数据库管理员)已使用 KILL 语句或 mysqladmin kill 命令 终止 正在运行的线程 。

  • 您尝试在关闭与服务器的连接后运行查询。 这表示应该更正的应用程序中的逻辑错误。

  • 在不同主机上运行的客户端应用程序没有从该主机连接到MySQL服务器的必要权限。

  • 您从客户端的TCP / IP连接获得超时。 如果您一直在使用命令,则可能会发生这种情况: mysql_options(..., MYSQL_OPT_READ_TIMEOUT,...) 或 mysql_options(..., MYSQL_OPT_WRITE_TIMEOUT,...) 。 在这种情况下,增加超时可能有助于解决问题。

  • 您在服务器端遇到超时,并且禁用了客户端中的自动重新连接( 结构中 的 reconnect 标志 MYSQL 等于0)。

  • 您正在使用Windows客户端,并且在 wait_timeout 发出命令之前 服务器已断开连接(可能是因为 已过期)。

    Windows上的问题是,在某些情况下,MySQL在写入到服务器的TCP / IP连接时不会从操作系统中收到错误,而是在尝试从连接中读取答案时收到错误。

    对此的解决方案是, mysql_ping() 如果自上次查询以来已经存在很长时间(这是Connector / ODBC所做的)或者 wait_timeout 在 mysqld 服务器 上 设置得 如此之高以至于它在实践中永远不会超时,那么 要么 对 连接执行 操作。

  • 如果向服务器发送不正确或太大的查询,也可能会出现这些错误。 如果 mysqld 收到的数据包太大或无序,则会假定客户端出现问题并关闭连接。 如果需要大查询(例如,如果使用大 BLOB 列),则可以通过设置服务器的 max_allowed_packet 变量 来增加查询限制,该 变量的默认值为64MB。 您可能还需要增加客户端的最大数据包大小。 有关设置数据包大小的更多信息,请参见 第B.4.2.9节“数据包太大” 。

    一个 INSERT 或者 REPLACE 是插入大量行的声明也可能引起这些类型的错误。 这些语句中的任何一个都向服务器发送单个请求,而不管要插入的行数是多少; 因此,您通常可以通过减少每个 INSERT 或 每个发送的行数来避免错误 REPLACE 。

  • 如果主机名查找失败(例如,如果您的服务器或网络所依赖的DNS服务器发生故障),也可能会看到此错误。 这是因为MySQL依赖于主机系统进行名称解析,但无法知道它是否正常工作 - 从MySQL的角度来看,问题与任何其他网络超时无法区分。

    MySQL server has gone away 如果使用该 --skip-networking 选项 启动MySQL, 您可能还会看到 错误 。

    如果MySQL端口(默认3306)被防火墙阻止,则可能导致此错误的另一个网络问题,从而阻止任何连接到MySQL服务器。

  • 您还可以在分叉子进程的应用程序中遇到此错误,所有这些应用程序都尝试使用与MySQL服务器相同的连接。 通过为每个子进程使用单独的连接可以避免这种情况。

  • 您遇到了执行查询时服务器死机的错误。

您可以通过执行 mysqladmin版本 并检查服务器的正常运行时间 来检查MySQL服务器是否已死亡并重新启动 。 如果因为 mysqld 崩溃并重新启动 而导致客户端连接中断 ,则应集中精力查找崩溃的原因。 首先检查是否再次发出查询会再次杀死服务器。 请参见 第B.4.3.3节“如果MySQL不断崩溃该怎么办” 。

您可以通过启动 mysqld 并将 log_error_verbosity 系统变量设置为3 来获取有关丢失连接的更多信息 。这会记录文件中的一些断开连接消息 hostname.err 。 请参见 第5.4.2节“错误日志” 。

如果要创建有关此问题的错误报告,请确保包含以下信息:

另请参见 第B.4.2.10节“通信错误和中止的连接” 和 第1.7节“如何报告错误或问题” 。

B.4.2.9数据包太大

通信数据包是发送到MySQL服务器的单个SQL语句,发送到客户端的单个行,或从主复制服务器发送到从属服务器的二进制日志事件。

可以传输到MySQL 8.0服务器或客户端的最大可能数据包是1GB。

当MySQL客户端或 mysqld 服务器收到大于 max_allowed_packet 字节 的数据包时 ,它会发出 ER_NET_PACKET_TOO_LARGE 错误并关闭连接。 对于某些客户端, Lost connection to MySQL server during query 如果通信包太大 ,您也可能会收到 错误。

客户端和服务器都有自己的 max_allowed_packet 变量,因此如果要处理大数据包,则必须在客户端和服务器中增加此变量。

如果您使用的是 mysql 客户端程序,则其默认 max_allowed_packet 变量为16MB。 要设置更大的值,请启动 mysql, 如下所示:

外壳> mysql --max_allowed_packet=32M

这将数据包大小设置为32MB。

服务器的默认 max_allowed_packet 值为64MB。 如果服务器需要处理大查询(例如,如果您正在使用大 BLOB 列) ,则可以增加此值 。 例如,要将变量设置为128MB,请按以下方式启动服务器:

外壳> mysqld --max_allowed_packet=128M

您还可以使用选项文件进行设置 max_allowed_packet 。 例如,要将服务器的大小设置为128MB,请在选项文件中添加以下行:

的[mysqld]
max_allowed_pa​​cket的= 128M

增加此变量的值是安全的,因为仅在需要时才分配额外的内存。 例如, mysqld 仅在发出长查询或 mysqld 必须返回大结果行 时才分配更多内存 。 变量的小默认值是在客户端和服务器之间捕获不正确的数据包的预防措施,并且还要确保您不会意外地使用大型数据包而耗尽内存。

如果您使用较大的 BLOB 值但是没有给 mysqld 访问足够的内存来处理查询, 那么您也可能会遇到大数据包的奇怪问题 。 如果您怀疑是这种情况,请尝试将 ulimit -d 256000 添加 到 mysqld_safe 脚本 的开头 并重新启动 mysqld 。

B.4.2.10通信错误和中止的连接

如果出现连接问题(例如通信错误或连接中止),请使用这些信息源来诊断问题:

如果 log_error_verbosity 系统变量设置为3,您可能会在错误日志中找到如下消息:

[注意]中止连接854到db:'employees'用户:'josh'

如果客户端甚至无法连接,则服务器会递增 Aborted_connects 状态变量。 由于以下原因,可能会发生不成功的连接尝试:

如果发生这些事情,可能表明有人试图闯入您的服务器! 如果启用了常规查询日志,则会记录针对这些类型的问题的消息。

如果客户端成功连接但稍后未正确断开连接或终止,则服务器会递增 Aborted_clients 状态变量,并将 中止的连接 消息记录到错误日志中。 原因可能是以下任何一种情况:

连接中止或客户端中止问题的其他原因:

  • 该 max_allowed_packet 变量的值太小或查询需要比你分配更多的内存 的mysqld 。 请参见 第B.4.2.9节“数据包太大” 。

  • 在Linux上使用以太网协议,包括半双工和全双工。 一些Linux以太网驱动程序有这个bug。 您应该通过在客户端和服务器计算机之间使用FTP传输大文件来测试此错误。 如果传输进入突发 - 暂停 - 突发 - 暂停模式,则表示您正在遇到Linux双工综合症。 将网卡和集线器/交换机的双工模式切换为全双工或半双工,并测试结果以确定最佳设置。

  • 线程库导致读取中断的问题。

  • 配置错误的TCP / IP。

  • 有故障的以太网,集线器,交换机,电缆等。 只有更换硬件才能正确诊断。

另见 第B.4.2.8节“MySQL服务器已经消失” 。

B.4.2.11表格已满

如果发生表满错误,则可能是磁盘已满或表已达到其最大大小。 MySQL数据库的有效最大表大小通常由操作系统对文件大小的约束决定,而不是由MySQL内部限制决定。 请参见 第C.10.3节“表大小限制” 。

B.4.2.12无法创建/写入文件

如果某些查询出现以下类型的错误,则表示MySQL无法为临时目录中的结果集创建临时文件:

无法创建/写入文件'\\ sqla3fe_0.ism'。

上述错误是Windows的典型消息; Unix消息类似。

一个修复是 使用 选项 启动 mysqld --tmpdir 或将选项添加到 [mysqld] 选项文件 的 部分。 例如,要指定目录 C:\temp ,请使用以下行:

的[mysqld]
TMPDIR = C:/温度

该 C:\temp 目录必须存在并且有足够的空间供MySQL服务器写入。 请参见 第4.2.2.2节“使用选项文件” 。

此错误的另一个原因可能是权限问题。 确保MySQL服务器可以写入 tmpdir 目录。

还要检查 perror 获得的错误代码 。 服务器无法写入表的一个原因是文件系统已满:

外壳> perror 28
操作系统错误代码28:设备上没有剩余空间

如果在启动期间出现以下类型的错误,则表示用于存储数据文件的文件系统或目录是写保护的。 如果写入错误发生在测试文件中,则错误并不严重,可以安全地忽略。

无法创建测试文件/usr/local/mysql/data/master.lower-test

B.4.2.13命令不同步

如果您 Commands out of sync; you can't run this command now 输入了客户端代码,则会以错误的顺序调用客户端函数。

例如,如果您 mysql_use_result() 在调用之前 使用 并尝试执行新查询 ,则可能会发生这种情况 mysql_free_result() 。 如果您尝试执行两个不调用 mysql_use_result() 或 mysql_store_result() 在两者之间 返回数据的查询,也会发生这种情况 。

B.4.2.14忽略用户

如果您收到以下错误,则表示当 mysqld 启动或重新加载授权表时,它在 user 表中找到了一个密码无效 的帐户 。

Found wrong password for user 'some_user'@'some_host'; ignoring user

因此,权限系统会简单地忽略该帐户。 要解决此问题,请为该帐户分配新的有效密码。

B.4.2.15表'tbl_name'不存在

如果您遇到以下任一错误,通常意味着默认数据库中不存在具有给定名称的表:

表' tbl_name'不存在
找不到文件:' tbl_name'(错误号码:2)

在某些情况下,表可能存在,但您指的是错误的:

  • 因为MySQL使用目录和文件来存储数据库和表,所以如果数据库和表名称位于具有区分大小写的文件名的文件系统上,则它们区分大小写。

  • 即使对于不区分大小写的文件系统(例如在Windows上),对查询中给定表的所有引用都必须使用相同的字母大小写。

您可以使用默认数据库检查哪些表 SHOW TABLES 。 请参见 第13.7.6节“显示语法” 。

B.4.2.16无法初始化字符集

如果您遇到字符集问题,可能会看到如下错误:

MySQL连接失败:无法初始化字符集 charset_name

此错误可能具有以下任何原因:

  • 字符集是多字节字符集,您不支持客户端中的字符集。 在这种情况下,您需要通过 使用该 选项 运行 CMake 来重新编译客户端 。 请参见 第2.9.4节“MySQL源配置选项” 。 -DDEFAULT_CHARSET=charset_name

    编译所有标准MySQL二进制文件,支持所有多字节字符集。

  • 字符集是一个未编译到 mysqld中 的简单字符集, 字符集定义文件不在客户端期望找到它们的位置。

    在这种情况下,您需要使用以下方法之一来解决问题:

    • 重新编译客户端,支持字符集。 请参见 第2.9.4节“MySQL源配置选项” 。

    • 向客户端指定字符集定义文件所在的目录。 对于许多客户,您可以使用该 --character-sets-dir 选项 执行此操作 。

    • 将字符定义文件复制到客户端期望的路径。

B.4.2.17找不到文件和类似错误

如果你 , 或任何其他误差 或 从MySQL,这意味着你没有为MySQL服务器分配足够的文件描述符。 您可以使用 perror 实用程序来获取错误编号的含义: ERROR 'file_name' not found (errno: 23) Can't open file: file_name (errno: 24) errno 23 errno 24

外壳> perror 23
操作系统错误代码23:文件表溢出
外壳> perror 24
操作系统错误代码24:打开的文件过多
外壳> perror 11
操作系统错误代码11:资源暂时不可用

这里的问题是 mysqld 试图同时打开太多文件。 您可以告诉 mysqld 不要一次打开这么多文件或增加 mysqld 可用的文件描述符数量 。

要告诉 mysqld 一次打开更少的文件,可以通过减少 table_open_cache 系统变量 的值来使表缓存更小 (默认值为64)。 这可能无法完全防止文件描述符耗尽,因为在某些情况下,服务器可能会尝试临时扩展缓存大小,如 第8.4.3.1节“MySQL如何打开和关闭表”中所述 。 减少值 max_connections 也会减少打开文件的数量(默认值为100)。

要更改 mysqld 可用的文件描述符数 ,可以使用 mysqld_safe --open-files-limit 选项 或设置 系统变量。 请参见 第5.1.8节“服务器系统变量” 。 设置这些值的最简单方法是在选项文件中添加一个选项。 请参见 第4.2.2.2节“使用选项文件” 。 如果你有一个 不支持设置打开文件限制 的旧版 mysqld ,你可以编辑 mysqld_safe 脚本。 脚本中 有一个注释掉的行 ulimit -n 256 。 你可以删除 open_files_limit # 取消注释该行的字符,并更改数字 256 以设置可供 mysqld 使用的文件描述符的数量 。

--open-files-limit 和 ulimit 可以增加文件描述符的数量,但只能达到操作系统强加的限制。 还有一个 “ 硬 ” ,只能如果你开始重写限制 mysqld_safe的 或 mysqld的 作为 root (只记得,你还需要与启动服务器 --user 在这种情况下选项,以便它不会继续照常运行 root 后启动)。 如果需要增加操作系统对每个进程可用的文件描述符数量的限制,请参阅系统文档。

注意

如果你运行 tcsh shell, ulimit 不起作用! 当您要求当前限制时, tcsh 也会报告错误的值。 在这种情况下,您应该 使用 sh 启动 mysqld_safe 。

B.4.2.18表 - 腐败问题

如果你已经开始 的mysqld 使用 --myisam-recover-options 中,MySQL自动检查并尝试修复 MyISAM 表,如果他们被标记为“未正常关闭”或“崩溃”。 如果发生这种情况,MySQL会在 hostname.err 文件中 写入一个条目, 如果需要修复该表 'Warning: Checking table ...' ,则后跟 该 文件 Warning: Repairing table 。 如果你得到很多这些错误,如果没有 mysqld 在之前意外死亡,那么就会出现问题并需要进一步调查。

当服务器检测到 MyISAM 表损坏时,它会将其他信息写入错误日志,例如源文件的名称和行号以及访问该表的线程列表。 示例: Got an error from thread_id=1, mi_dynrec.c:368 。 这是包含在错误报告中的有用信息。

另请参见 第5.1.7节“服务器命令选项” 和 第29.5.1.7节“如果遇到表损坏,请创建测试用例” 。

B.4.3与管理有关的问题

B.4.3.1文件权限问题

如果您遇到文件权限问题,则 mysqld 启动 时可能会错误地设置 UMASK 或 UMASK_DIR 环境变量 。 例如,MySQL可能会在您创建表时发出以下错误消息:

错误:找不到文件:'path / with / file_name'(错误代码:13)

默认值 UMASK 和 UMASK_DIR 值分别为 0640 和 0750 。 如果以零开头, MySQL假定值为 UMASK 或 UMASK_DIR 八进制。 例如,设置 UMASK=0600 相当于 UMASK=384 因为0600八进制是384十进制。

要更改默认 UMASK 值,请 按如下所示 启动 mysqld_safe :

shell> UMASK=384  # = 600 in octal
shell> export UMASK
shell>mysqld_safe &

默认情况下,MySQL创建访问权限值为的数据库目录 0750 。 要修改此行为,请设置 UMASK_DIR 变量。 如果设置其值,则使用组合 值 UMASK 和 UMASK_DIR 值 创建新目录 。 例如,要授予对所有新目录的组访问权限,请 按以下方式 启动 mysqld_safe :

shell> UMASK_DIR=504  # = 770 in octal
shell> export UMASK_DIR
shell>mysqld_safe &

有关其他详细信息,请参见 第4.9节“MySQL程序环境变量” 。

B.4.3.2如何重置root密码

如果您从未 root 为MySQL 分配过 密码,则服务器根本不需要密码即可进行连接 root 。 但是,这是不安全的。 有关分配密码的说明,请参见 第2.10.4节“保护初始MySQL帐户” 。

如果您知道 root 密码并想要更改密码,请参见 第13.7.1.1节“ALTER USER语法” 和 第13.7.1.10节“SET PASSWORD语法” 。

如果您 root 之前已经 分配了 密码但忘记 了 密码,则可以指定新密码。 以下部分提供了有关Windows,Unix和类Unix系统的说明,以及适用于任何系统的一般说明。

B.4.3.2.1重置root密码:Windows系统

在Windows上,使用以下过程重置MySQL 'root'@'localhost' 帐户 的密码 。 要更改 root 具有不同主机名部分 的 帐户 的密码 ,请修改使用该主机名的说明。

  1. 以管理员身份登录系统。

  2. 如果MySQL服务器正在运行,请将其停止。 对于作为Windows服务运行的服务器,请转到服务管理器:从“ 开始” 菜单中选择“ 控制面板” ,然后 选择“ 管理工具” ,再选择“ 服务” 。 在列表中找到MySQL服务并停止它。

    如果您的服务器未作为服务运行,则可能需要使用任务管理器强制它停止。

  3. 在一行上创建一个包含密码赋值语句的文本文件。 将密码替换为您要使用的密码。

    ALTER USER'root'@'localhost'ENFENTIFIED BY'MyNewPass';
    
  4. 保存文件。 此示例假定您为该文件命名 C:\mysql-init.txt 。

  5. 打开控制台窗口以进入命令提示符:从“ 开始” 菜单中选择 “运行” ,然后输入 cmd 作为要运行的命令。

  6. 使用特殊 --init-file 选项 启动MySQL服务器 (注意选项值中的反斜杠加倍):

    C:\> cd "C:\Program Files\MySQL\MySQL Server 8.0\bin"
    C:\>mysqld --init-file=C:\\mysql-init.txt
    

    如果您将MySQL安装到其他位置,请相应地调整 cd 命令。

    服务器 --init-file 在启动时 执行 选项 命名的文件内容 ,更改 'root'@'localhost' 帐户密码。

    要使服务器输出显示在控制台窗口而不是日志文件中,请将该 --console 选项 添加 到 mysqld 命令。

    如果使用MySQL安装向导安装MySQL,则可能需要指定 --defaults-file 选项。 例如:

    C:\> mysqld
             --defaults-file="C:\\ProgramData\\MySQL\\MySQL Server 8.0\\my.ini"
             --init-file=C:\\mysql-init.txt
    

    --defaults-file 可以使用服务管理器找到 相应的 设置:从“ 开始” 菜单中选择“ 控制面板” ,然后 选择“ 管理工具” ,再选择“ 服务” 。 在列表中找到MySQL服务,右键单击它,然后选择该 Properties 选项。 该 Path to executable 字段包含 --defaults-file 设置。

  7. 服务器成功启动后,删除 C:\mysql-init.txt 。

您现在应该能够 root 使用新密码 连接到MySQL服务器 。 停止MySQL服务器并正常重启。 如果将服务器作为服务运行,请从Windows服务窗口启动它。 如果手动启动服务器,请使用通常使用的任何命令。

B.4.3.2.2重置root密码:Unix和类Unix系统

在Unix上,使用以下过程重置MySQL 'root'@'localhost' 帐户 的密码 。 要更改 root 具有不同主机名部分 的 帐户 的密码 ,请修改使用该主机名的说明。

说明假定您将从通常用于运行它的Unix登录帐户启动MySQL服务器。 例如,如果使用 mysql 登录帐户 运行服务器 ,则应按照 mysql 之前的说明使用说明进行 登录 。 或者,您可以以as身份登录 root ,但在这种情况下,您 必须 使用该 选项 启动 mysqld --user=mysql 。 如果您在 root 不使用 --user=mysql 的 情况下 启动服务器 ,则服务器可能会创建 root 数据目录中的文件,例如日志文件,这些文件可能会导致未来服务器启动时出现与权限相关的问题。 如果发生这种情况,您需要更改文件的所有权 mysql 或删除它们。

  1. 以MySQL服务器运行的Unix用户身份登录到您的系统(例如, mysql )。

  2. 如果MySQL服务器正在运行,请将其停止。 找到 .pid 包含服务器进程ID 的 文件。 此文件的确切位置和名称取决于您的分发,主机名和配置。 常见的位置是 /var/lib/mysql/ , /var/run/mysqld/ 和 /usr/local/mysql/data/ 。 通常,文件名具有扩展名, .pid 并以 mysqld 系统的主机名或系统的主机名 开头 。

    通过向 mysqld 进程 发送正常 kill (非 kill -9 )来 停止MySQL服务器 。 在以下命令中 使用该 文件 的实际路径名 : .pid

    外壳> kill `cat /mysql-data-directory/host_name.pid`
    

    使用该 cat 命令 使用反引号(不是正向引号) 。 这些导致输出 cat 被替换为 kill 命令。

  3. 在一行上创建一个包含密码赋值语句的文本文件。 将密码替换为您要使用的密码。

    ALTER USER'root'@'localhost'ENFENTIFIED BY'MyNewPass';
    
  4. 保存文件。 此示例假定您为该文件命名 /home/me/mysql-init 。 该文件包含密码,因此请勿将其保存在其他用户可以读取的位置。 如果您未以 mysql (服务器运行的用户身份) 登录 ,请确保该文件具有允许 mysql 读取它的 权限 。

  5. 使用特殊 --init-file 选项 启动MySQL服务器 :

    外壳> mysqld --init-file=/home/me/mysql-init &
    

    服务器 --init-file 在启动时 执行 选项 命名的文件内容 ,更改 'root'@'localhost' 帐户密码。

    其他选项也可能是必需的,具体取决于您正常启动服务器的方式。 例如, --defaults-file 之前可能需要 --init-file 。

  6. 服务器成功启动后,删除 /home/me/mysql-init 。

您现在应该能够 root 使用新密码 连接到MySQL服务器 。 停止服务器并正常重新启动它。

B.4.3.2.3重置Root密码:通用指令

前面几节提供了专门针对Windows和Unix以及类Unix系统的密码重置说明。 或者,在任何平台上,您都可以使用 mysql 客户端 重置密码 (但这种方法不太安全):

  1. 如有必要,请停止MySQL服务器,然后使用该 --skip-grant-tables 选项 重新启动它 。 这使得任何人都可以在没有密码和所有权限的情况下进行连接,并禁用帐户管理语句,例如 ALTER USER 和 SET PASSWORD 。 因为这是不安全的,如果使用该 --skip-grant-tables 选项 启动服务器 ,它会 --skip-networking 自动 启用 以防止远程连接。

  2. 使用 mysql 客户端 连接MySQL服务器 ; 没有密码是必需的,因为服务器启动时 --skip-grant-tables :

    外壳> mysql
    
  3. 在 mysql 客户端中,告诉服务器重新加载授权表,以便帐户管理语句起作用:

    MySQL的> FLUSH PRIVILEGES;
    

    然后更改 'root'@'localhost' 帐户密码。 将密码替换为您要使用的密码。 要更改 root 具有不同主机名部分 的 帐户 的密码 ,请修改使用该主机名的说明。

    MySQL的> ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
    

您现在应该能够 root 使用新密码 连接到MySQL服务器 。 停止服务器并正常重新启动它(没有 --skip-grant-tables 和 --skip-networking 选项)。

B.4.3.3如果MySQL不断崩溃该怎么办

每个MySQL版本在发布之前都在许多平台上进行了测试。 这并不意味着MySQL中没有错误,但是如果存在错误,它们应该很少并且很难找到。 如果您遇到问题,如果您试图找出系统崩溃的确切原因,那么它总会有所帮助,因为您有更好的机会快速解决问题。

首先,您应该尝试找出问题是 mysqld 服务器是否死亡或者您的问题是否与您的客户端有关。 您可以 通过执行 mysqladmin版本 来检查 mysqld 服务器已运行 多长时间 。 如果 mysqld 已经死亡并重新启动,您可以通过查看服务器的错误日志找到原因。 请参见 第5.4.2节“错误日志” 。

在某些系统上,您可以在错误日志中找到 mysqld 死亡 的堆栈跟踪 。 请注意,错误日志中写入的变量值可能并不总是100%正确。

许多服务器崩溃是由损坏的数据文件或索引文件引起的。 MySQL write() 在每个SQL语句之后以及在客户端收到有关结果的通知之前 ,使用 系统调用 更新磁盘上的文件 。 (如果在 delay_key_write 启用系统变量的情况下 运行,则不是这样 ,在这种情况下会写入数据文件而不是索引文件。)这意味着即使 mysqld 崩溃, 数据文件内容也是安全的 ,因为操作系统确保了未刷新的数据写入磁盘。 通过 使用该 选项 启动 mysqld , 您可以强制MySQL在每个SQL语句之后将所有内容刷新到磁盘 --flush 。

前面的意思是通常你不应该得到损坏的表,除非发生以下情况之一:

  • MySQL服务器或服务器主机在更新过程中被终止。

  • 您在 mysqld 中 发现了一个错误 ,导致它在更新过程中死亡。

  • 一些外部程序在 没有正确锁定表的情况下 与 mysqld 同时操作数据文件或索引文件 。

  • 您正在运行许多 mysqld 服务器,这些服务器在不支持良好文件系统锁定的系统上使用相同的数据目录(通常由 lockd 锁管理器 处理 ),或者您正在运行多个禁用外部锁定的服务器。

  • 您有一个崩溃的数据文件或索引文件,其中包含使 mysqld 混淆的非常损坏的数据 。

  • 您在数据存储代码中发现了一个错误。 这不太可能,但至少是可能的。 在这种情况下,您可以尝试使用 ALTER TABLE 已修复的表副本 将存储引擎更改为另一个引擎 。

因为很难知道为什么会崩溃,所以首先要检查一下对他人有用的东西是否会崩溃。 请尝试以下方法:

  • 使用 mysqladmin shutdown 停止 mysqld 服务器, 从数据目录 运行 myisamchk --silent --force * / *。MYI 以检查所有 表,然后重启 mysqld 。 这可确保您从干净的状态运行。 请参见 第5章, MySQL服务器管理 。 MyISAM

  • 启用 通用查询日志 启动 mysqld (请参见 第5.4.3节“通用查询日志” )。 然后尝试从写入日志的信息中确定某个特定查询是否会杀死服务器。 大约95%的错误与特定查询有关。 通常,这是服务器重新启动之前日志文件中的最后一个查询之一。 请参见 第5.4.3节“常规查询日志” 。 如果您可以使用特定查询重复杀死MySQL,即使您在发布之前检查了所有表,那么您已经隔离了该错误并应该为其提交错误报告。 看到 第1.7节“如何报告错误或问题” 。

  • 尝试制作一个我们可以用来重复问题的测试用例。 请参见 第29.5节“调试和移植MySQL” 。

  • 试试这个 fork_big.pl 剧本。 (它位于 tests 源代码分发目录中。)

  • 配置MySQL进行调试可以在出现问题时更容易收集有关可能错误的信息。 使用 CMake -DWITH_DEBUG=1 选项 重新配置MySQL, 然后重新编译。 请参见 第29.5节“调试和移植MySQL” 。

  • 确保已应用适用于您的操作系统的最新修补程序。

  • 使用 mysqld --skip-external-locking 选项 。 在某些系统上, 锁管理器无法正常工作; 该 选项告诉 mysqld 不要使用外部锁定。 (这意味着您不能 在同一数据目录上 运行两个 mysqld 服务器,并且如果使用 myisamchk 则必须小心 。但是,尝试将该选项作为测试可能是 有益的 。) lockd --skip-external-locking

  • 如果 mysqld 似乎正在运行但没有响应,请尝试 mysqladmin -u root processlist 。 有时 mysqld 并没有挂起,即使它看起来没有反应。 问题可能是所有连接都在使用中,或者可能存在一些内部锁定问题。 mysqladmin -u root processlist 通常能够在这些情况下建立连接,并且可以提供有关当前连接数及其状态的有用信息。

  • 在单独的窗口中 运行命令 mysqladmin -i 5 status 或 mysqladmin -i 5 -r status 以在运行其他查询时生成统计信息。

  • 请尝试以下方法:

    1. 从 gdb (或另一个调试器) 启动 mysqld 。 请参见 第29.5节“调试和移植MySQL” 。

    2. 运行测试脚本。

    3. 在三个最低级别打印回溯和局部变量。 在 gdb中 ,当 mysqld 在 gdb中 崩溃 时,可以使用以下命令执行此操作 :

      回溯
      信息本地
      向上
      信息本地
      向上
      信息本地
      

      使用 gdb ,您还可以检查存在哪些线程 info threads 并切换到特定线程 ,其中 是线程ID。 thread N N

  • 尝试使用Perl脚本模拟您的应用程序以强制MySQL崩溃或行为异常。

  • 发送正常的错误报告。 请参见 第1.7节“如何报告错误或问题” 。 比平时更加​​细致。 因为MySQL适用于许多人,所以崩溃可能是由于您的计算机上只存在某些内容(例如,与您的特定系统库相关的错误)。

  • 如果您有包含动态长度行的表问题,您只使用 VARCHAR 列(未 BLOB 或 TEXT 列),你可以尝试所有更改 VARCHAR 到 CHAR 与 ALTER TABLE 。 这迫使MySQL使用固定大小的行。 固定大小的行占用一些额外的空间,但更容忍腐败。

    当前的动态行代码已经使用了好几年而且问题很少,但动态长度的行本质上更容易出错,因此尝试这种策略以确定它是否有帮助可能是一个好主意。

  • 在诊断问题时考虑硬件故障的可能性。 有缺陷的硬件可能是数据损坏的原因。 在对硬件进行故障排除时,请特别注意内存和磁盘子系统。

B.4.3.4 MySQL如何处理完整磁盘

本节介绍MySQL如何响应磁盘已满的错误(例如 “ 设备上没有剩余空间 ” )以及超出配额的错误(例如 “ 写入失败 ” 或 “ 达到用户块限制 ” )。

此部分与写入 MyISAM 表 相关 。 它还适用于对二进制日志文件和二进制日志索引文件的写入,除了对 “ 行 ” 和 “ 记录 ”的 引用 应理解为 “ 事件”。 ”

当磁盘已满磁盘时,MySQL会执行以下操作:

  • 它每分钟检查一次,看是否有足够的空间来写当前行。 如果有足够的空间,它就会继续,好像什么也没发生过一样。

  • 它每10分钟写一个条目到日志文件,警告磁盘已满的情况。

要解决此问题,请执行以下操作:

  • 要继续,您只需释放足够的磁盘空间即可插入所有记录。

  • 或者,要中止线程,请使用 mysqladmin kill 。 下次检查磁盘时(1分钟内)线程将中止。

  • 其他线程可能正在等待导致磁盘已满的情况的表。 如果您有多个 “ 锁定 ” 线程,则杀死正在等待磁盘已满状态的一个线程会使其他线程继续运行。

上述行为的例外情况是您 在 语句 之后 或之后 使用 REPAIR TABLE 或 OPTIMIZE TABLE 在批处理中创建索引时 。 所有这些语句都可能会创建大型临时文件,如果留给自己,则会对系统的其余部分造成严重问题。 如果磁盘在MySQL执行任何这些操作时变满,它会删除大的临时文件并将表标记为崩溃。 例外情况是, 旧表保持不变。 LOAD DATA ALTER TABLE ALTER TABLE

B.4.3.5 MySQL存储临时文件的位置

在Unix上,MySQL使用 TMPDIR 环境变量 的值 作为存储临时文件的目录的路径名。 如果 TMPDIR 没有设置,MySQL使用系统默认的,通常 /tmp , /var/tmp 或 /usr/tmp 。

在Windows上,MySQL的顺序查找的值 TMPDIR , TEMP 以及 TMP 环境变量。 对于第一个发现设置,MySQL使用它并不检查剩余的。 如果没有的 TMPDIR , TEMP 或 TMP 设定,MySQL使用Windows系统默认情况下,通常是 C:\windows\temp\ 。

如果包含临时文件目录的文件系统太小,则可以使用 mysqld --tmpdir 选项指定文件系统中有足够空间的目录。

该 --tmpdir 选项可以设置为以循环方式使用的多个路径的列表。 路径应该用 : Unix上 的冒号字符( )和 ; Windows上的 分号字符( ) 分隔 。

注意

为了有效地分散负载,这些路径应位于不同的 物理 磁盘上,而不是同一磁盘的不同分区。

如果MySQL服务器充当复制从属服务器,则可以使用该 --slave-load-tmpdir 选项指定用于在复制 LOAD DATA 语句 时保留临时文件的单独目录 。 此目录应位于基于磁盘的文件系统(不是基于内存的文件系统)中,以便用于复制LOAD DATA的临时文件可以在计算机重新启动后继续存在。 该目录也不应该是在系统启动过程中由操作系统清除的目录。 但是,如果已删除临时文件,则重新启动后现在可以继续复制。

如果 mysqld 被终止 ,MySQL会安排删除临时文件 。 在支持它的平台上(例如Unix),可以通过在打开文件后取消链接来完成。 这样做的缺点是名称没有出现在目录列表中,并且您没有看到填充临时文件目录所在的文件系统的大型临时文件。 (在这种情况下, lsof + L1 可能有助于识别与 mysqld 相关的大文件 。)

排序( ORDER BY 或 GROUP BY )时,MySQL通常使用一个或两个临时文件。 所需的最大磁盘空间由以下表达式确定:

(排序的长度+ sizeof(行指针))
*匹配行数
* 2

行指针大小通常是四个字节,但是对于非常大的表,将来可能会增长。

对于某些语句,MySQL会创建不隐藏的临时SQL表,并且名称以其开头 #sql 。

某些 SELECT 查询会创建临时SQL表以保存中间结果。

重建表并且不使用该 ALGORITHM=INPLACE 技术 在线执行的DDL操作会在与 原始表相同的目录中创建原始表的临时副本。

联机DDL操作可以使用临时日志文件来记录并发DML,创建索引时的临时排序文件以及重建表时的临时中间表文件。 有关更多信息,请参见 第15.12.3节“在线DDL空间要求” 。

InnoDB 用户创建的临时表和磁盘内部临时表是 ibtmp1 在MySQL数据目录 中指定的临时表空间文件中创建的 。 有关更多信息,请参见 第15.6.3.5节“临时表空间” 。

另请参见 第15.14.7节“InnoDB INFORMATION_SCHEMA临时表信息表” 。

可选 EXTENDED 修饰符导致 SHOW TABLES 列出由失败 ALTER TABLE 语句 创建的隐藏表 。 请参见 第13.7.6.37节“显示表语法” 。

B.4.3.6如何保护或更改MySQL Unix套接字文件

服务器用于与本地客户端通信的Unix套接字文件的默认位置是 /tmp/mysql.sock 。 (对于某些分发格式,目录可能不同,例如 /var/lib/mysql RPM。)

在某些版本的Unix上,任何人都可以删除目录中的 /tmp 文件或用于临时文件的其他类似目录。 如果套接字文件位于系统上的此类目录中,则可能会导致问题。

在大多数Unix版本中,您可以保护您的 /tmp 目录,以便只能由其所有者或超级用户( root ) 删除文件 。 要执行此操作,请 通过 使用以下命令 登录来 设置 目录 sticky 上 的 位 : /tmp root

外壳> chmod +t /tmp

您可以 sticky 通过执行 来检查该 位 是否 已设置 ls -ld /tmp 。 如果是最后一个权限字符 t ,则设置该位。

另一种方法是更改​​服务器创建Unix套接字文件的位置。 如果这样做,您还应该让客户端程序知道文件的新位置。 您可以通过多种方式指定文件位置:

  • 在全局或本地选项文件中指定路径。 例如,将以下行放入 /etc/my.cnf :

    的[mysqld]
    插座= /路径/到/插座
    
    [客户]
    插座= /路径/到/插座
    

    请参见 第4.2.2.2节“使用选项文件” 。

  • --socket 在 mysqld_safe 的命令行上 指定一个 选项, 并在运行客户端程序时指定。

  • 将 MYSQL_UNIX_PORT 环境变量 设置为 Unix套接字文件的路径。

  • 从源代码重新编译MySQL以使用不同的默认Unix套接字文件位置。 MYSQL_UNIX_ADDR 运行 CMake 时, 使用该 选项 定义文件的路径 。 请参见 第2.9.4节“MySQL源配置选项” 。

您可以通过尝试使用此命令连接到服务器来测试新套接字位置是否正常工作:

外壳> mysqladmin --socket=/path/to/socket version

B.4.3.7时区问题

如果您 SELECT NOW() 在以UTC而不是当地时间返回值时 遇到问题 ,则必须告诉服务器您当前的时区。 如果 UNIX_TIMESTAMP() 返回错误的值, 则同样适用 。 这应该针对运行服务器的环境(例如,在 mysqld_safe 或 mysql.server中 )完成。 请参见 第4.9节“MySQL程序环境变量” 。

您可以使用 mysqld_safe 选项 设置服务器的时区 。 您也可以 在启动 mysqld 之前 通过设置 环境变量 来设置它 。 --timezone=timezone_name TZ

允许值为 --timezone 或 TZ 取决于系统。 请参阅操作系统文档以了解可接受的值。

B.4.4与查询相关的问题

B.4.4.1字符串搜索中的大小写敏感性

对于非二进制字符串( CHAR , VARCHAR , TEXT ),字符串搜索使用比较操作数的排序规则。 对于二进制串( BINARY , VARBINARY , BLOB ),比较使用在操作数中字节的数值; 这意味着对于字母字符,比较将区分大小写。

非二进制字符串和二进制字符串之间的比较被视为二进制字符串的比较。

简单的比较操作( >=, >, =, <, <= ,排序和分组)基于每个角色的 “ 排序值”。 “ 具有相同排序值的字符被视为相同的字符。 例如,如果 e 与 é 具有在给定的排序规则相同的排序值,它们的比较结果为相等的。

默认字符集和排序规则是 utf8mb4 和 utf8mb4_0900_ai_ci ,因此非二进制字符串比较默认情况下不区分大小写。 这意味着,如果使用搜索 col_name LIKE 'a%' ,则会获得以 A 或 开头的所有列值 a 。 要使此搜索区分大小写,请确保其中一个操作数具有区分大小写或二进制排序规则。 例如,如果要比较具有 utf8mb4 字符集 的列和字符串,则 可以使用 COLLATE 运算符使操作数具有 utf8mb4_0900_as_cs 或 utf8mb4_bin 排序规则:

col_nameCOLLATE utf8mb4_0900_as_cs LIKE'a%'
 col_name喜欢'a%'合作utf8mb4_0900_as_cs
 col_name收集utf8mb4_bin喜欢'a%'
 col_name喜欢'a%'合作伙伴utf8mb4_bin

如果希望始终以区分大小写的方式处理列,请使用区分大小写或二进制排序规则来声明它。 请参见 第13.1.20节“CREATE TABLE语法” 。

要使非二进制字符串的区分大小写的比较不区分大小写,请使用 COLLATE 命名不区分大小写的排序规则。 以下示例中的字符串通常区分大小写,但 COLLATE 将比较更改为不区分大小写:

mysql> SET NAMES 'utf8mb4';
mysql> 
mysql>SET @s1 = 'MySQL' COLLATE utf8mb4_bin,
           @s2 = 'mysql' COLLATE utf8mb4_bin;SELECT @s1 = @s2;
+ ----------- +
| @ s1 = @ s2 |
+ ----------- +
| 0 |
+ ----------- +
MySQL的> SELECT @s1 COLLATE utf8mb4_0900_ai_ci = @s2;
+ -------------------------------------- +
| @ s1 COLLATE utf8mb4_0900_ai_ci = @ s2 |
+ -------------------------------------- +
| 1 |
+ -------------------------------------- +

二进制字符串在比较中区分大小写。 要将字符串与不区分大小写进行比较,请将其转换为非二进制字符串,并使用 COLLATE 命名不区分大小写的排序规则:

mysql> SET @s = BINARY 'MySQL';
mysql>SELECT @s = 'mysql';
+ -------------- +
| @s ='mysql'|
+ -------------- +
| 0 |
+ -------------- +
MySQL的> SELECT CONVERT(@s USING utf8mb4) COLLATE utf8mb4_0900_ai_ci = 'mysql';
+ ------------------------------------------------- --------------- +
| CONVERT(@s USING utf8mb4)COLLATE utf8mb4_0900_ai_ci ='mysql'|
+ ------------------------------------------------- --------------- +
| 1 |
+ ------------------------------------------------- --------------- +

要确定值是否将作为非二进制或二进制字符串进行比较,请使用该 COLLATION() 函数。 此示例显示 VERSION() 返回具有不区分大小写的排序规则的字符串,因此比较不区分大小写:

MySQL的> SELECT COLLATION(VERSION());
+ ---------------------- +
| COLLATION(VERSION())|
+ ---------------------- +
| utf8_general_ci |
+ ---------------------- +

对于二进制字符串,排序规则值为 binary ,因此比较将区分大小写。 您将看到的一个上下文 binary 是压缩函数,它返回二进制字符串作为一般规则:string:

MySQL的> SELECT COLLATION(COMPRESS('x'));
+ -------------------------- +
| COLLATION(COMPRESS('x'))|
+ -------------------------- +
| 二进制|
+ -------------------------- +

要检查字符串的排序值, WEIGHT_STRING() 可能会有所帮助。 请参见 第12.5节“字符串函数” 。

B.4.4.2使用DATE列的问题

DATE 值 的格式 是 'YYYY-MM-DD' 。 根据标准SQL,不允许使用其他格式。 你应该使用这种格式 UPDATE 的表达和在 WHERE 条款 SELECT 的语句。 例如:

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

为方便起见,如果日期在数字上下文中使用,MySQL会自动将日期转换为数字,反之亦然。 MySQL还允许 “ 宽松 ” 一个在更新,当字符串格式 WHERE ,其比较日期的条款 DATE , DATETIME 或 TIMESTAMP 列。 “ 宽松 ” 格式意味着任何标点符号都可以用作部件之间的分隔符。 例如, '2004-08-15' 并且 '2004#08#15' 是等价的。 MySQL也可以转换不包含分隔符的字符串(例如 '20040815' ),只要它作为日期有意义。

当您比较 DATE , TIME , DATETIME ,或 TIMESTAMP 成一个常量字符串用 < , <= , = , >= , > ,或 BETWEEN 运营商,MySQL通常字符串到内部长整型转换更快比较(也为更多的 “ 宽松 ” 的字符串检查)。 但是,此转换受以下例外情况限制:

  • 比较两列时

  • 当你一个比较 DATE , TIME , DATETIME ,或 TIMESTAMP 列表达式

  • 当您使用除了刚刚列出的那些之外的任何比较方法,例如 IN 或 STRCMP() 。

对于这些异常,通过将对象转换为字符串并执行字符串比较来完成比较。

为了安全起见,假设要将字符串作为字符串进行比较,并且如果要将时间值与字符串进行比较,请使用相应的字符串函数。

可以存储和检索 特殊的 “ 零 ” 日期。 当 通过Connector / ODBC使用日期时,它会自动转换为 因为ODBC无法处理这种日期。 '0000-00-00' '0000-00-00'. '0000-00-00' NULL

因为MySQL执行刚刚描述的转换,所以以下语句有效(假设这 idate 是一 DATE 列):

INSERT INTO t1(idate)VALUES(19970505);
INSERT INTO t1(idate)VALUES('19970505');
INSERT INTO t1(idate)VALUES('97 -05-05');
INSERT INTO t1(idate)VALUES('1997.05.05');
INSERT INTO t1(idate)VALUES('1997 05 05');
INSERT INTO t1(idate)VALUES('0000-00-00');

SELECT idate FROM t1 WHERE idate> ='1997-05-05';
SELECT idate FROM t1 WHERE idate> = 19970505;
SELECT MOD(idate,100)FROM t1 WHERE idate> = 19970505;
SELECT idate FROM t1 WHERE idate> ='19970505';

但是,以下声明不起作用:

SELECT idate FROM t1 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应用程序,并且您希望准确存储用户插入的内容(不进行日期验证)。

MySQL允许您存储日期或月份和日期为零的日期。 如果您想将生日存储在 DATE 列中并且只知道部分 日期,这很方便 。 要禁止日期中零月或日零件,请启用该 NO_ZERO_IN_DATE 模式。

MySQL允许您将 “ 零 ” 值 存储 '0000-00-00' 为 “ 虚拟日期”。 “ 在某些情况下,这比使用 NULL 值 更方便 。 如果要存储在 DATE 列中 的日期 无法转换为任何合理的值,MySQL将存储 '0000-00-00' 。 要禁用 '0000-00-00' ,请启用该 NO_ZERO_DATE 模式。

要让MySQL检查所有日期并仅接受合法日期(除非被覆盖 IGNORE ),请将 sql_mode 系统变量 设置 为 "NO_ZERO_IN_DATE,NO_ZERO_DATE" 。

B.4.4.3 NULL值的问题

NULL 值 的概念 是SQL新手的常见混淆源,他们常常认为这 NULL 与空字符串是一样的 '' 。 不是这种情况。 例如,以下语句完全不同:

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

两个语句都在 phone 列中 插入一个值 ,但第一个插入一个 NULL 值,第二个插入一个空字符串。 第一个的含义可以被视为 “ 电话号码未知 ” ,第二个的含义可以被视为 “ 已知该人没有电话,因此没有电话号码。 ”

为了帮助 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值” 。

您可以在可以有一列中添加索引 NULL ,如果您使用的值 MyISAM , InnoDB 或 MEMORY 存储引擎。 否则,您必须声明索引列 NOT NULL ,并且不能插入 NULL 列。

使用时 LOAD DATA 更新 数据 ,使用空列或缺少列 '' 。 要将 NULL 值 加载 到列中,请 \N 在数据文件中使用。 NULL 在某些情况下也可以使用 字面词 。 请参见 第13.2.7节“LOAD DATA语法” 。

使用 DISTINCT ,, GROUP BY 或时 ORDER BY ,所有 NULL 值都被视为相等。

使用时 ORDER BY , NULL 如果指定 DESC 按降序排序, 则首先显示值,或者显示最后一个值 。

集合体(摘要)功能,例如 COUNT() , MIN() ,和 SUM() 忽略 NULL 的值。 例外情况是 COUNT(*) ,它计算行而不是单个列值。 例如,以下语句产生两个计数。 第一个是表中行数的计数,第二个是 列 中非 NULL 值 数的计数 age :

MySQL的> SELECT COUNT(*), COUNT(age) FROM person;

对于某些数据类型,MySQL NULL 特别 处理 值。 如果插入 NULL 到一个 TIMESTAMP 列,当前日期和时间插入。 如果插入 NULL 具有该 AUTO_INCREMENT 属性 的整数或浮点列, 则插入序列中的下一个数字。

B.4.4.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'客户身份'FROM tbl_name;

标准SQL不允许在 WHERE 子句中 引用列别名 。 强制执行此限制是因为在 WHERE 评估子句 时 ,可能尚未确定列值。 例如,以下查询是非法的:

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

该 WHERE 子句确定子句中应包含哪些行 GROUP BY ,但它引用了列值的别名,该列值在选择行之后才会知道,并按以下方式分组 GROUP BY 。

在查询的选择列表中,可以使用标识符或字符串引用字符指定带引号的列别名:

SELECT 1 AS`one`,2 AS'2';

在语句的其他地方,对别名的引用引用必须使用标识符引用,或者引用被视为字符串文字。 例如,此语句按列中的值进行分组 id ,使用别名引用 `a` :

SELECT id AS'a',COUNT(*)AS cnt FROM tbl_name
  GROUP BY`a`;

但是这个语句按字面字符串分组, 'a' 并且不会按预期工作:

SELECT id AS'a',COUNT(*)AS cnt FROM tbl_name
  GROUP BY'a';

B.4.4.5非事务表的回滚失败

如果在尝试执行a时收到以下消息 ROLLBACK ,则表示您在事务中使用的一个或多个表不支持事务:

警告:无法回滚某些非事务性更改的表

这些非事务性表不受该 ROLLBACK 语句的 影响 。

如果您没有故意在事务中混合事务性表和非事务性表,则此消息的最可能原因是您认为事务性的表实际上不是。 如果您尝试使用 mysqld 服务器 不支持的事务存储引擎 (或使用启动选项禁用) 创建表,则会发生这种情况 。 如果 mysqld 不支持存储引擎,它会将表创建为 MyISAM 表,这是非事务性的。

您可以使用以下任一语句检查存储引擎中的表:

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

请参见 第13.7.6.36节“SHOW TABLE STATUS语法” 和 第13.7.6.10节“SHOW CREATE TABLE语法” 。

要检查 mysqld 服务器支持 哪些存储引擎 ,请使用以下语句:

展示引擎;

有关 完整详细信息 , 请参见 第13.7.6.16节“显示发动机语法” 。

B.4.4.6从相关表中删除行

如果 DELETE 语句 的总长度 related_table 大于 max_allowed_packet 系统变量 的默认值 ,则应将其拆分为较小的部分并执行多个 DELETE 语句。 如果 已编制索引 , 则 每个语句 DELETE 仅指定100到1,000个 related_column 值, 您可能会获得最快的速度 related_column 。 如果 related_column 未编入索引,则速度与 IN 子句中 的参数数量无关 。

B.4.4.7解决无匹配行的问题

如果您有一个使用许多表但没有返回任何行的复杂查询,则应使用以下过程找出错误:

  1. 测试查询 EXPLAIN 以检查是否可以找到明显错误的内容。 请参见 第13.8.2节“EXPLAIN语法” 。

  2. 仅选择 WHERE 子句 中使用的那些列 。

  3. 从查询中一次删除一个表,直到它返回一些行。 如果表很大,最好 LIMIT 10 与查询 一起使用 。

  4. SELECT 为应该与上次从查询中删除的表匹配行的列 发出a 。

  5. 如果要比较 具有小数的数字 FLOAT 或 DOUBLE 列,则不能使用equality( = )比较。 此问题在大多数计算机语言中很常见,因为并非所有浮点值都可以精确存储。 在某些情况下,更改 FLOAT 为 DOUBLE 修复此问题。 请参见 第B.4.4.8节“浮点值的问题” 。

  6. 如果您仍然无法弄清楚出了什么问题,请创建一个可以运行的最小测试 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
    

    将测试文件附加到错误报告中,您可以使用 第1.7节“如何报告错误或问题”中 的说明进行归档 。

B.4.4.8浮点值的问题

浮点数有时会引起混淆,因为它们是近似值而不是存储为精确值。 在SQL语句中写入的浮点值可能与内部表示的值不同。 尝试将浮点值视为比较中的精确值可能会导致问题。 它们还受平台或实现依赖性的影响。 该 FLOAT 和 DOUBLE 数据类型都受到这些问题。 对于 DECIMAL 列,MySQL执行精度为65位十进制数的运算,这可以解决最常见的不准确问题。

以下示例用于 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;

+ ------ + ------- + ------ +
| 我| 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 |
+ ------ + ------- + ------ +

结果是正确的。 虽然前五个记录看起来不应该满足比较(值 a 和 b 看起来并不相同),但它们可能会这样做,因为数字之间的差异显示在十进制十分左右左右,这取决于诸如计算机体系结构或编译器版本或优化级别。 例如,不同的CPU可能以不同方式评估浮点数。

如果列 d1 和 d2 已被定义为 DECIMAL ,而不是 DOUBLE ,则结果 SELECT 查询会只包含一个行上面所示的最后一个。

进行浮点数比较的正确方法是首先确定数字之间差异的可接受容差,然后与容差值进行比较。 例如,如果我们同意浮点数如果在精度为万分之一(0.0001)内相同时应该被视为相同,则应编写比较以找出大于容差值的差异:

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
    - >GROUP BY i HAVING ABS(a - b) > 0.0001;
+ ------ + ------- + ------ +
| 我| a | b |
+ ------ + ------- + ------ +
| 6 | -51.4 | 0 |
+ ------ + ------- + ------ +
1排(0.00秒)

相反,要获得数字相同的行,测试应找到容差值内的差异:

mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
    - >GROUP BY i HAVING ABS(a - b) <= 0.0001;
+ ------ + ------ + ------ +
| 我| 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 |
+ ------ + ------ + ------ +
5行(0.03秒)

浮点值受平台或实现依赖性的影响。 假设您执行以下语句:

创建表t1(c1 FLOAT(53,0),c2 FLOAT(53,0));
插入t1值('1e + 52',' -  1e + 52');
SELECT * FROM t1;

在某些平台上, SELECT 语句返回 inf 和 -inf 。 在其他人,它返回 0 和 -0 。

上述问题的含义是,如果您尝试通过 在主服务器上转储 具有 mysqldump的 表内容 并将转储文件重新加载到从服务器 来创建复制 从服务器,则包含浮点列的表可能在两个主机之间不同。

B.4.5与优化器相关的问题

MySQL使用基于成本的优化器来确定解析查询的最佳方法。 在许多情况下,MySQL可以计算出最佳的查询计划,但有时MySQL没有足够的有关手头数据的信息,并且必须对数据做出 “有 根据的 ” 猜测。

对于MySQL不做“正确”事情的情况,可用于帮助MySQL的工具是:

B.4.6表定义相关问题

B.4.6.1 ALTER TABLE的问题

如果在 ALTER TABLE 用于更改字符集的字符集或排序规则 时出现重复键错误 ,则原因是新列排序规则将两个键映射到相同的值或表已损坏。 在后一种情况下,您应该 REPAIR TABLE 在桌面上 运行 。 REPAIR TABLE 工程 MyISAM , ARCHIVE 和 CSV 表。

如果您 ALTER TABLE 在事务性表上使用或者如果您使用的是Windows, ALTER TABLE 则在已经完成操作时解锁表 LOCK TABLE 。 这样做是因为 InnoDB 并且这些操作系统无法删除正在使用的表。

B.4.6.2临时表问题

创建的临时表 CREATE TEMPORARY TABLE 具有以下限制:

  • TEMPORARY 表只能由支持 InnoDB , MEMORY , MyISAM ,和 MERGE 存储引擎。

  • NDB Cluster不支持临时表。

  • 该 SHOW TABLES 语句未列出 TEMPORARY 表格。

  • 要重命名 TEMPORARY 表, RENAME TABLE 不起作用。 ALTER TABLE 改为 使用 :

    ALTER TABLE old_name RENAME new_name;
    
  • 您不能 TEMPORARY 在同一查询中多次 引用 表。 例如,以下内容不起作用:

    SELECT * FROM temp_table JOIN temp_table AS t2;
    

    该语句产生此错误:

    错误1137:无法重新打开表:'temp_table'
    

    如果您的查询允许使用公用表表达式(CTE)而不是 TEMPORARY 表, 则可以解决此问题 。 例如,由于 无法重新打开表 错误而 失败 :

    CREATE TEMPORARY TABLE t SELECT 1 AS col_a,2 AS col_b;
    SELECT * FROM t AS t1 JOIN t AS t2;
    

    要避免错误,请使用 WITH 定义CTE 的 子句而不是 TEMPORARY 表:

    with cte AS(SELECT 1 AS col_a,2 AS col_b)
    SELECT * FROM cte AS t1 JOIN cte AS t2;
    
  • 将 不能重新打开表 的错误,如果你还下不同的别名存储函数多次引用一个临时表时,即使发生在函数中不同的语句引用。 对于在存储函数外部创建并在多个调用和被调用函数之间引用的临时表,可能会发生这种情况。

  • 如果使用 TEMPORARY 与现有非 TEMPORARY 表 相同的名称创建 a, 则在 删除表 TEMPORARY 之前将隐藏 非 表 TEMPORARY ,即使表使用不同的存储引擎也是如此。

  • 使用临时表和复制时存在已知问题。 有关 更多信息 , 请参见 第17.4.1.30节“复制和临时表” 。

B.4.7 MySQL中的已知问题

本节列出了最新版MySQL中的已知问题。

有关特定于平台的问题的信息,请参见 第2.1节“一般安装指南” 和 第29.5节“调试和移植MySQL”中 的安装和移植说明 。

以下问题是已知的:

  • 子查询优化 IN 不如此有效 = 。

  • 即使你使用 lower_case_table_names=2 (它使MySQL能够记住用于数据库和表名的情况),MySQL也不记得用于函数的数据库名称 DATABASE() 或各种日志(在不区分大小写的系统上)的情况。

  • 删除 FOREIGN KEY 约束在复制中不起作用,因为约束可能在从属上具有另一个名称。

  • REPLACE (并 LOAD DATA 带有 REPLACE 选项)不会触发 ON DELETE CASCADE 。

  • DISTINCT 有 ORDER BY 没有在里面工作 GROUP_CONCAT() ,如果你不使用所有,只有那些在列 DISTINCT 列表。

  • 当将一个大整数值(在2 63 和2 64 -1之间)插入到十进制或字符串列中时,它将作为负值插入,因为该数字是在有符号整数上下文中计算的。

  • 通过基于语句的二进制日志记录,主服务器将执行的查询写入二进制日志。 这是一种非常快速,紧凑,高效的记录方法,在大多数情况下都能很好地工作。 但是,如果查询的设计方式使得数据修改是不确定的(通常不是推荐的做法,甚至在复制之外),则主服务器和从服务器上的数据可能会变得不同。

    例如:

    当且仅当前面的查询没有 ORDER BY 保证确定性顺序的子句时 。

    例如,对于 INSERT ... SELECT no ORDER BY , SELECT 可以以不同的顺序返回行(这导致行具有不同的等级,因此在 AUTO_INCREMENT 列中 获得不同的数字 ),这取决于主服务器和从服务器上的优化器所做出的选择。

    仅在以下情况下,在主服务器和从服务器上对查询进

    • 该表使用主服务器上的不同存储引擎而不是从服务器存储。 (可以在主站和从站上使用不同的存储引擎。例如, 如果从站的可用磁盘空间较少 ,则可以 InnoDB 在主站 MyISAM 上 使用 ,但 在从站上使用。)

    • MySQL缓冲区大小( key_buffer_size 等等)在主站和从站上是不同的。

    • 主服务器和从服务器运行不同的MySQL版本,优化器代码在这些版本之间有所不同。

    使用 mysqlbinlog | mysql 也可能影响数据库恢复 。

    避免此问题的最简单方法是 ORDER BY 在上述非确定性查询中 添加一个 子句,以确保始终以相同的顺序存储或修改行。 使用基于行或混合日志记录格式也可以避免此问题。

  • 如果未使用启动选项指定文件名,则日志文件名基于服务器主机名。 要在将主机名更改为其他名称时保留相同的日志文件名,必须明确使用诸如的选项 。 请参见 第5.1.7节“服务器命令选项” 。 或者,重命名旧文件以反映主机名更改。 如果这些是二进制日志,则必须编辑二进制日志索引文件并在其中修复二进制日志文件名。 (对于从属服务器上的中继日志也是如此。) --log-bin=old_host_name-bin

  • mysqlbinlog 不会删除 LOAD DATA 语句 后留下的临时文件 。 请参见 第4.6.8节“ mysqlbinlog - 处理二进制日志文件的实用程序” 。

  • RENAME 不适 TEMPORARY 用于表中使用的表或 MERGE 表。

  • 使用时 SET CHARACTER SET ,不能在数据库,表和列名称中使用已翻译的字符。

  • 在MySQL 8.0.17之前,您不能使用 _ 或 % 使用 ESCAPE in LIKE ... ESCAPE 。

  • max_sort_length 比较数据值时 ,服务器仅使用第一个 字节。 这意味着值不能被可靠地在使用 GROUP BY , ORDER BY 或 DISTINCT 如果它们仅在第一后不同 max_sort_length 字节。 要解决此问题,请增加变量值。 默认值为 max_sort_length 1024,可以在服务器启动时或运行时更改。

  • 用 BIGINT 或 完成数值计算 DOUBLE (两者通常都是64位长)。 您获得的精度取决于功能。 一般的规则是,位功能与执行 BIGINT 精度, IF() 并 ELT() 用 BIGINT 或 DOUBLE 精度,其余与 DOUBLE 精度。 如果除了位字段以外的任何内容,它们应该尽量避免使用无符号长long值(如果它们大于63位(9223372036854775807))。

  • 一个表中 最多可包含255个 列 ENUM 和 SET 列。

  • 在 MIN() 和 MAX() ,以及其他聚合函数中,MySQL当前 按字符串值 比较 ENUM 和 SET 列,而不是字符串在集合中的相对位置。

  • 在 UPDATE 语句中,列从左到右更新。 如果您引用更新的列,则会获得更新的值而不是原始值。 例如,下面的语句递增 KEY 的 2 , 不是 1 :

    MySQL的> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1;
    
  • 您可以在同一查询中引用多个临时表,但不能多次引用任何给定的临时表。 例如,以下内容不起作用:

    MySQL的> SELECT * FROM temp_table, temp_table AS t2;
    错误1137:无法重新打开表:'temp_table'
    
  • DISTINCT 当您在连接中使用 “ 隐藏 ” 列 时 ,优化程序可能会有 不同的 处理 方式 。 在连接中,隐藏列被计为结果的一部分(即使它们未显示),而在普通查询中,隐藏列不参与 DISTINCT 比较。

    一个例子是:

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

    和

    SELECT DISTINCT band_downloads.mp3id
           来自band_downloads,band_mp3
           在哪里band_downloads.userid = 9
           AND band_mp3.id = band_downloads.mp3id
           ORDER BY band_downloads.id DESC;
    

    在第二种情况下,您可能会在结果集中获得两个相同的行(因为隐藏 id 列中 的值 可能不同)。

    请注意,这仅适用 ORDER BY 于结果中 没有 列的 查询 。

  • 如果 PROCEDURE 对返回空集的查询 执行a ,则在某些情况下 PROCEDURE 不会对列进行转换。

  • 创建类型表 MERGE 不会检查基础表是否是兼容类型。

  • 如果您使用 ALTER TABLE 向 UNIQUE 表中使用的 MERGE 表添加索引,然后 在 表上添加普通索引,则 MERGE 表中的键顺序是不同的,如果表中存在旧的非 UNIQUE 键。 这是因为 在正常索引之前 ALTER TABLE 放置 UNIQUE 索引以便能够尽早检测重复键。

原文