New Page

mysql-logo.gif (3082 bytes) MySQL中文参考手册

整理:中华电脑书库 http://www.pcbookcn.com

推荐：透明网络--国际域名一级注册商，美国NAC、HE数据中心合作伙伴！
支持20多家银行60多种银行卡在线支付，立即到帐！特别提供美国主机，没有任何限制！

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

目录

0 译者序

MySQL是一个精巧的SQL数据库管理系统，虽然它不是开放源代码的产品，但在某些情况下你可以自由使用。由于它的强大功能、灵活性、丰富的应用编程接口（API）以及精巧的系统结构，受到了广大自由软件爱好者甚至是商业软件用户的青睐，特别是与Apache和PHP/PERL结合，为建立基于数据库的动态网站提供了强大动力。

MySQL有瑞典的T.c.X公司负责开发和维护，MySQL的用户手册很单纯，只有一个集中的<MySQL Reference Manual>，但其内容覆盖了MySQL的所有信息，因此该手册是了解和掌握MySQL的绝佳文献。

虽然对MySQL的开发不能出一份力，但可为它的推广使用尽一份心，面对500多页的参考手册，知道要精确译出它决非易事，但愿几个月的心血能为大家提供一丝微薄的帮助。

由于本人水平有限，文中肯定有不准确的地方，敬请在阅读过程中不吝指出。文中不明之处，请参阅手册原文。

本文的内容针对MySQL 3.23.7alpla，实际上很多内容是通用的。另外，参考手册的几个附录也是很有价值的，但由于时间有限，未能译出，可参见原文。

MySQL官方站点：http://www.mysql.com.

最新参考手册：http://www.mysql.com/doc.html

版权说明：本手册参考之原文的版权属T.c.X。而本手册可自由使用、修改、散发、转载和商业用途，但必须保留译者署名。

目录


MySQL中文参考手册- 1 mysql的一般信息

a:hover{color:red;} a.t1:visited{color:red;} -->

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

第一章,前一章，下一章, 最后一章, 目录.

1 MySQL 的一般信息

这是MySQL参考手册；它记载了MySQL版本3.23.7-alpha。

MySQL 是一个快速、多线程、多用户和强壮的SQL数据库服务器。

对Unix和 OS/2 平台，MySQL基本上是免费的；但对微软平台，你在30 天的试用期后必须获得一个MySQL 许可证。详见第三节 MySQL许可证和技术支持。

MySQL 主页提供有关MySQL的最新信息。

对于MySQL能力的讨论，详见1.4 MySQL 的主要特征。

对于安装指南，见4 安装 MySQL。对于有关移植MySQL到新机器或操作系统的技巧，参见G 对移植到其他系统的说明。

有关从 3.21 版升级的信息，详见4.16.2 从一个 3.21 版本升级到 3.22 。

MySQL的入门教程，见8 MySQL 教程。

SQL和基准信息的例子，见基准目录(在分发中的'sql-bench'目录)。

对于新特征和错误修复一个历史记录，见D MySQL的变迁。

对于当前已知错误和功能缺陷的一张列表，见E MySQL已知错误和设计缺陷。

未来计划，见F 我们想要在未来加入到MySQL 的计划表( TODO ）。

这个计划的所有贡献者的名单，见C MySQL 的贡献者。

重要：

将臭虫(错误)报告、问提和建议发到邮件列表（原文未提供）。

对源代码分发，mysqlbug 脚本可在‘scripts’目录下找到。 对二进制的分发，mysqlbug可在‘bin’目录下找到。

如果你有任何关于这本手册的增补或修正的任何建议，请将它们发给手册小组(docs@mysql.com )。

1.1 什么是 MySQL？

MySQL是一个真正的多用户、多线程SQL数据库服务器。SQL（结构化查询语言）是世界上最流行的和标准化的数据库语言。MySQL是以一个客户机/服务器结构的实现，它由一个服务器守护程序mysqld和很多不同的客户程序和库组成。

SQL是一种标准化的语言，它使得存储、更新和存取信息更容易。例如，你能用SQL语言为一个网站检索产品信息及存储顾客信息，同时MySQL也足够快和灵活以允许你存储记录文件和图像。

MySQL 主要目标是快速、健壮和易用。最初是因为我们需要这样一个SQL服务器，它能处理与任何可不昂贵硬件平台上提供数据库的厂家在一个数量级上的大型数据库，但速度更快，MySQL就开发出来。自1996年以来，我们一直都在使用MySQL，其环境有超过 40 个数据库，包含 10,000个表，其中500多个表超过7百万行，这大约有100 个吉字节(GB)的关键应用数据。

MySQL建立的基础是业已用在高要求的生产环境多年的一套实用例程。尽管MySQL仍在开发中，但它已经提供一个丰富和极其有用的功能集。

MySQL的官方发音是“My Ess Que Ell”(不是 MY-SEQUEL )。

1.2 关于本手册

目前这本手册有Texinfo、普通文本、Info、HTML、PostScript和 PDF 等格式的版本。因为它们的长度，PostScript和 PDF 版本没有包括在主要的MySQL分发中，但是可从http://www.mysql.com 获得单独的下载。

主要的文档是Texinfo文件， HTML版本自动地用一个texi2html改进版本生成。普通文本和Info版本用makeinfo生成。 Postscript版本由texi2dvi和dvips生成。PDF 版本用pdftex生成。

本手册由David Axmark, Michael (Monty) Widenius, Paul DuBois and Kim Aldale维护。 而其他的贡献者，见C MySQL贡献者。

1.2.1 本手册中使用的约定

这本手册使用了一定文字格式的约定：

constant / 固定宽度
固定宽度字体用于命令名字和选择、SQL语句、数据库、表和列命名、C 和 Perl 代码、环境变量。例如：“为了了解mysqladmin如何工作，用--help选项调用它”。
'文件名'
有包围引号的固定宽度字体用于文件名和路径。例如：“发行版本被安装在'/usr/local/'目录下”。
'c'
有包围引号的固定宽度字体也用于指明字符序列。例如：“要指定一个通配符，使用'%'字符”。
斜体
斜体的字体被用于强调，like this 。
粗体
粗体用于存取权限名字(例如，“不要轻易授权process权限”)并表达特别强调。

当命令显示出准备由一个特定的程序执行时，程序由命令所显示的提示符指出。例如，shell> 表明你从你的登录外壳执行一个命令，而mysql>表明你从mysql客户执行命令：

shell> 在这键入一个shell命令
mysql> 在这里键入一个mysql命令

shell命令用 Bourne shell语法显示。如果你正在使用csh风格的外壳，你可能需要用略微不同的方式发出命令。例如，设置一个环境变量和运行一个命令的序列在 Bourne shell语法看起来像这样：

shell> VARNAME=value some_command

对于csh，你将执行这样的序列：

shell> setenv VARNAME value
shell> some_command

数据库、表和列名字经常必须被代入命令中。为表明这种代入是必要的，本手册使用db_name、tbl_name和col_name。例如，你可能看到象这样的语句：

mysql> SELECT col_name FROM db_name.tbl_name;

这意味着如果你想输入类似的语句，你将提供你自己数据库、表和列的名字，也许像这样：

mysql> SELECT author_name FROM biblio_db.author_list;

SQL语句可以写成大写或小写的。当本手册显示SQL语句时，如果讨论这些关键字，大写被用于特定的关键字(强调它们)而小写被用于语句的其他部分。因此你可能在讨论SELECT语句时看到如下显示：

mysql> SELECT count(*) FROM tbl_name;

另一方面，在讨论COUNT()函数时，语句将写成这样：

mysql> select COUNT(*) from tbl_name;

如果不有意地特别强调，所有的关键字一律写成大写。

在句法描述中，方括号('['和']')被用来表示任选的词或子句：

DROP TABLE [IF EXISTS] tbl_name

当一个语法元素由很多选择组成时，各选择用垂直线分开('|')。当可能从一组选择中选择一个成员时，选择在方括号内被列出。当必须从一组选择中选择一个成员时，选择在花括号内被列出('{'和'}')：

TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)
{DESCRIBE | DESC} tbl_name {col_name | wild}

1.3 MySQL 的历史

我们曾经开始打算利用mSQL用我们自己的快速底层(ISAM)实用程序连接我们的数据库表，然而，在一些测试以后我们得到出结论：mSQL对我们的需求来说不够快速和灵活。这导致了一个连接我们数据库的新SQL接口，但它几乎有与mSQL相同的应用编程接口。选择这个应用编程接口以方便第三方的代码移植。

MySQL名字的由来不是非常清楚。我们的基目录和很多的库和工具具有前缀“my”已超过10年历史，然而，Monty的女儿(年轻几岁的)也被命名"my"。因此其中哪一个原因给MySQL起了这个名字仍然是一个谜，甚至对我们。

1.4 MySQL 的主要特征

下表描述MySQL一些重要的特征：

  • 使用核心线程的完全多线程。这意味着它能很容易地利用多CPU（如果有）。
  • C 、C++、 Eiffel 、 Java、 Perl、 PHP、Python、和 TCL API。见20 MySQL 客户工具和 API。
  • 可运行在不同的平台上，见4.2 MySQL支持的操作系统。
  • 多种列类型：1、 2、 3、4、和 8 字节长度的有符号/无符号整数、FLOAT、DOUBLE、CHAR、VARCHAR、TEXT、BLOB、DATE、TIME、DATETIME、 TIMESTAMP、YEAR、SET和ENUM类型。 见7.3 列类型。
  • 利用一个优化的一遍扫描多重联结（one-sweep multi-join）非常快速地进行联结(join)。
  • 在查询的SELECT和WHERE部分支持全部运算符和函数，例如：
    mysql> SELECT CONCAT(first_name, " ", last_name) FROM tbl_name
           WHERE income/dependents > 10000 AND age > 30;
  • 通过一个高度优化的类库实现SQL函数库并且像他们能达到的一样快速，通常在查询初始化后不应该有任何内存分配。
  • 全面支持SQL的GROUP BY和ORDER BY子句，支持聚合函数( COUNT()、COUNT(DISTINCT)、AVG()、STD()、SUM()、 MAX()和MIN() )。
  • 支持ANSI SQL的LEFT OUTER JOIN和ODBC语法。
  • 你可以在同一查询中混用来自不同数据库的表。(与版本 3.22一样 )。
  • 一个非常灵活且安全的权限和口令系统，并且它允许基于主机的认证。口令是安全的，因为当与一个服务器连接时，所有的口令传送被加密。
  • ODBC for Windiws 95。所有的 ODBC 2 . 5 函数和其他许多函数。例如，你可以用Access连接你的 MySQL服务器。见16 MySQL ODBC 支持。
  • 具备索引压缩的快速B树磁盘表。
  • 每个表允许有16个索引。每个索引可以由1～16个列或列的一部分组成。最大索引长度是 256 个字节(在编译MySQL时，它可以改变)。一个索引可以使用一个CHAR或VARCHAR字段的前缀。
  • 定长和变长记录。
  • 用作临时表的内存散列表。
  • 大数据库处理。我们正在对某些包含 50,000,000 个记录的数据库使用MySQL。
  • 所有列都有缺省值，你可以用INSERT插入一个表列的子集，那些没用明确给定值的列设置为他们的缺省值。
  • 为了可移植性使用 GNU Automake , Autoconf 和libtool。
  • 用C和C++编写，并用大量不同的编译器测试。
  • 一个非常快速的基于线程的内存分配系统。
  • 没有内存漏洞。用一个商用内存漏洞监测程序测试过(purify)。
  • 包括myisamchk，一个检查、优化和修复数据库表的快速实用程序，详见13 维护 MySQL安装。
  • 全面支持ISO-8859-1 Latin1 字符集。例如，斯堪的纳维亚的字符 @ringaccent{a}, @"a and @"o 在表和列名字被允许。
  • 所有数据以 ISO-8859-1 Latin1 格式保存。所有正常的字符串比较是忽略大小写的。
  • 根据 ISO-8859-1 Latin1 字符集进行排序(目前瑞典语的方式)。通过在源代码中增加排序顺序数组可以改变它。为了理解一个更高级的排序例子，看一看捷克语的排序代码。MySQL支持可在编译时指定的很多不同的字符集。
  • 表和列的别名符合 SQL92 标准。
  • DELETE、INSERT、REPLACE和UPDATE 返回有多少行被改变(受影响)。
  • 函数名不会与表或列名冲突。例如ABS是一个有效的列名字。对函数调用的唯一限制是函数名与随后的“(”不能有空格。详见7.31 MySQL对保留字很挑剔吗？。
  • 所有MySQL程序可以用选项--help或-?获得联机帮助。
  • 服务器能为客户提供多种语言的出错消息，详见9.1 MySQL支持哪些语言？。
  • 客户端使用TCP/IP 连接或Unix套接字（socket）或NT下的命名管道连接MySQL。
  • MySQL特有的SHOW命令可用来检索数据库、表和索引的信息，EXPLAIN命令可用来确定优化器如何解决一个查询。

1.5 MySQL的稳定性？

本小节回答这样的问题：“MySQL的稳定程度？”和 “我能在本项目中依赖MySQL吗?”。这里我们将试图澄清一些问题并且回答似乎很多人关心的更重要的问题。本节已经与从邮件列表(它在报导错误是很活跃的)收集了的信息综合在一起。

对TcX，MySQL在我们自1996中期开始的计划中运行没有发生任何问题。当MySQL被更公开地发布时，我们注意到了有一些 “未测试代码”片断很快地被不同于我们的查询方式的新用户发现。每个新版本比前一个都有更少的可移植性问题(尽管每个发行有许多新功能)，并且我们希望有可能把下一个版本之一标记为“稳定”的。

每个MySQL的发行都是可用的，并且只有当用户使用从“灰色地带”来的代码时才有问题，当然,不知情的用户不能知道灰色地带是什么；本小节尝试揭示我们目前已知的东西。这里的描述涉及MySQL 3. 22.x 版本。所有已知和报告的错误都会在最新的版本被更正，除了在错误小节中列出的与“设计n”有关的错误。详见E MySQL已知的错误和设计缺陷。

MySQL以多层结构和不同的独立模块编写，这些模块列举在下面以表明它们中的每一个是如何很好地被测试过：

ISAM表处理器--稳定
它管理所有在MySQL 3.22和早期版本中的数据的存储和检索。在所有MySQL版本中，代码中已经没有一个单独（报告的）错误。得到一个损坏的数据库表的唯一已知方法是在一个更新中途杀死服务器，即使这样也不大可能破坏任何数据而不能挽救，因为所有数据在每个查询之间被倒入(flush)到磁盘，而且从来没有一个有关由于MySQL中的错误而丢失数据的错误报告。
MyISAM 表处理器-- Beta
这是 MySQL 3.23的新功能，它大部分是基于ISAM表代码但有很多新的有用的功能。
语法处理器和词法分析器 --稳定
很长时间没有一个在这个系统中的错误报告。
C 客户代码--稳定
没有已知的问题。在早期的 3. 20版本中，在发送/接收缓冲器的大小上有一些限制。 3.21.x后，现在缓冲器的大小是动态的，可到一个24M的缺省值。
标准客户程序--稳定
这些包括mysql、mysqladmin和mysqlshow、mysqldump及mysqlimport。
基本结构式查询语言--稳定
基本SQL函数系统、字符串类和动态内存处理，本系统中未见单独报告的错误。
查询优化程序--稳定

范围优化程序-- Gamma

Join优化器--稳定

锁定-- Gamma
这是非常依赖于系统的，在某些系统上，用标准操作系统锁定(fcntl())有很大问题，在这些情况下，你应该用选项--skip-locking运行MySQL守护程序。当使用NFS挂载的文件系统，已知在一些 Linux 系统上和SunOS上出现问题。
Linux 线程-- Gamma
唯一发现的问题式fcntl()调用，它通过使用mysqld的--skip-locking选项解决。一些人已经报告了0.5版中的锁定问题。
Solaris 2.5 + pthreads --稳定
我们在我们的开发工作中使用。
MIT-pthreads (其他系统)-- Gamma
自从 3.20.15版以来，没有报告的错误，而且从3.20.16开始没有已知的错误。在一些系统上，在一些操作是相当慢时(在每查询之间有 1/20秒的睡眠 )有一个“功能失效”。当然，MIT-pthreads 可能使任何事情慢一点，但是基于索引的SELECT语句通常在一个时帧内完成，因此不应该有一个mutex 锁定/线程的把戏。
其他线程实现 -- Alpha - Beta
移植到其他系统仍然是很新的并且可能有错误，可能是在MySQL中，但是最通常的是线程实现本身。
LOAD DATA ... ,INSERT ... SELECT --稳定
一些人已经认为他们在这里发现了错误，但是这些经常多是误解。请在报告问题前检查手册！
ALTER TABLE --稳定
在 3.22.12中有小的改变。
DBD --稳定
现在由 Jochen Wiedmann 维护了。
mysqlaccess --稳定
由 Yves Carlier 编写并维护。
GRANT -- Gamma
MySQL 3.22.12.做了很大改变。
MyODBC （使用 ODBC SDK 2.5 )-- Gamma
它与一些程序似乎工作得很好。

TcX 为付费客户提供电子邮件的支持，但是MySQL邮件列表通常提供常见问题的答案，错误通常马上用一个补丁修补，对严重的错误，几乎总是有新的版本发行。

1.6 顺应2000年（Year 2000 compliance）

MySQL本身己没有2000年有问题( Y2K ):

  • MySQL使用Unix时间函数并且在2069年前没有日期问题, 所有2位年份被认为在1970年到2069年的范围，这意味着如果在一个year类型的列中存储的01，MySQL把它当作2001。
  • 所有MySQL日期函数存储在一个文件'sql/time.cc'中，并且很仔细地编码保证是2000年安全的 。
  • MySQL 3.22 和以后的版本，新的YEAR类型的列能在一个字节中存储0年和1901年到2155年，并用使用2或4位显示它们。

你可以用一种不是Y2K-safe的方式使用 MySQL应用程序来深入该问题。例如，许多老的应用程序使用2位数字(它有二义性)而非4位数字存储或操作年份，这个问题可能与使用诸如00或99作为“丢失的”值的提示的应用程序混淆起来。

很不幸，这些问题可能很难修复，因为不同的应用程序可能由不同程序员编写，其中每一个可能使用了不同的约定和日期处理函数。

这里是简单的示范，显示MySQL在 2030 年之前没有任何日期问题。

mysql> DROP TABLE IF EXISTS y2k;
mysql> CREATE TABLE y2k (date date, date_time datetime, time_stamp timestamp);
mysql> INSERT INTO y2k VALUES ("1998-12-31","1998-12-31 23:59:59",19981231235959);
mysql> INSERT INTO y2k VALUES ("1999-01-01","1999-01-01 00:00:00",19990101000000);
mysql> INSERT INTO y2k VALUES ("1999-09-09","1999-09-09 23:59:59",19990909235959);
mysql> INSERT INTO y2k VALUES ("2000-01-01","2000-01-01 00:00:00",20000101000000);
mysql> INSERT INTO y2k VALUES ("2000-02-28","2000-02-28 00:00:00",20000228000000);
mysql> INSERT INTO y2k VALUES ("2000-02-29","2000-02-29 00:00:00",20000229000000);
mysql> INSERT INTO y2k VALUES ("2000-03-01","2000-03-01 00:00:00",20000301000000);
mysql> INSERT INTO y2k VALUES ("2000-12-31","2000-12-31 23:59:59",20001231235959);
mysql> INSERT INTO y2k VALUES ("2001-01-01","2001-01-01 00:00:00",20010101000000);
mysql> INSERT INTO y2k VALUES ("2004-12-31","2004-12-31 23:59:59",20041231235959);
mysql> INSERT INTO y2k VALUES ("2005-01-01","2005-01-01 00:00:00",20050101000000);
mysql> INSERT INTO y2k VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000);
mysql> INSERT INTO y2k VALUES ("2050-01-01","2050-01-01 00:00:00",20500101000000);
mysql> SELECT * FROM y2k;
+------------+---------------------+----------------+
| date       | date_time           | time_stamp     |
+------------+---------------------+----------------+
| 1998-12-31 | 1998-12-31 23:59:59 | 19981231235959 |
| 1999-01-01 | 1999-01-01 00:00:00 | 19990101000000 |
| 1999-09-09 | 1999-09-09 23:59:59 | 19990909235959 |
| 2000-01-01 | 2000-01-01 00:00:00 | 20000101000000 |
| 2000-02-28 | 2000-02-28 00:00:00 | 20000228000000 |
| 2000-02-29 | 2000-02-29 00:00:00 | 20000229000000 |
| 2000-03-01 | 2000-03-01 00:00:00 | 20000301000000 |
| 2000-12-31 | 2000-12-31 23:59:59 | 20001231235959 |
| 2001-01-01 | 2001-01-01 00:00:00 | 20010101000000 |
| 2004-12-31 | 2004-12-31 23:59:59 | 20041231235959 |
| 2005-01-01 | 2005-01-01 00:00:00 | 20050101000000 |
| 2030-01-01 | 2030-01-01 00:00:00 | 20300101000000 |
| 2050-01-01 | 2050-01-01 00:00:00 | 00000000000000 |
+------------+---------------------+----------------+

13 rows in set (0.00 sec)

这表示DATE和DATETIME类型将不会有未来日期的任何问题(它们处理日期到 9999 )。

TIMESTAMP类型被用来存储当前时间，有一个仅2030-01-01的上限。TIMESTAMP在32位的机器上(有符号值)有一个从1970到2030的范围，在64位机器上它处理时间可达2106（无符号值)。

尽管MySQL是顺应Y2K的，但提供无二义性的输入是你的责任。对于MySQL处理二义性日期的输入(包含2位数字年份)的规则，详见7.3.6.1 Y2K 问题和日期类型。

1.7 SQL一般信息和教程

在MySQL邮件列表上，这本书被多人推荐：

Judith S. Bowman, Sandra L. Emerson and Marcy Darnovsky
The Practical SQL Handbook: Using Structured Query Language
Second Edition
Addison-Wesley
ISBN 0-201-62623-3
http://www.awl.com

这本书也接受了 MySQL 用户的一些建议：

Martin Gruber
Understanding SQL
ISBN 0-89588-644-8
Publisher Sybex 510 523 8233
Alameda, CA USA

一本SQL语言教程可在 http://www.geocities.com/SiliconValley/Vista/2207/sql1.html 找到。

SQL in 21 Tagen (用德语写的网上书籍) http://www.mut.de/leseecke/buecher/sql/inhalt.htm 。

1.8 有用的MySQL相关链接

1.8.1 教程

  • A beginner's tutoral of how to start using MySQL
  • http://www.analysisandsolutions.com/code/mybasic.htm 新手如何在一台Windows 机器上安装和设置MySQL。
  • 很多MySQL教程
  • 建立一个基于 MySQL的网站
  • MySQL- perl 教程
  • PHP/MySQL 教程

1.8.2 Perl相关链接

  • MySQL 的Perl DBI FAQ

1.8.3 MySQL 讨论论坛

  • 使用MySQL实例 (check Top 20)

1.8.4 支持 MySQL 的商业应用

  • SupportWizard; Interactive helpdesk on the web (This product includes a licensed copy of MySQL)
  • Right Now Web; Web automation for customer service
  • Bazaar; Interactive Discussion Forums with web interface
  • PhoneSweepT 是世界的第一个商业电话扫描仪.近年来的很多侵入不是通过因特网，而是通过非法的拨号调制解调器. PhoneSweep 让你通过循环地将电话发到你的公司控制的每个号码上来发现这些调制解调器， PhoneSweep有一个内置的专家系统，能识别出超过 250 种不同类型的遥远存取程序，包括Carbon CopyT 、pcANYWHERET 和 Windows NT RAS .所有信息保存在SQL数据库，最后产生一份详细易懂的报告，说明你公司内那个拨号调制解调器的那项服务被刺探。

1.8.5 SQL客户程序

  • 微软Windows 平台上MySQL编辑器/实用程序
  • KDE MySQL 客户
  • Kiosk：一个用于数据库管理的 MySQL客户 用 Perl编写，将成为Bazaar的一部分。

1.8.6 支持MySQL的Web 开发工具

  • PHP ：一种服务器端的嵌入HTML的脚本语言
  • Midgard 应用服务器：基于 MySQL 和 PHP强大的网站开发环境
  • SmartWorker 是一个Web应用开发平台
  • XSP： e(X)tendible (s)erver (p)ages ：是一个用Java 编写的嵌入 HTML的标签语言(以前 XTAGS出名)
  • dbServ：是对Web服务器的扩充，它将到数据库输出集成进你的 HTML编码。你可以在你的输出使用任何 HTML函数，只有客户端能阻止你。它作为独立的服务器或作为 Java servlet 运行。
  • Chili!Soft 平台无关的ASP
  • MySQL + PHP demos
  • ForwardSQL：操作的MySQL数据库的 HTML 接口
  • WWW-SQL：显示数据库信息
  • Minivend ：Web购物车
  • HeiTML：是HTML的服务器端扩充，同时又是一种第四代语言语言
  • Metahtml：一种WWW应用程序的动态编程语言
  • VelocityGen for Perl and TCL
  • Hawkeye 因特网服务器套件
  • Linux网络数据库连接
  • WDBI：是作为一个很好支持MySQL数据库的通用前端的Web浏览器
  • WebGroove 脚本： HTML编译器和服务器端脚本语言
  • 一种服务器端网站脚本语言
  • 怎样在 Solaris 上用Coldfusion使用MySQL
  • Calistra 的 ODBC MySQL管理器
  • Webmerger：这个CGI工具解释文件并且生成基于一套简单标签的动态输出，通过 ODBC 提供MySQL和PostgreSQL的Ready-to-run 驱动程序。
  • PHPclub：PHP 的技巧
  • MySQL 和 Perl 脚本
  • Widgetchuck ：网站工具和小配件
  • AdCycle：广告管理软件

1.8.7 用 MySQL 支持的数据库设计工具

  • "Dezign for databases" 是使用一个实体关系图表的数据库开发工具( ERD ).

1.8.8 使用MySQL工具的Web服务器

  • 一个 Apache 认证模块
  • The Roxen Challenger Web server

1.8.9 对其他程序的扩充

  • 一个有源代码的MySQL的 Delphi 接口. 由 Matthias Fichtner 编写。
  • TmySQL：一个通过Delphi使用MySQL的库
  • Delphi TDataset部件
  • 支持BIND(Internel域名服务器）
  • 使用 MySQL 的 Sendmail扩充

1.8.10 通过其他程序使用MySQL

  • 通过Access使用 MySQL

1.8.11 ODBC有关的链接

  • 流行的 iODBC 驱动程序( libiodbc )现在以开放源代码获得
  • FreeODBC 主页

1.8.12 API有关的链接

  • www.jppp.com：为MySQL部分实现了TDataset兼容的部件。
  • qpopmysql：一个允许MySQL数据库进行 POP3 认证补丁。还有一个到Paul Khavkine的Procmail补丁的连接，允许任何MTA向MySQL数据库中的用户投递信件。
  • 针对Active X的Visual Basic 类生成器
  • Macintosh 的客户库
  • Free Pascal的MySQL绑定
  • SCMDB：SCMDB 是SCM的一个插件，SCM移植 mysql的C语言库到概念框架(scheme)。利用这个库，框架开发者能连接到一个mySQL数据库并且在他们的程序钟使用嵌入式SQL。

1.8.13 其它MySQLx有关的链接

  • Registry of Web providers who support MySQL
  • Links about using MySQL / MySQL in Japan/Asia
  • Commercial Web defect tracking system
  • PTS: Project Tracking System
  • Job and software tracking system
  • ExportSQL: A script to export data from Access95+
  • SAL (Scientific Applications on Linux) MySQL entry
  • A consulting company which mentions MySQL in the right company
  • PMP Computer Solutions. Database developers using MySQL and mSQL
  • Airborne Early Warning Association
  • MySQL UDF Registry
  • Y2K tester

1.8.14 SQL和数据库接口

  • KMySQL：KMySQL 是主要支持MySQL的KDE数据库库护程序。
  • JDBC 数据库存取应用程序接口
  • mSQL TCL 补丁
  • EasySQL :一个类ODBC驱动程序管理器
  • SQL数据库的一个 REXX 接口
  • TCL 接口

1.8.15 使用MySQL的例子

  • Little6 Inc An online contract and job finding site that is powered by MySQL, PHP3 and Linux.
  • DELECis A tool which makes it very easy to create an automatically generated table documentation. They have used MySQL as an example.
  • Steve Fambro Uses MySQL and webmerger. There is an employee database, and a license plate database with all of the registered Utah vehicles (over 1.2 million). The License plate field is indexed.....so the *searches* are instantaneous.
  • World Records A search engine for information about music that uses MySQL and PHP.
  • A Contact Database using MySQL and PHP
  • Web based interface and Community Calender with PHP
  • Perl package to generate html from a SQL table structure and for generating SQL statements from an html form.
  • Basic telephone database using DBI/DBD.
  • Installing new Perl modules that require locally installed modules
  • JDBC examples by Daniel K. Schneider
  • SQL BNF
  • Object Oriented Concepts Inc; CORBA applications with examples in source
  • DBWiz; Includes an example of how to manage own cursors in VB
  • Pluribus Pluribus, is a free search engine that learns to improve the quality of its results over time. Pluribus works by recording which pages a user prefers among those returned for a query. A user votes for a page by selecting it; Pluribus then uses that knowledge to improve the quality of the results when someone else submits the same (or similar) query. Uses PHP and MySQL.
  • Stopbit A technology news site using MySQL and PHP
  • Example scripts at Jokes2000
  • FutureForum Web Discussion Software
  • http://www.linuxsupportline.com/~kalendar/ KDE based calendar manager The calendar manager has both single user (file based) and multi user (MySQL database) support.
  • Example of storing/retrieving images with MySQL and CGI
  • Online shopping cart system
  • Old Photo Album The album is a collaborative popular history of photography project that generates all pages from data stored in a MySQL database. Pages are dynamically generated through a php3 interface to the database content. Users contribute images and descriptions. Contributed images are stored on the web server to avoid storing them in the database as BLOBs. All other information is stored in on the shared MySQL server.

1.8.16 一般的数据库链接

  • Database Jump Site
  • Homepage of the webdb-l (Web Databases) mailing list.
  • Perl DBI/DBD modules homepage
  • Cygwin tools. UNIX on top of Windows
  • dbasecentral.com; Development and distribution of powerful and easy-to-use database applications and systems.
  • Tek-Tips Forums Tek-Tips Forums are 800+ independent peer-to-peer non-commercial support forums for Computer Professionals. Features include automatic e-mail notification of responses, a links library, and member confidentiality guaranteed.

也有很多网页使用 MySQL。详见A 一些 MySQL 用户。将任何新增发送到这张表中，并在某处加上 MySQL 标识(在一个“使用工具”的页面或类似的地方)。

第一章,前一章，下一章, 最后一章, 目录.


MySQL中文参考手册- 2 MySQL邮件列表及如何提问或报告错误

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

第一章, 前一章, 下一章, 最后一章，目录.

2 MySQL邮件列表及如何提问或报告错误

2.1 MySQL 邮件列表

要订阅主 MySQL 邮件列表，送一条消息到电子邮件地址 mysql-subscribe@lists.mysql.com 。

要退订主 MySQL 邮件列表，送一条消息到电子邮件地址 mysql-unsubscribe@lists.mysql.com 。

只有你发送消息的地址是有意义的，消息的主题行和正文将被忽略。

如果你的回复地址不是有效的，你可以明确地指定地址。把短横加到订阅或退订命令词，随后是你的地址，“@”由一个字符“=”代替。例如，要订阅到john@host.domain，送一条消息到mysql-subscribe-john=host.domain@lists.mysql.com。

邮寄到 mysql-subscribe@lists.mysql.com 或 ezmlm 邮件列表处理器。详细信息可在 ezmlm 网点得到。

要想邮寄一条消息到列表本身，发送你的消息到 mysql@lists.mysql.com。然而，请千万不要将关于订阅或退订的邮件发到mysql@lists.mysql.com ，因为送到该地址的任何邮件被自动地被散发到上千个其他用户。

你本地的网站可能有很多 mysql@lists.mysql.com 的订户，如果这样，也可能有一个本地邮件列表，以便使从 lists.mysql.com 发到你网站的消息被传送到你的本地列表。在这种情况下，请联系你的系统主管加入本地 MySQL 列表和从其中删除。

已有下列 MySQL 邮件列表：

announce
这是MySQL新版本和相关程序的发布通知,这是小信息量的列表，我们认为所有的 MySQL 用户应该订阅。
mysql
为一般 MySQL 讨论的主列表。请注意一些话题最好在更专业的列表上讨论。如果你邮寄到错误的列表上，你可能得不到回答！
mysql digest
文摘形式的mysql列表，这意味着你得到所有单个消息，作为一个大邮件一天发送一次。
java
讨论 MySQL 和 Java ，主要关于 JDBC 驱动程序。
java digest
一个文摘版本java 列表。
win32
有关微软操作系统上例如 Windows NT的 MySQL所有东西。
win32 digest
一个文摘版本win32表。
myodbc
有关用 ODBC联接 MySQL 的所有东西。
myodbc digest
一个文摘版本 myodbc 列表。
msql-mysql-modules
关于 MySQL中对Perl支持的一个列表。
msql-mysql-modules-digest
一个文摘版本 msql-mysql-modules 列表。
developer
为开发 MySQL 原代码的人的一个列表。
developer digest
一个文摘版本developer列表.

你可用上述的方法订阅或退订所有列表。在你的订阅或退订消息中，只是放入不是mysql的适当邮件列表名。例如，订阅或退订myodbc列表，送一条消息到（原文未提供）。

2.2 提问或报告错误

在邮寄一份错误报告或问题前，请按下列步骤做：

  • 由寻找 MySQL 联机的手册开始：
     http://www.mysql.com/Manual_chapter/manual_toc.html

    我们通过经常以新发现的问题的解决方法更新手册，努力使它是最新的！

  • 搜索 MySQL 邮件列表档案：
     http://www.mysql.com/doc.html
  • 你也可使用 http://www.mysql.com/search.html 寻找在http://www.mysql.com/下的网页(包括手册)。

如果你不能在手册或档案发现答案，检查你本地的 MySQL 专家。如果你仍然不能发现你问题的答案，继续读下一节关于怎样发送邮件到 （原文未提供）。

2.3 怎样报告错误或问题

写一份好的错误报告需要耐心，但是第一次就做得正确可节省你我的时间。本节将帮助你正确撰写你的报告，以使你不浪费时间，也可能做一些根本不能帮助我们的事情。

如果可能的话，我们鼓励每个人使用 mysqlbug 脚本产生一份错误报告(或关于任何问题的一份报告)。mysqlbug可在源代码分发或二进制分发的 MySQL安装目录下的'bin'目录中的'scripts' 目录下找到。如果你不能使用mysqlbug，你仍然应该包括在本节列出的所有必要的信息。

mysqlbug 脚本通过自动确定下列很多信息来帮助你生成一份报告，但是如果一些重要的东西不见了，请在你的消息中包含它！请仔细阅读本节并且保证这里描述的所有信息包含在你的报告中。

要记住，有可能回复一条包含太多的信息消息，但不回复包含极少信息的消息，因为人们认为他们知道一个问题的原因并且假设某些细节无所谓，所以他们常常忽略事实。一个好的原则是：如果你怀疑所说的事情，继续说！在你的报告中写上几行，比因为第一次没有包含足够的信息而被迫追问和等待答案要快上千倍，而且少些麻烦。

最常见的错误是人们不指出他们正在使用的MySQL分发的版本号，或不指出在什么平台上平台安装了 MySQL (包括平台版本号)。这是极其相关的信息，并且没有它99%错误报告是无用的！我们经常得到这样的提问“为什么它不给我工作?”，然后我们发现所需的功能还没有在该版本的 MySQL 中实现，或在一份报告中描述的一个错误已经在更新的MySQL 版本修正了。有时错误是依赖于平台，在这种情况下，不知道平台操作系统和版本号根本不可能修正任何东西。

还要记住，要提供你的编译器信息，如果它与问题有关。人们经常发现错在编译器而认为MySQL的问题。大多数编译器始终都在开发中并且随版本也逐渐变得更好。为了确定决定你的问题是否依赖于你的编译器，我们需要知道使用什么编译器。注意每个编译器得问题应该被认为是一个错误，因此要报告。

在错误报告中包含一个问题的完好描述是最有帮助的。即，你所做的导致这个问题的一个好的例子和确切描述的问题本身。最好的报告是包括显示如何再次产生错误或问题的一个完整例子。

如果一个程序产生一条错误信息，非常重要的是在你的错误报告中要包含它！如果我们试着从使用程序的档案中找一些东西，最好是报告的错误消息精确地匹配程序所产生的。（甚至注意大小写！)你决不应该试图记住错误消息是什么，相反，将全部消息拷贝并且粘贴进你的报告中！

如果你有一个MyODBC问题，你应该尝试产生一个 MyODBC 跟踪文件，详见16.6 报告 MyODBC的问题.

请记住，将要阅读你报告的人有很多使用80列显示。在产生报告或使用mysql命令行工具的例子时，你应该为那些可能超出显示可用宽度的输出(例如，EXPLAIN SELECT语句，见下面的例子)使用--vertical选项(或\G语句终止符)。

请在你的报告中包括下列信息：

  • 你正在使用的 MySQL 分发的版本号(例如， MySQL 3.22.22 )。你可以执行mysqladmin version找到你正在运行哪个版本。mysqladmin可以在你的MySQL安装目录的'bin'目录下面找到。
  • 你正在使用的机器的制造商和型号。
  • 操作系统名字和版本。对大多数操作系统，你可以通过执行一条Unix命令uname -a 得到有关信息。
  • 有时存储器的数量(物理和虚拟的)是有意义的，如果有疑问，包含这些值。
  • 如果你正在使用一个MySQL源代码分发 ，则需要使用的编译器的名称和版本号。如果你有一个二进制代码的分发，就需要该分发的名字。
  • 如果问题在编译期间发生，则包含准确的错误消息，并且也包含问题发生的文件中出错代码周围的一些上下文。
  • 如果任何数据库表与问题有关，包含从 mysqldump --db_name  tbl_name1  tbl_name2 …的输出结果。这是很容易做到的，并且它是一个获得有关任何数据库表信息的有效方法，将帮助我们创造一个匹配你所遇到问题的环境。
  • 对于与速度或SELECT语句有关的问题，你总是应该包括EXPLAIN SELECT．．．的输出和至少SELECT语句产生的行数。你给出有关你的情况越多的信息，某些人越能帮助你。例如，下列的例子是一份很好的错误报告(当然它应该用与 mysqlbug 脚本邮寄)：运行 mysql 命令行工具的例子(注意对其输出超过80列显示设备的语句使用\G终止符)：
    mysql> SHOW VARIABLES;
mysql> SHOW COLUMNS FROM ...\G
       <output-from-SHOW-COLUMNS>
mysql> EXPLAIN SELECT ...\G
       <output-from-EXPLAIN>
mysql> FLUSH STATUS;
mysql> SELECT ...;
       <A short version of the output from SELECT,
       including the time taken to run the query>
mysql> SHOW STATUS;
       <output from SHOW STATUS>
  • 如果在运行 MySQL 时是发生问题，尝试一下提供一个重现问题的输入脚本，该脚本应该包括任何必要的源文件，重现你情况的脚本越准确越好。如果你不能提供脚本，你至少应该在你的邮件中包括从 mysqladmin variables extended-status processlist的输出以提供你的系统怎样运行！
  • 如果你认为 MySQL 产生一个奇怪的查询结果，不仅要包含结果，而且也要包含应该是什么结果的意见和描述你意见所依据的理由。
  • 当给出问题的一个例子时，最好使用在你的真实情况下的而不是一个新的变量名、表名等等。这个问题应该与一个变量的名、表等有关！也许这些条件是苛刻的，但是安全比担心更好。不管怎么说，提供使用你实际情况的例子应该比较容易，并且各方面来讲它对我们更好一些。如果你有不想把数据显示别人看，你可使用ftp把它上传到ftp://www.mysql.com/pub/mysql/secret/。如果数据确实是高度机密的，甚至不想让我们看到它们，那么继续，并提供使用其它名字的例子，但是请注意这是最后选择。
  • 如果可能，包括相关程序的所有选项，例如，指明你启动 mysqld 守护程序和运行任何 MySQL 客户程序所使用的选项，对象mysqld 和 mysql等程序和configure 的选项常常是答案的关键和至关重要的！包括他们绝对不是一个坏主意！如果你使用任何模块，例如Perl或PHP，请也包括它们的版本号。
  • 如果你不能产生一个行数少的测试，或如果测试表太大，不能寄给邮件列表(超过10行),你应该使用mysqldump倒出(dump)数据库表并且创建“README”文件描述你的问题，用tar和gzip造创建你的文件的一个压缩的档案，并且使用ftp把档案文件转移到ftp://www.mysql.com/pub/mysql/secret/，然后把问题的简短描述发到mysql@lists.mysql.com 。
  • 如果你的问题与权限系统有关。请包括mysqlaccess 、mysqladmin reload的输出和所有尝试连接时得到的错误消息！当你测试你的权限时，你应该首先运行mysqlaccess。在这以后，执行 mysqladmin reload version，最后你应该尝试用你有问题的程序进行连接。 mysqlaccess 可在你的 MySQL 安装目录下的“bin”目录找到。
  • 如果你有一个对错误的补丁程序，那最好，但是千万别假设补丁程序是我们需要的一切，或即使你不提供一些必要信息如补丁能修正的错误的前提条件，就可使用它。我们可能发现你的补丁程序问题，或者我们可能根本不理解它。如果是这样，我们不能使用它。在这里测试条件将帮助我们，这意味着补丁程序将处理一切可能出现的情况。如果我们发现了补丁不能工作的边界条件（即使很怪），它可能毫无用处。
  • 对错误是什么、为什么发生或它依赖什么的猜测通常是错误的。我们甚至不能在没有首先使用一个调试器以确定一个错误的真正原因时做这种猜测。
  • 在你的邮件消息说明你已经检查了参考手册和邮件归档，以便让其他人知道你自己尝试解决你的问题。
  • 如果你得到一个parse error，请仔细检查你的语法！如果你不能它发现有什么不对，极有可能是你当前 MySQL 版本不支持你正在使用的查询。如果你正在使用最新版而且 http://www.mysql.com/doc.html 的参考手册没有涉及你正在使用的语法， MySQL 就不支持你的查询。在这种情况下，你唯一的选择是自己实现语法并邮寄过来。如果手册涉及你正在使用的语法，但是你有一个更旧版本的 MySQL ，你应该检查 MySQL 的更新历史来找出语法何时被实现。见D MySQL 变迁历史。这时你有升级到一个更新 MySQL版本的选择。
  • 如果你有一个这样的问题：当你存取某些特定数据库表时，你的数据好像已破坏或出错，你应该首先用myisamchk检查然后尝试修复你的数据库表。见 13 维护 MySQL 安装.
  • 你经常得到破坏了的数据库表，你应该尝试发现这何时和为何发生！此时“mysql-data-directory/'hostname'.err”文件可能包含所发生事情的一些信息。请在你的错误报告包含这个文件的任何有用信息！如果没有在更新当中杀死了mysqld，通常应该绝对不破坏数据库表！如果你能找出mysqld为什么死掉的原因，对于我们，更容易向你提供对问题的修正！
  • 如果可能，下载最新版本的 MySQL ，并且检查它是否解决你的问题。MySQL的所有版本都被彻底地测试并且应该毫无问题地运行！我们相信使一切尽可能向后兼容，并且你应该能在数分钟内切换 MySQL 版本！见 4.3 要使用 MySQL 哪个版本。

如果你是一个支持客户，请直接邮寄错误报告到适当的邮件列表，看看是否有其他人有这个问题的经验（或许已经解决）。

对于报导MyODBC错误的信息，见 16.2 怎样报告 MyODBC 问题。

一些常见问题的答案，见 18 问题和常见的错误。

当答案个别发给你而不是邮件列表时，总结答案并且将总结发到邮件列表以便其它人可以从你收到的帮助你解决问题的答案中受益，这被认为是一个很好的规矩。

2.4 在邮件列表上回答问题的指南

如果你认为你的答案引起广泛的兴趣，你可能想要把它寄到邮件列表中而不是直接答复提问的人。试着让你的答案足够普遍，让不是邮寄者的其他人可从它获益。当你邮寄到邮件列表时，请保证你的回答不和以前的答案重复。

尝试总结在你的答复中的问题的主要部分，别感觉不好意思引用全部原文消息。

请不要从有 HTML 模式的浏览器投寄邮件消息！许多用户不用浏览器读邮件！

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-3 MySQL许可证和技术支持

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

第一章,前一章,下一章,最后一章，目录.

3 MySQL的许可证和技术支持

本章描述 MySQL 许可证和技术支持安排，包括：

  • 我们对于非微软和微软操作系统许可证的政策；
  • MySQL 分发遵从的版权(见3.2 MySQL 使用的版权)；
  • 当申请一个许可证时，演示一个例子(见3.4 许可证实例）；
  • 许可证和支持费用(见3.5 MySQL 的许可证和技术支持费用)，及技术支持的好处(见 3.6 商业性支持的类型）；

3.1 MySQL的许可证政策

针对非微软操作系统如Unix或 OS/2 的许可证的正式条款在 J 针对非微软操作系统的 MySQL 服务器许可证中说明。基本上，我们许可证政策如下：

  • 对于一般的内部使用，MySQL通常是免费的。如果你不想，就不必付钱给我们。
  • 一个许可证是必需的，如果：
    • 你直接销售MySQL服务器或作为其他产品或服务的一部分；
    • 你在某些客户那里为了安装和维护一个 MySQL 服务器而收费；
    • 你在不可再分发的分发中包括 MySQL并且你对该分发的某些部分收费；
  • 在必须有 MySQL 许可证的情况下，对每台运行mysqld服务器的机器，你都需要一个许可证，但多CPU机器按单CPU计算，并且在一台机器上运行 MySQL 服务器的数量或并发连接到这台运行一个服务器的机器的客户数量也无限制！
  • 你在商业程序中包含客户代码不需要一个许可证，MySQL的客户端存取部分不属公共领域，mysql命令行客户程序包含在 GNU 通用许可证下的 readline 库的代码。
  • 对于已经购买了 10 个许可证或一种足够级别的技术支持的消费者，我们提供附加的功能。目前，这意味着我们提供 myisampack实用工具，它能生成快速的压缩的只读数据库（服务器支持读取这样的数据库，但不包含用于生成它们的压缩工具)。当支持协议产生了足够的收入时，我们将在与MySQL 服务器同样的许可证下发行这个工具。
  • 如果你使用不需要一个许可证的 MySQL，但是你的确喜欢 MySQL 并且有志于更进一步的开发，无论如何肯定欢迎你购买一个许可证。
  • 如果你在一个商业环境中使用 MySQL以便通过它获利，我们要求你购买一定级别的技术支持以推进开发。我们感到，如果 MySQL 有助于你的业务，要求你帮助MySQL也是合理的（否则，如果向我们你询问支持问题，你不仅是正在免费使用我们倾注大量精力的产品，而且你正在要求我们提供免费的支持。）。

对于在微软操作系统下面( Win95/Win98/WinNT)的使用，你在一个 30 天的试用期后需要一个 MySQL 许可证，除了教育用途或大学或政府资助的研究机构的许可证可免费申请获得，见 K 针对微软操作系统的 MySQL 许可证。一个共享软件版本的 MySQL -Win32 可在购买前从 http://www.mysql.com/mysql_w32.htmy 下载试用。在你付钱后，你将得到一个口令让你能够访问最新 MySQL - Win32 版本。

如果你对你特定的 MySQL使用是否需要一个许可证有任何问题，请联系我们，见 3.5.2 联系信息.

如果你需要一个 MySQL 许可证，最容易的付款方法是使用在 https://www.mysql.com/license.htmy网站的 Tcx 的安全服务器上的许可证表格。其他付费形式在3.5.1 付款信息讨论。

3.2 MySQL使用的版权

MySQL 分发有若干不同的版权：

  1. 构造mysqlclient库和“client”目录下的程序所需的MySQL特定源代码使属于公共领域(public domain)，属于公共领域的每个文件有一个文件头清楚地说明这点。这包括在“client”目录下的所有东西和mysys、mystring和dbug库的某些部分。
  2. 源代码的某一小部分( GNU  getopt)遵从“ GNU 库文件通用许可证(GLPL)”，参见"mysys/COPYING.LIB"文件。
  3. 原代码的某一小部分( GNU  readline)遵从“ GNU 公共许可证”。见"readline/COPYING"文件。
  4. 源代码的某些部分(regexp 库)遵从Berkerley风格的版权。
  5. 在非微软平台上的MySQL服务器所需的其他源代码遵从“ MySQL 自由公共许可证”，它基于“阿拉丁自由公共许可证”。见J 针对非微软操作系统的 MySQL 服务器许可证。当在任何微软操作系统上运行MySQL时，使用另外的许可证。

下列几点阐明了我们的版权政策后的理念：

  • SQL客户库应该是完全免费的，以使它能不受限制地包含在商业产品中。
  • 想要自由存取我们花了很多精力开发的软件的任何人都可以拥有它，只要他们不试图借助分发它以盈利为目而直接赚钱。
  • 想要有权保护他们自己的软件专利，但也从我们的工作得到价值的任何人，可以为此权力付费。
  • 这意味着正常的家庭使用是免费的，但是如果你为一些对你很重要的事使用 MySQL，你可以通过购买一个许可证或一个技术支持合同来帮助进一步开发它。见3.6 商业性支持的类型。

3.2.1 可能的未来版权改变

我们可能在将来用GPL分发较老的 MySQL 版本，然而，这些版本将被标明为 GNU MySQL。另外，在相关文件的所有版权通告将改为 GPL 。

3.3 MySQL商业性分发

本节澄清“ MySQL 自由公共许可证”( FPL )中提出的许可证条款。见 J 针对非微软操作系统的 MySQL 服务器许可证。

MySQL可以是自由地使用，包括被商业实体的评估或不受支持的内部使用。然而，MySQL商业目的分发，或任何部分或全部包含或从MySQL派生的东西，都需要从 TcX AB 申请一个书面的商业许可证，它是唯一的授权发证实体。

你不能“免费”地在一个含有任何收费的东西的软件包中包含MySQL，但下面所说的除外。

在许可证的第二款提供了例外的目的是允许运营一个FTP服务器或公告牌的商业组织免费分发 MySQL，如果：

  1. 该组织遵守 FPL 的其他条款，其中包括要求分发 MySQL 和任何派生产品的全部源代码，并且与MySQL一起分发FPL本身；
  2. 为下载 MySQL 的唯一费用是基于分发服务的费用，而不是基于正在被检索的信息内容(即，费用应该与检索同样大小的随机位组合是一样的)；
  3. 服务器或BBS可由一般公众访问，即，电话号码或IP地址没被保密，且任何人可以获得信息的存取(可能通过交订费或存取费用，该费用不依赖于或相关于购买其他东西)。

如果你想要以商业形式分发集成了MySQL的软件，并且你不想满足这些条件，你应该联系 TcX AB 寻求商业许可证，它涉及付费。你能合法地分发 MySQL 或任何包含 MySQL的东西的唯一方法是在FPL的要求下分发 MySQL，或通过从 TcX AB 获得一个商业许可证。

3.4 许可证实例

本节描述一些实例以阐述你是否许可使用 MySQL，通常这些例子包括提供 MySQL 服务器作为一个产品的一部分，或你正在向客户销售服务，或要求 MySQL与你的产品一起使用。在这些的情况中，如果必要，为客户申请一个许可证是你的责任。（如果你的客户已经有了 MySQL 许可证，这个要求就不考虑了，但是卖方必须将客户信息和和许可证号传到TcX，并且许可证必须是一个完整的许可证，而不是一个OEM许可证。）

注意单个 MySQL 许可证涵盖了一台机器上的任何数量的CPU/用户/客户的mysqld的服务器！

3.4.1 销售使用MySQL的产品

要确定在销售你的应用程序时，你是否需要一个 MySQL 许可证，你应该询问，应用程序的正确运行是否可能使用 MySQL ，且你是否在你的产品中包括 MySQL 。有几种情况要考虑：

  • 你的应用是否需要 MySQL 才能正确工作？如果你的产品需要 MySQL，对于任何运行mysqld服务器的机器，你都需要一个许可证。例如，如果你已经围绕MySQL设计了应用，然后你确实开发了需要该引擎的一个商业产品，因此你需要一个许可证。如果你的应用不需要 MySQL，你不必获得一个许可证。例如，如果 MySQL 只是为你的产品加入一些新的可选功能(例如，如果 MySQL被用来增加日志到数据库中，而不是记录到一个文本文件中)，它应该在正常使用范围内，并且不需要一个许可证。换句话说，如果你销售为MySQL 而专门设计的或需要MySQL才能运行的产品，你需要一个许可证，不管你是否是为你的客户提供 MySQL来作为你产品的一部分，这也取决于你在为你的客户做什么。你计划为你的客户提供与软件一起安装 MySQL详细的指令吗？那么你的产品可能使用 MySQL，如果是，你需要购买一个许可证。如果你简单地连接在购买你的软件时你希望已经安装数据库的话，那么你可能不需要一个许可证。
  • 你在一个分发中包括 MySQL并对此分发收费吗？如果你在销售给客户的分发中包括 MySQL ，对每台运行mysqld服务器的机器，你都将需要一个许可证，因为在这种情况下，你正在销售一个包括 MySQL的系统，不管与你的产品一起使用 MySQL是你必需的或可选的。
  • 你的产品既不需要也不包含 MySQL 吗？假定你想销售一个产品，它设计成通用的以使用“某些数据库”并且能被配置成可使用它支持的多个其他数据库选择( MySQL， PostgreSQL，或其他)，即，你的产品不需要 MySQL，但是能支持任何基本功能水平的数据库，且你不依赖任何只有 MySQL 才支持的东西。如果你的客户实际上确实选择使用MySQL，你们中有人欠我们钱吗？在这种情况下，如果你不提供，为客户获得或设置 MySQL 应由客户决定是否使用它，你也不需要一个许可证。如果你确实施行那种服务，见3.4.2 销售MySQL 相关的服务。

3.4.2 销售MySQL相关的服务

如果你在一个客户机器上安装 MySQL 并为此服务收费(直接或间接地)，那么你必须购买一个 MySQL 许可证。

如果你销售一个应用，而 MySQL 不是完全需要但是能被使用，可能要出示一个许可证，这取决于怎样建立 MySQL。假如你的产品既不需要 MySQL 也不在你的产品分发包含它，但是可以为有这种愿望的那些客户配置成使用 MySQL。（例如，你的产品可以使用任何数据库引擎的一个，可能就是这种情况。）

如果客户得到并且安装 MySQL，不需要许可证。如果你为你的客户施行这种服务，那么就需要一个许可证，因为你正在销售一种包含 MySQL 的服务。

3.4.3 ISP MySQL 服务

因特网服务供应商(ISP)经常为他们的客户配备 MySQL 服务器。

如果你是一个ISP，允许客户自己在没有你帮助的情况下安装并且管理你机器上的MySQL，你和你的客户都不需要一个MySQL 许可证。

如果你对作为你客户服务一部分的 MySQL安装和管理的支持收费，那么因为你正在销售一种包括 MySQL服务，你需要一个许可证。

3.4.4 运营一个使用 MySQL的Web服务器

如果你与一个Web服务器一起使用 MySQL，你不必支付一个许可证费用。

就算你运营使用 MySQL的一个商业Web服务器，也是这样的，因为你不在销售 MySQL 本身。然而，在这种情况下，我们希望你购买 MySQL 技术支持，因为 MySQL 正在帮助你的企业。

3.5 MySQL的许可证和技术支持费用

我们当前的许可证价格如下。所有的价格以美元计算。如果你用信用卡支付，货币单位是欧元(欧洲共同体欧元)，所以价格将略有不同。

许可证数量 | 每拷贝定价 | 总价
1 | 美元 $200 | 美元 $200
10个包装 | 美元 $150 | 美元 $1500
50个包装 | 美元 $120 | 美元 $6000

对于大批量(OEM)购买，适用下列价格：

许可证数量 | 每拷贝定价 | 一次最少量 | 最少支付
100-999 | 美元 $40 | 100 | 美元 $4000
1000-2499 | 美元 $25 | 200 | 美元 $5000
2500-4999 | 美元 $20 | 400 | 美元 $8000

对于OEM厂家购买，你必须为可能出现的问题或扩展你用户的需求充当中间人。我们也要求OEM客户至少有一个扩展的电子邮件支持合同。

如果你有一大批廉价产品，你总可以就另外条件与我们商谈(例如，出售价格的一个百分比)。如果你是，请提供关于你的产品、定价、市场和任何其他相关的信息。

在购买了10个 MySQL 许可证后，你将得到一个 myisampack 个人拷贝，不允许你再分发这个实用程序，但是你可以分发用它压缩的数据库表。

一个全价许可证不是一个技术支持协议且包含很少的支持。这意味着我们尝试回答任何相关的问题。如果答案在文档中，我们将指导你到适当的章节，如果你没购买一个许可证或技术支持，我们将根本不可能回答。

如果你发现我们认为的一个真正的错误(bug)，我们愿意在任何情况下修复它，但是如果你支付支持费用，我们将通知你关于修复进展情况而不是仅在以后的版本修复它。

更全面的支持独立是单独销售的，每个级别所包含的技术支持的说明见3.6 商业性支持的类型。各种类型的商业性支持的费用如下。支持级别的价格以欧元计算，1欧元是大约 1.17 美元。

支持的类型 | 每年花费
基本电子邮件支持 | 欧元 170
扩展电子邮件支持 | 欧元 1000
登录支持 | 欧元 2000
扩展登录支持 | 欧元 5000

由于两个支持级别的价格差异，你可以从任何低级别的支持升级到一个较高级别的支持。

3.5.1 付款信息

目前，我们能用SWIFT、支票或信用卡方式付款。

付款应该寄到：

Postgirot Bank AB
105 06 STOCKHOLM, SWEDEN

TCX DataKonsult AB
BOX 6434
11382 STOCKHOLM, SWEDEN

SWIFT address: PGSI SESS
Account number: 96 77 06 - 3

指定：许可证或支持及你的名字和电子邮件地址。

在欧洲和日本你能使用 EuroGiro (应该是稍微便宜)付到相同的帐户。

如果你想要用支票付款，使它可付到“ Monty Progrem KB ”并且把它寄到下面的地址：

TCX DataKonsult AB
BOX 6434, Torsgatan 21
11382 STOCKHOLM, SWEDEN

如果你想要在因特网上用信用卡付款，你可以使用Tcx 安全许可证表格。

你也可以打印许可证表格，填好它并传真到：

+46-8-729 69 05

如果你想要我们给你发票，你可以用许可证表格并在注释域里写上“开发票”。你也可以把一条有关你公司的信息的消息寄给我们并要求开发票。

3.5.2 联系信息

对商业许可证，或如果你有本小节任何信息的任何问题，请联系 MySQL 许可证组，比较受欢迎的方法是通过电子邮件而传真可能花更长的时间(传真 +46-8-729 69 05 )。

David Axmark
Detron HB
Kungsgatan 65 B
753 21 UPPSALA
SWEDEN
Voice Phone +46-18-10 22 80     (Timezone GMT+1. 说瑞典语和英语)

3.6 商业性支持的类型

3.6.1 基本的电子邮件支持

基本的电子邮件支持是很便宜的支持选择，并且更应该认为它是作为支持我们开发 MySQL 的一种方式而不是真正的支持选择。

在这支持级别上，MySQL 邮件列表是通信的最佳方法，问题通常应该寄给主邮件列表( mysql@lists.mysql.com )或其它常规列表之一(例如对于有关Windows MySQL 问题，mysql-win32@lists.mysql.com )，因为其他人可能已经经历了并且解决了你的问题。见2.2 提问或报告错误。

然而，通过购买基本电子邮件支持，你也能访问支持地址 mysql-support@mysql.com，它不作为你购买一个许可证而得到很小支持的一部分，这意味着对于特别紧急的问题，你可以交叉邮寄你的消息到 mysql-support@mysql.com。(如果消息包含敏感数据，你应该只邮寄到 mysql-support@mysql.com)。

记住！当你发送一条消息到时，总要包括你的登记号码和过期日期。

基本电子邮件支持包括下列服务类型：

  • 如果你的问题已经在手册被回答了，我们将通知你正确的章节，你能在那找到答案。如果答案不在手册里，我们将为你解决问题指出正确方向。
  • 我们保证及时回复你的电子邮件消息。我们不能保证我们能解决任何问题，但是如果我们能用电子邮件联络你，至少你将收到一个回复。
  • 当你在一个支持的平台上从一个二进制分发安装MySQL时，我们将帮助解决意外的问题。支持的平台是那些已知的 MySQL 可运行的平台。见4.2 MySQL支持的操作系统。
  • 我们将在关于错误和缺少的功能方面帮助你，任何发现的错误将在MySQL下一版本中修复。如果错误对你是严重的，只要错误修复，我们将邮寄给你一个补丁。严重的错误对我们总是有最高优先级，以保证它们尽快被修复。
  • 你对MySQL更进一步开发的建议将被考虑，利用电子邮件支持，你已经帮助了MySQL进一步的开发。如果你想要有更多的介入，升级到更高级别的支持。
  • 如果你想要我们帮助优化你的系统，你必须升级到高级别的支持。

3.6.2 扩展电子邮件支持

扩展的电子邮件支持包含了基本的电子邮件支持的一切，并增加：

  • 你的电子邮件将在基本的电子邮件支持用户和非注册用户的邮件之前处理。
  • 你对 MySQL 进一步的开发建议将得到更大程度的考虑，适合MySQL基本目标的简单扩充在几天时间内实现，有了扩展的电子邮件支持，你已经帮助了MySQL进一步的开发。
  • 我们会包括一个用于快速生成压缩只读数据库的myisampack包装工具的二进制版本。目前的服务器支持读取这样的数据库但不包括用于生成它们的包装的工具。
  • 扩充的电子邮件支持覆盖的典型问题是：
    • 我们将回答并且(在原因内)解决与 MySQL可能的错误(bug)相关的问题。一旦错误被发现并且改正，我们将邮寄补丁。
    • 当你在支持的平台上从源代码或二进制的分发安装MySQL时，我们将帮助解决意外的问题。
    • 我们将回答有关缺少的功能的问题并且提供如何解决它的提示。
    • 我们将提供针对你的实际情况优化mysqld的提示。
  • 你被允许影响 MySQL TODO表上的项目的优先级，这将保证你确实需要的功能将更快地被实现。

3.6.3 登录支持

登录支持包含了扩展的电子邮件支持的一切，并增加：

  • 你的电子邮件甚至将在扩展的电子邮件支持用户的邮件之前被处理。
  • 你对 MySQL 进一步的开发建议将得到更高程度地考虑，可在几小时内被实现而且适合MySQL基本目标的可行的扩展将尽快实现。
  • 如果你有一个很特定的问题，我们可以尝试登录你的系统以解决“那个地方”的问题。
  • 象任何数据库供应商一样，我们不能保证我们能从破坏了的数据库表中挽救任何数据，但是如果发生最糟的情况，我们将帮助你尽可能挽救。 MySQL 业已证明自己很可靠，但是由于超过我们控制范围的情况，任何事情都是可能的(例如,如果你的系统崩溃或某人执行一个kill -9杀死服务器)。
  • 我们将在优化你的系统和查询上提供启示。
  • 你允许打电话给一个 MySQL 开发者(适度地)并且讨论你的 MySQL 相关的问题。

3.6.4 扩展的登录支持

扩展的登录支持包括登录支持的一切，并增加：

  • 你的电子邮件有最高可能的优先级。
  • 我们将踊跃检查你的系统并且帮助你优化它和查询。我们也可以优化或扩充 MySQL 以便更好地适合你的需要。
  • 你也可以申请只特别对你的查询扩充，如：
    mysql>select MY_CALCULATION(col_name1,col_name2) from tbl_name ;
  • 我们将为你的系统提供所有重要的MySQL版本的二进制分发，只要我们能在一个类似的系统上得到一个帐号。在最糟的情况下，我们可以要求访问你的系统以便能创建一个二进制分发。
  • 如果你能提供住所并且支付旅途费用，你甚至能让一个 MySQL 开发者访问你并为你的麻烦提供帮助。扩展的登录支持赋予你每年一次个人会面的权利，但是我们一直对我们的客户非常灵活！

第一章,前一章,下一章,最后一章，目录.


MySQL中文参考手册- 4 安装MySQL

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

4 安装MySQL

本章描述怎样获得并安装MySQL：

  • 对于你能从其获得MySQL的站点列表，见4.1 怎样获得MySQL。
  • 要了解支持哪些平台，见4.2 MySQL支持的操作系统。
  • 可获得MySQL的多个版本，以二进制代码和源代码形式分发。为了确定你应该使用的分发的版本和类型，见4.4 怎样和何时发布更新版本。
  • 针对二进制代码和源代码分发的安装指令在4.6 安装 MySQL 二进制代码分发和4.7 安装 MySQL 源代码分发讲述。每套指令均包含一个关于你可能涉及的系统特定问题的部分。
  • 为安装后期过程，见4.15 安装后期的设置与测试。不管你是用一个二进制代码还是源代码分发来安装MySQL，这些过程均适用。

4.1 怎样获得MySQL

检查MySQL主页获得当前版本的信息和下载指令。

然而，TcX的因特网链接不是很快的；我们更希望让你从下列镜象站点之一进行真正的下载。

请向webmaster@mysql.com报告不存在的或过时的镜像站点。

欧洲：

  • 奥地利 [ 维也纳技术大学 ]WWW ftp
  • 保加利亚 [ Naturella ]ftp
  • 克罗地亚 [ HULK ]WWW ftp
  • 捷克共和国 [ 在Brno的Masaryk大学 ]WWW ftp
  • 捷克共和国 [ www.sopik.cz ]WWW
  • 丹麦 [ Borsen ]WWW
  • 丹麦 [ SunSITE ]WWW ftp
  • 爱沙尼亚 [ OKinteractive ]WWW
  • 法国 [ minet ]WWW
  • 芬兰 [ EUnet ]WWW
  • 芬兰 [ clinet ]ftp
  • 德国 [ 波恩大学, 波恩 ]WWW ftp
  • 德国 [ Wolfenbuettel ]WWW ftp
  • 德国 [ Staufen ]WWW
  • 德国 [ Cable & Wireless ]ftp
  • 希腊 [ NTUA , 雅典]WWW ftp
  • Island [ GM ]WWW WWW
  • 意大利 [ Teta Srl ]WWW
  • 爱尔兰 [ Ireland On-Line/Dublin ]WWW ftp
  • 波兰 [ Sunsite ]WWW ftp
  • 葡萄牙 [ lerianet ]WWW ftp
  • 俄国 [ DirectNet ]WWW
  • 俄国 [ IZHCOM ]WWW ftp
  • 俄国 [ Scientific Center/Chernogolovka ]ftp
  • 罗马尼亚 [ Timisoara ]WWW ftp
  • 罗马尼亚 [ Bucharest ]WWW ftp
  • 西班牙 [ MasterD ]WWW
  • 瑞典 [ Sunet ]WWW ftp
  • 瑞士 [ Sunsite ]WWW ftp
  • 英国 [ Omnipotent/UK ]WWW ftp
  • 英国 [ PLiG/UK ]WWW ftp
  • 英国 [ SunSITE ]WWW ftp
  • 乌克兰 [ PACO ]WWW ftp

北美洲：

  • 加拿大 [ Tryc ]WWW
  • 加拿大 [ Cyberus ]WWW ftp
  • 美国 [ Hurricane Electric/San Jose ]WWW
  • 美国 [ Circle Net/North Carolina ]WWW
  • 美国 [ Gina net/Florida ]WWW
  • 美国 [ pingzero/Los Angeles ]WWW
  • 美国 [ 威斯康星大学 / 威斯康星]WWW ftp
  • 美国 [ DIGEX ]ftp

南美洲：

  • 巴西 [ Matrix ]WWW
  • 智利 [ Vision ]WWW

亚洲：

  • 中国 [ Freecode ]WWW
  • 中国 [ Netfirm ]WWW
  • 朝鲜 [ KREONet ]WWW
  • 日本 [ Soft Agency ]WWW
  • 日本 [ Nagoya Syouka University ]WWW ftp
  • 新加坡 [ HJC ]WWW ftp
  • 台湾 [ HT ]WWW

澳洲：

  • 澳洲 [ AARNet/Queensland ]WWW ftp
  • 澳洲 [ Tas ]WWW ftp
  • 澳洲 [ Blue Planet/Melbourne ]WWW
  • 澳洲 [ ITworks Consulting/Victoria ]WWW

非洲：

  • 南非 [ Mweb/ ]WWW
  • 南非 [ The Internet Solution/Johannesburg ]ftp

4.2 MySQL 支持的操作系统

我们使用 GNU Autoconf，因此将MySQL移植到所有使用 Posix 线程和一个 C++ 编译器的现代系统是可能的。(仅仅为了编译客户代码，只需要一个 C++ 编译器而不是线程)。我们主要在Sun Solaris(版本 2.5 & 2.6)上使用并开发软件本身，而RedHat Linux 5.0 居其次。

MySQL已经被报告在下列操作系统/线程包的组合上成功地编译。注意，对很多操作系统，原生的线程支持仅工作于最新的版本。

  • 有原生线程的AIX 4.x
  • 包括 MIT-pthreads 包的BSDI 2.x
  • 有原生线程的BSDI 3.0、3.1和4.x
  • 有原生线程的DEC UNIX 4.x
  • 包括MIT-pthreads包的FreeBSD 2.x
  • 有原生程的FreeBSD 3.x
  • 包括 MIT-pthreads 包的 HP-UX 10.20
  • 有原生线程的 HP-UX 11.x 。
  • 有 LinuxThreads 0.7.1 的 Linux 2.0 + 或glibc2.0.7
  • MacOS X 服务器
  • NetBSD 1.3/1.4 Intel 和 NetBSD 1.3 Alpha ( 需要 GNU make）
  • 包括 MIT-pthreads 包的 OpenBSD 2.x
  • OS/2 Wrap 3、FixPack 29和OS/2 Wrap 4、FixPack 4
  • 有原生线程的SGI Irix 6.x
  • SPARC和x86上有原生线程的Solaris 2.5、2.6和2.7
  • 包括 MIT-pthreads 包的SunOS 4.x
  • 有最新FSU Pthreads移植包的SCO OpenServer
  • SCO UnixWare 7.0.1
  • Tru64 Unix
  • Win95、Win98和NT(只有拥有MySQL许可证或MySQL电子邮件支持的用户可得到最新版本)。对那些在购买之前想测试的人，我们以共享软件方式发布了MySQL 3.21.29（一个较老的版本）。

4.3 使用MySQL哪个版本

首先要作出决策，你是否想要使用最新的开发版本或最终的稳定版本：

  • 通常, 如果你是第一次开始使用MySQL或尝试移植它到一些还没有二进制分发系统上，我们推荐使用开发版本(当前 3.22.x)。这是因为通常在开发版本中没用真正严重的错误，并且你能容易用你的机器上的crash-me和基准测试套件来测试它。见10.8 使用你自己的基准测试。
  • 否则，如果你正在运行一个老的系统并且想要升级，但是又不想要用3.22冒险，你应该升级到3.21.33。我们已经试着仅修复致命错误，并且对那个版本进行更小的相对安全的改动。

要做的第二项决策是你是否想要使用源代码分发或二进制分发：

  • 如果你想在一个已经存在一个最新二进制分发的平台上运行MySQL，就用它。通常，这比一个源代码分发更容易安装。
  • 如果你想要阅读(或修改)构成MySQL的C和C++代码，你应该拿到源代码分发。源代码总是最终的手册。源代码分发也比二进制的分发包含更多的测试和实例。

MySQL的命名机制使用由3个数字和一个后缀组成的版本号。例如，一个像mysql-3.21.17-beta的版本号这样解释：

  • 第1数字(3)描述文件格式。所有版本3的发行都有相同的文件格式。当一个版本4出现时，每个数据库表都将必须转换到新格式(当然，为此有一个很不错的工具)。
  • 第2数字(21)是发行级别。通常有2种选择。一个是发部/稳定分支(当前为21)而其它是开发分支(当前22)。通常两者都是稳定的，但是开发版本可能有毛病，新功能缺乏文档或可能在某些系统上编译失败。
  • 第3个数字(17)是在此发行级别的版本号，这随每个新分发递增。通常你需要你已经选择的发行(release)的最新版本(version)。
  • 后缀(beta)显示发行的稳定性级别。可能的后缀有：
    • alpha 表明发行包含大量未被100%测试的新代码。已知的错误(通常没有)应该在新闻小节被记录。见D MySQL 变迁的历史记录。在大多数 alpha 版本也有新的命令和扩展。
    • beta 意味着所有的新代码被测试了，没有增加重要的新特征，应该没有已知的错误。
    • gamma 是一个发行了一段时间的beta版本，看起来应该运行正常。这就是很多其他公司称为一个发布的东西。
    • 如果没有后缀，这意味着该版本已经在很多地方运行一段时间了，而且没有非平台特定的错误报告。这就是我们称为一个稳定版本的东西。

MySQL所有版本都经过我们的标准测试和基准测试运行，以保证他们可相当安全地使用。因为标准测试不断扩充以检测以前发现的错误，测试套件一直在改进之中。

注意，所有版本都至少已经用下列套件进行了测试：

一个内部测试套件
这是一个客户生产系统的一部分。它可能有很多几百个兆字节数据的数据库表。
MySQL基准测试套件
它运行一定范围的常用查询。它也是一个测试，检测最新的优化处理是否真的使代码更快。见10.8 使用你自己的基准测试。
crash-me测试
这尝试决定数据库支持什么功能和它的能力与限制是什么。见10.8 使用你的自己基准测试。

其他测试是在内部的生产环境中使用最新MySQL版本，至少在一台机器上。我们有超过100GB的数据可用使用。

4.4 怎样和何时发布更新版本

在TcX，MySQL进展的相当快，并且我们想要与其它MySQL用户分享它。当我们有一个看来其它人似乎需要的非常有用的功能时，我们就试着制作一个发行版本。

我们也尝试帮助那些需要很容易实现的功能的用户，我们也关注我们授权的用户想要什么，我们更特别关注我们的扩展电子邮件支持的客户想要什么，并且尽力帮助他们。

没有人一定要下载一个新版本，新闻小节中将告诉你新版本是否有一些你确实想要的东西。见D MySQL 变迁的历史记录。

当更新MySQL时，我们使用下列方针：

  • 对每个小的改进，在版本字符串的最后数字增加1。当有主要的新功能或与先前版本比有较小不兼容性时，在版本字符串的第2数字增加1。当文件格式变化时，第1数字加1。
  • 稳定的测试过的版本每年准备出现1-2次，但是如果发现小错误，只有错误修复的一个版本将被发行。
  • 工作版本准备每1-8周出现一次。
  • 对一些平台的二进制分发，主要版本由我们制作。其他人可以为其他系统制作二进制分发，但是可能不多见。
  • 一旦我们找到并修复了小错误，我们通常使用户可以得到补丁。
  • 对非紧急但烦人的错误，如果他们被发给我们，我们将使用户可以得到补丁，否则我们将集中许多错误到一个更大的补丁中。
  • 在任何情况下，如果在一个发行中有一个致命错误，我们将尽快制作一个新版本。我们想其他公司也这样做。:)

当前的稳定版本是3.22；我们已经转移到3.23的积极开发中。在稳定版本中，错误仍将被修复。我们不相信一个完全冻结，因为这也留下的错误修复和“必须做”的事情。“某种程度的冻结”意味着我们可以增加小东西，它“将几乎肯定不影响已经能工作的任何东西”。

4.5 安装布局

这节描述安装二进制代码和源代码分发时创建的缺省目录布局。

二进制分发通过在你选择的安装地点(典型的“/usr/local/mysql”)解压缩来安装，并且在该处创建下列目录：

目录 | 目录的内容
“bin” | 客户程序和mysqld服务器
“data” | 日志文件, 数据库
“include” | 包含(头)文件
“lib” | 库文件
“scripts” | mysql_install_db
“share/mysql ” | 错误消息文件
“sql-bench” | 基准程序

源代码分发在你配置并编译后进行安装。缺省地，安装步骤将文件安装在“/usr/local”下的下列子目录：

目录 | 目录的内容
“bin” | 客户程序和脚本
“include/mysql” | 包含(头)文件
“info” | Info格式的文档
“lib/mysql” | 库文件
“libexec” | mysqld服务器
“share/mysql” | 错误消息文件
“sql-bench” | 基准程序和crash-me测试
“var” | 数据库和日志文件。

在一个安装目录内，源代码安装的布局在下列方面不同于二进制安装：

  • mysqld服务器被安装在“libexec”目录而不是“bin”目录内。
  • 数据目录是“var”而非“data”。
  • mysql_install_db被安装在“/usr/local/bin”目录而非“/usr/local/mysql/scripts”内。
  • 头文件和库目录是“include/mysql”和“lib/mysql”而非“include”和“lib”。

4.6 安装MySQL二进制代码分发

你需要下列工具安装一个MySQL二进制分发：

  • GNU gunzip解压缩分发。
  • 一个适当的tar解包分发。 GNU tar已知可以。

在Linux下的另一个安装方法是使用RPM(RedHat包管理器)分发。见4.6.1 Linux RPM 注意事项。

如果你碰到问题，在把问题邮寄到mysql@lists.mysql.com时，请总是使用 mysqlbug，就算问题不是一个bug，mysqlbug收集系统信息，将有助于其它人解决你的问题。不使用mysqlbug，你将减少得到你问题的一个解决方案的可能性！在你解包分发后，你会在“bin”目录下找到mysqlbug。见2.3 怎样报告错误或问题。

你必须执行以便安装并使用一个MySQL二进制分发的基本命令是：

shell> gunzip < mysql-VERSION-OS.tar.gz |tar  xvf -
shell> ln - s  mysql-VERSION-OS  mysql
shell> cd mysql
shell> scripts/mysql_install_db
shell> bin/safe_mysqld &

如果你安装了DBI和Msql-Mysql-modulesPerl模块，你可以使用bin/mysql_setpermission脚本增加新用户。

以下是更详细的描述：

对于安装二进制分发，遵循以下步骤，然后继续到4.15 安装后期的设置与测试，进行安装后期的设置和测试：

  1. 挑选一个你想解开分发包的目录，进入给目录。在下面的例子中，我们将分发解包在“/usr/local”下并且创建一个安装MySQL的“/usr/local/mysql”目录。（因此，下列指令假设你有权限在“/usr/local”中创建文件，如果该目录被保护，你需要以root实施安装。)
  2. 从4.1 怎样获得MySQL中列出的站点之一获得一个分发文件。MySQL二进制分发以压缩的tar文档提供，并且有类似“mysql-VERSION-OS.tar.gz”的名字，这里VERSION是一个数字(例如，3.21.15)，且OS表明分发能运行的操作系统类型(例如，pc-linux-gnu-i586)。
  3. 解开分发并且创建立安装目录：
    shell> gunzip < mysql-VERSION-OS.tar.gz |tar  xvf -
shell> ln - s  mysql-VERSION-OS  mysql

    第一个命令创建一个名为“mysql-VERSION-OS”的目录，第二个命令生成到该目录的一个符号链接。这让你更容易地把安装目录指定为“/usr/local/mysql”。

  4. 进入安装目录：
    shell> cd  mysql

    你会在mysql目录下发现几个文件和子目录，对安装目的最重要的是“bin”和“scripts”子目录。

    “bin”
    这个目录包含客户程序和服务器，你应该把这个目录的完整路径加到你的PATH环境变量，以便你的shell能正确的找到MySQL程序。
    “scripts”
    这个目录包含mysql_install_db脚本，用来初始化服务器存取权限。
  5. 如果你想使用mysqlaccess而在某个非标准的地点有MySQL分发，你必须改变地点，在哪儿mysqlaccess期望找到mysql客户。编辑“bin/mysqlaccess”脚本，大约在第18行，寻找类似下面的行：
    $MYSQL = “/usr/local/bin/mysql”;　# path to mysql executable

    改变路径以反映出mysql实际存储在你系统上的地点。如果你不这样做，当你运行mysqlaccess时，你将得到一个broken pipe的错误。

  6. 创造MySQL授权表(只有在你以前没安装过MySQL是必要的)：
    shell> scripts/mysql_install_db

    注意当你运行时mysql_install_db时，比版本3.22.10老的MySQL版本启动MySQL服务器。这不再是真的了！

  7. 如果你想要安装对Perl DBI/DBD接口的支持，见4.10 Perl安装注意事项。
  8. 如果你喜欢在引导机器时自动启动MySQL，你可以拷贝support-files/mysql.server文件到你系统有启动文件的地方。更多的信息可以在support-files/mysql.server脚本中和4.15.3 自动启动和停止MySQL找到。

在所有东西被解包并且安装以后，你应该初始化并且测试你的分发。

你可以用下列命令启动MySQL服务器：

shell> bin/safe_mysqld &

见4.15 安装后期的设置和测试。

4.6.1 Linux RPM 注意事项

在Linux上安装MySQL推荐的方法是使用一个RPM文件。MySQL RPM目前是在一个 RedHat 5.2 系统上建立的，但是应该能工作在支持rpm且使用glibc的其他 Linux 版本上。

如果一个RPM文件有问题，例如Sorry, the host 'xxxx' could not be looked up，见4.6.3.1 Linux 注意事项。

你可能要使用的RPM文件有：

  • MySQL-VERSION.i386.rpm MySQL服务器。除非你只是想要与运行在其他机器上MySQL服务器连接，否则你将需要它。
  • MySQL-client-VERSION.i386.rpm 标准MySQL客户程序。你可能总是需要安装这个包。
  • MySQL-bench-VERSION.i386.rpm 测试和基准程序。需要Perl和msql-mysql-modules RPM。
  • MySQL-devel-VERSION.i386.rpm 所需的库和包含文件。如果你想要编译其他MySQL客户程序, 例如Perl模块。
  • MySQL-VERSION.src.rpm 包含上述所有包的源代码。它也能被用来尝试为其他硬件平台构造RPM(例如，Alpha或SPARC)。

查看一个RPM包中的所有文件：

shell> rpm - qpl  MySQL-VERSION.i386.rpm

实施一个标准的最小安装，运行这个命令：

shell> rpm -i MySQL-VERSION.i386.rpm  MySQL-client-VERSION.i386.rpm

只安装客户包：

shell> rpm -i MySQL-client-VERSION.i386.rpm

RPM将数据放在“/var/lib/mysql”里，RPM也在“/etc/rc.d/”里创建适当的入口以便在引导时自动启动服务器。（这意味着如果你以前已经安装过，在对它改变之前，你可以把你以前安装的MySQL启动文件做个拷贝，因此你不会丢失改动）。

在安装了RPM文件后，“mysqld”守护程序应该正在运行，并且现在你应该可以开始使用MySQL。见4.15 安装后期的设置和测试。

如果一些东西出错，可以在二进制的安装一节里找到更多的信息。见4.6 安装MySQL二进制代码分发。

4.6.2 构造客户程序

如果你编译你自己写的或你从第三方获得的MySQL客户程序，他们必须用link命令的-lmysqlclient选项进行链接。你可能也需要指定一个 -L 选项，告诉链接器在哪儿查找库文件。例如，如果库文件安装在“/usr/local/mysql/lib”里，在链接命令上使用 -L/usr/local/mysql/lib -lmysqlclient。

对使用MySQL头文件的客户程序，当你编译他们时，你可能需要指定一个 -I 选项(例如，-I/usr/local/mysql/include)， 使得编译器能找到头文件。

4.6.3 系统特定的问题

下一节说明在从一个二进制分发安装MySQL时，已经在特定的系统上观察到已发生过一些问题。

4.6.3.1 Linux 注意事项

MySQL需要至少Linux 2.0。

二进制发行版用-static链接的，这意味着你一般不必担心你拥有的系统库是哪个版本。你也不必安装LinuxThreads。一个用-static链接的程序比一个动态链接程序稍大些但更快(3-5%)。然而，一个问题是你不能使用静态链接的用户定义函数(UDF)。如果你准备编写或使用UDF函数(这只对C或C++程序员)，你必须编译MySQL本身，使用动态链接。

如果你正在使用一个基于libc-的系统(而不是一个glibc2系统)，你将可能碰到二进制发行的主机名解析和getpwnam()的一些问题（这是因为glibc不幸地依赖于一些包括解析主机名和getwpent()的外部库，甚至在用-static编译时)。在这种情况下，当你运行mysql_install_db时，你可能得到下列错误信息：

sorry, the host 'xxxx' could not be looked up

或当你尝试以 --user 选项运行 mysqld 时的下列错误：

getpwnam : No such fileor directory

你能用下列方法之一解决这个问题：

  • 获得一个MySQL源代码分发(一个RPM或tar分发)并且安装它。
  • 执行mysql_install_db --force；这将不执行mysql_install_db里面的resolveip测试。缺点是你不能在授权表中使用主机名字；相反你必须使用IP数字(除了localhost)。如果你正在使用一个老的不支持--force的MySQL版本，你必须用编辑器删除mysql_install中的resolveip测试。
  • 用su启动mysqld而不使用--user。

MySQL的Linux-Intel二进制代码和RPM发行版是为最高可能的速度而配置的。我们总是努力使用可用的最快的稳定的编译器。

MySQL的Perl支持要求Perl 5.004_03或更新。

4.6.3.2 HP-UX 注意事项

针对HP-UX的MySQL二进制分发作为一个HP depot（仓库）或tar 文件格式分发的。为了使用depot文件，你必须运行至少HP-UX 10.x 以便访问HP的软件仓库工具。

MySQL的HP版本在运行HP-UX 10.20下的HP 9000/8xx 服务器上编译，并且使用MIT-pthreads。它已知可在这种配置下很好地工作。MySQL 3.22.26和更新版也用HP原生线程包构造。

其他可以运行的配置：

  • 运行 HP-UX 10.20 + 的 HP 9000/7xx
  • 运行 HP-UX 10.30 的 HP 9000/8xx

下列配置几乎肯定不能运行：

  • 运行 HP-UX 10.x 的 HP 9000/7xx 或 8xx ，x < 2
  • 运行 HP-UX 9.x 的 HP 9000/7xx 或 8xx

为了安装分发，使用下面的命令之一, 这里/path/to/depot是仓库文件的完整路径：

  • 要安装所有东西，包括服务器、客户和开发工具：
     shell> /usr/sbin/swinstall - s  /path/to/depot  mysql.full
  • 仅仅安装服务器：
    shell> /usr/sbin/swinstall - s  /path/to/depot  mysql.server
  • 仅仅安装客户软件包：
    shell> /usr/sbin/swinstall - s  /path/to/depot  mysql.client
  • 仅仅安装开发工具：
    shell> /usr/sbin/swinstall - s  /path/to/depot  mysql.developer

depot在“/opt/mysql”存放二进制代码和库文件并在“/var/opt/mysql”存放数据。depot也在“/sbin/init.d”和“ /sbin/rc2.d”里创建适当的入口以自动地在引导时启动服务器。显然, 这有必要以root身份来安装。

为了安装HP-UX tar分发，你必须有GNU tar的一个拷贝。

4.7 安装MySQL源代码分发

你需要下列工具构造并安装MySQL源代码：

  • GNU gunzip解压缩该分发。
  • 一个合适的tar解包分发。GNU tar已知可以工作。
  • 一个能运行的ANSI C++编译器。gcc> = 2.8.1 、egcs> = 1.0.2 、SGI C++和SunPro C++是一些已知能工作编译器。 当使gcc用时，不需要libg++。gcc2.7.x 有一个bug，使得它可能不能编译一些完全合法的C++文件，例如“sql/sql_base.cc”。如果你仅有gcc2.7.x，你必须升级gcc才能编译MySQL。
  • 一个优秀的make程序。GNU make总是被推荐且有时必须。如果你有问题，我们推荐试一试GNU make3.75或更新。

如果你遇到问题，当向mysql@lists.mysql.com邮寄问题时，请一直使用mysqlbug。就算问题不是一个bug，mysqlbug收集系统信息，将有助于其它人解决你的问题。如果不使用mysqlbug，你减少得到关你问题的一个解决方案的可能性！在你解包分发后，你会在“scripts”目录下找到mysqlbug。见2.3 怎样报告错误或问题。

4.7.1 快速安装概述

你必须执行的安装MySQL源代码分发的基本命令是(从一个解包的tar文件)：

shell>configure
shell>make
shell>make install
shell>scripts/mysql_install_db
shell>/usr/local/mysql/bin/safe_mysqld &

如果你从一个源代码RPM开始，那么执行如下命令。

shell> rpm -- rebuild MySQL-VERSION.src.rpm

这样你制作一个可以安装的二进制RPM。

如果你安装了DBI和Msql-Mysql-modulesPerl模块，你可以利用bin/mysql_setpermission脚本增加新用户。

以下是更详细的描述：

为了安装源代码分发，按照下列步骤，然后继续到4.15 安装后期的设置与测试，进行安装后期的初始化与测试。

  1. 挑选一个你要在其下面解包分发的目录，并且进入该目录。
  2. 从节4.1 怎样获得MySQL中列出的站点之一获得一个分发文件。MySQL源代码分发以压缩的tar档案提供，并且有类似于“mysql-VERSION.tar.gz”的名字，这里的VERSION是一个类似3.23.7-alpha的数字。
  3. 在当前目录下解包分发：
    shell> gunzip < mysql-VERSION.tar.gz | tar  xvf -

    这个命令创建名为“mysql-VERSION”的一个目录。

  4. 进入解包分发的顶级目录：
     shell> cd  mysql-VERSION
  5. 设置发行版本并且编译：
    shell>./configure--prefix=/usr/local/mysql
shell>make

    当你运行configure时，你可能想要指定一些选项，运行./configure --help得到一张选项表。4.7.3 典型的configure选项讨论一些很有用的选项。如果configure失败，你将发送包含你认为能帮你解决该问题的“config.log”的邮件，如果configure异常退出，也要包括configure的最后几行输出。用mysqlbug脚本邮寄错误报告。见2.3 怎样报告错误和问题。如果编译失败，见节4.8 编译问题？，帮助解决很多常见问题。

  6. 安装所有东西：
    shell>make install

    你可能需要root用户来运行这个命令。

  7. 创造MySQL授权表(只有你以前没安装MySQL是必需的)：
    shell>scripts/mysql_install_db

    注意，在运行mysql_install_db时，那些比3.22.10旧的MySQL版本启动MySQL服务器。现在不是这样了！

  8. 如果你想要安装对Perl DBI/DBD接口的支持，见4.10 Perl安装注意说明。
  9. 如果你想要MySQL在你引导机器时自动地启动，你可以拷贝support-files/mysql.server到你的系统中有启动文件的地方。更多的信息可以在support-files/mysql.server脚本里和4.15.3 自动启动和停止MySQL找到。

在所有东西安装完以后，你应该初始化并且测试你的分发。

你可以用下列命令启动MySQL服务器，这里BINDIR是safe_mysqld被安装的目录(缺省为“/usr/local/bin”)：

shell> BINDIR/safe_mysqld &

如果这个命令提示mysqld daemon ended并马上失败，那么你能在文件“mysql-data-directory/'hostname'.err”找到一些信息。可能的原因是你已经有另外一个正在运行的mysqld服务器。见19.3 在同一台机器上运行多个MySQL服务器。

参见4.15 安装后期的设置与测试。

4.7.2 运用补丁

有时补丁出现在邮件列表上或放在MySQL FTP地点的补丁区。

为了使用来自邮件列表的一个补丁，保存补丁出现在文件的消息，进入你的MySQL源代码树的顶级目录并运行这些命令：

shell>patch - p1 <patch-file-name
shell>rm config.cache
shell>make clean

来自FTP地点的补丁是作为普通文本文件或作为被压缩了的gzip文件分发。运用一个文本的补丁如上述邮件列表补丁，为了使用一个压缩的补丁，进入你的MySQL源代码树顶级目录并运行这些命令：

shell>gunzip <patch-file-name.gz |patch - p1
shell>rm  config.cache
shell>make clean

在使用一个补丁以后，按照正常的源代码安装的指令，开始./configure步骤。在运行make install后，重启你的MySQL服务器。

在运行make install前，你可能需要关闭所有正在运行的服务器（使用mysqladmin shutdown)。如果一个程序的新版本替代当前正在执行的版本，一些系统不允许你安装它。

4.7.3 典型的configure选项

configure脚本给你一个很大的控制权来如何配置你的MySQL分发。典型地，你使用configure命令行的选项进行。你也可以用正确的环境变量作用于configure。对于一个由configure支持的选择列表，运行这个命令：

shell> ./configure -- help

一些更常用的configure选项见下面的描述：

  • 只编译MySQL客户库和客户程序而不是服务器，使用--without-server选项：
    shell> ./configure --without-server

    如果你没有一个 C++ 编译器，mysql将不编译(有一个客户程序需要C++)。在这种情况下，你可以去掉configure里面测试C++编译器的代码，然后运行带有 --without-server选项的./configure。编译步骤步将仍然尝试构造mysql，但是你可以忽略任何关于“ mysql.cc ”的警告。（如果make停止，试试make -k告诉它即使出错继续剩下的构造步骤）。

  • 如果你不想要位于“/usr/local/var”目录下面的日志(log)文件和数据库，使用类似于下列configure命令的一个：
    shell>./configure--prefix=/usr/local/mysql
shell>./configure--prefix=/usr/local --localstatedir=/usr/local/mysql/data

    第一个命令改变安装前缀以便任何东西被安装在“/usr/local/mysql”下面而非缺省的“/usr/local”。第二个命令保留缺省安装前缀，但是覆盖了数据库目录缺省目录(通常是“/usr/local/var”)并且把它改/usr/local/mysql/data.

  • 如果你正在使用Unix并且你想要MySQL的套接字位于缺省地点以外的某个地方(通常在目录“/tmp”或“/var/run”，使用象这样的configure的命令：
    shell> ./configure -- with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock

    注意给出的文件必须是一个绝对路径！

  • 如果你想编译静态链接程序(例如，制作二进制分发、获得更快的速度或与解决与RedHat分发的一些)，像这样运行configure：
    shell>./configure --with-client-ldflags=-all-static --with-mysqld-ldflags=-all-static
  • 如果你正在使用gcc并且没有安装libg++或libstdc++，你可以告诉configure使用gcc作为C++编译器：
    shell> CC=gcc  CXX=gcc  ./configure

    当你使用时gcc作为C++编译器是，它将不试图链接libg++或libstdc++。如果构造失败并且产生有关编译器或链接器的错误，不能创建共享库“libmysqlclient.so.#”(“#”是一个版本号), 你可以通过为configure指定--disable-shared选项来解决此问题。在这种情况下，configure将不构造一个共享libmysqlclient.so.#库。

  • 你可以设置MySQL对于非NULL的列不使用DEFAULT列值(即，不允许列是NULL)。这导致INSERT语句产生一个错误，除非你明确地为所有要求非NULL值的列指定值。为了禁止使用缺省值，这样运行configure：
    shell> CXXFLAGS=-DDONT_USE_DEFAULT_FIELDS  ./configure
  • 缺省地，MySQL使用ISO-8859-1(Latin1)字符集。为了改变缺省设置，使用--with-charset选项目：
    shell> ./configure -- with-charset=CHARSET

    CHARSET可以是big5、cp1251、cp1257、czech、danish、dec8、dos、euc_kr、gb2312 gbk、german1、hebrew、 hp8、hungarian、koi8_ru、koi8_ukr、latin1、latin2、sjis、swe7、tis620、ujis、usa7、win1251或win1251ukr之一。见9.1.1 用于数据和排序的字符集。注意：如果你想要改变字符集，你必须在配置期间做make distclean！如果你想在服务器和客户之间变换字符，你应该看一下SET OPTION CHARACTER SET命令。见7.25 SET OPTION句法。警告：如果你在创建了任何数据库表之后改变字符集，你将必须对每个表运行myisamchk -r -q，否则你的索引可能不正确地排序。（如果你安装了MySQL，创建一些表，然后重新配置MySQL使用一个不同的字符集并且重新安装它，这时就可能发生这种情况。）

  • 为了配置MySQL带有调试代码，使用--with-debug选项：
    shell> ./configure --with-debug

    这导致包含一个安全的内存分配器，能发现一些错误和并提供关于正在发生的事情的输出。见G.1调试一个MySQL服务器。

  • 属于特定系统的选项可在本章特定系统的小节里找到。见4.11 系统特定的问题。

4.8 编译问题？

所有MySQL程序在Solaris上使用gcc编译并且没有任何警告。在其他系统上，由于系统包含文件的差别可能会发生警告。对于使用MIT-pthreads时发生的警告，见4.9 MIT-pthreads 注意事项。其他问题，检查下面的表。

许多问题的解决方案涉及重新配置。如果你确实需要重新配置，注意下列事项：

  • 如果configure在它已经被运行了以后运行，它可以使用先前收集的信息。这个信息被存储在“config.cache”里面。当configure启动时，它寻找该文件而且如果它存在，假定信息仍然是正确的，读入它的内容。当你重新配置时，该假设是无效的。
  • 每次你运行configure时候，你必须运行make再重新编译。然而, 你可能想要把先前构造的老的目标文件删除，因为他们使用不同的配置选项被编译。

为了防止使用旧的配置信息或目标文件，在重新运行configure前运行这些命令：

shell>rm  config.cache
shell>make clean

另外，你可以运行make distclean。

下表描述了一些最常发生的编译MySQL的问题：

  • 如果在编译“sql_yacc.cc”时，你得到如下的一个错误，你可能是存储器或交换空间溢出：
    Internal compiler error: program cc1plus got fatal signal 11
  或
Out of virtual memory
  或
Virtual memory exhausted

    该问题是gcc要求大量的内存编译带有嵌入函数(inline function)的“sql_yacc.cc”。试试以--with-low-memory选项运行configure：

    shell>./configure -- with-low-memory

    如果你正在使用gcc，该选项使得将-fno-inline加到编译行，如果你正在使用其他的编译器，则加入-O0。你应该试一试--with-low-memory选项，即使你有特别多的存储器和交换空间，而你认为不能可能运行得溢出。这个问题甚至在很慷慨的硬件配置的系统上出现，通常用--with-low-memory选项修正它。

  • 缺省地，configure挑选c++作为编译器名字并用-lg++选项的GNU c++链接。如果你正在使用gcc，这个特性在配置期间导致如下问题：
    configure: error: installation or configuration problem:
C++ compiler cannot create executables.

    你可能也在编译期间看到g++、libg++或libstdc++相关的问题。这些问题的一个原因是你可能没有g++，或你可能有g++但无libg++或libstdc++。看一下“config.log”文件。它应该包含你的c++编译器不能工作的准确原因！为了解决这些问题，你可以使用gcc作为你的C++编译器。试试设置环境变量CXX为"gcc -O3"。例如：

    shell>CXX="gcc -O3" ./configure

    它能工作，因为gcc象g++一样编译C++源代码，但缺省地它不链接libg++或libstdc++。解决这些问题的其他方法当然是安装g++、libg++和libstdc++。

  • 如果你的编译以下面任何错误而失败，你必须升级make版本到GNUmake：
    making all in mit-pthreads
make: Fatal error in reader: Makefile, line 18:
Badly formed macro assignment
  or
make: file `Makefile' line 18: Must be a separator (:
  or
pthread.h: No such file or directory

    Solaris和FreeBSD已知make程序有问题。GNU make版本3.75已知能工作。

  • 如果你想要定义你的C或C++编译器所使用的标志，把标志加到CFLAGS和CXXFLAGS环境变量中即可。你也能使用CC和CXX来指定编译器名字。例如：
    shell>CC=gcc
shell>CFLAGS=-O6
shell>CXX=gcc
shell>CXXFLAGS=-O6
shell>export CC  CFLAGS  CXX  CXXFLAGS

    对于已经知道在不同系统上有用的标志定义列表，见4.14 TcX 二进制代码。

  • 如果你得到象如下的一条错误消息，你需要升级你的gcc编译器：
    client/libmysql.c:273: parse error brfore '__attribute__'

    gcc2.8.1已知可以工作，但是我们推荐使用egcs1.0.3a或更新。

  • 如果你在编译mysqld时显示例如下面的那些错误, configure没有正确地检测传到accept()、getsockname()或getpeername()最后参数的类型：
    cxx: Error: mysqld.cc, line 645: In this statement, the referenced
     type of the pointer value "&length" is "unsigned long", which
     is not compatible with "int".
new_sock = accept(sock, (struct sockaddr *)&cAddr, &length);

    为了修正它，编辑“config.h”文件(它由configure生成)。寻找这些行：

    /* Define as the base type of the last arg to accept */
#define SOCKET_SIZE_TYPE XXX

    更改XXX为size_t或int，这取决于你的操作系统。（注意：你每次运行configure都必须这样做，因为configure重新生成“config.h”。)

  • “sql_yacc.cc”文件由“sql_yacc.yy”生成。通常构造过程不需要创造“sql_yacc.cc”，因为MySQL有一个已经生成的拷贝，然而，如果你确实需要再创建它，你可能碰到这个错误：
    "sql_yacc.yy", line xxx fatal: default action causes potential...

    这是一个你的yacc版本不完善的迹象。你可能需要安装bison（GNU 版本yacc)并使用它。

  • 如果你需要调试mysqld或MySQL客户，运行configure，使用--with-debug选项，然后重新编译并且链接你客户程序到新的客户库。见G.2 调试一个MySQL客户。

4.9 MIT-pthreads注意事项

这节描述在使用 MIT-pthreads 所涉及的一些问题。

注意：在Linux上，你应该不使用MIT-pthreads而是安装LinuxThreads！见4.11.5 Linux 注意事项(所有的Linux 版本)。

如果你的系统不提供原生的线程支持，你将需要使用MIT-pthreads包构造MySQL。这包括大多数FreeBSD系统、SunOS 4.x 、Solaris 2.4和更早版本及其他，见4.2 MySQL 支持的操作系统。

  • 在大多数系统上，你能通过使用configure，用--with-mit-threads选项来强迫运行MIT-pthreads：
    shell> ./configure -- with-mit-threads

    当使用MIT-pthreads时，不支持在一个非源代码目录构造，因为我们想要使我们对代码的改变减到最小。

  • MIT-pthreads不支持用于实现Unix套接字的AF_UNIX协议。这意味着如果你使用MIT-pthreads进行编译，所有的链接必须使用TCP/IP进行(它有点慢)。如果在构造MySQL后，你发现你不能与本地的服务器连接，很可能是客户程序正在试图用缺省的Unix套接字与localhost连接。使用主机选择(-h或--host)明确地指定本地的主机名字，尝试做一个TCP/IP连接到mysql。
  • 决定是否使用MIT-pthreads的检查仅在处理服务器代码的配置过程期间发生。如果已经用--without-server配置了分发并只构造客户代码，客户将不知道MIT-pthreads是否正在被使用并且是否使用缺省的Unix套接字连接。因为Unix套接字不能在MIT-pthreads下面工作，这意味着当你运行客户程序时，你将需要使用-h或--host。
  • 当使用MIT-pthreads编译MySQL时，因为性能原因，系统锁定缺省为禁止使用。你可以用--use-locking选项告诉服务器使用系统锁定。
  • 有时pthreadbind()命令不能绑定一个套接字但没有任何错误消息(至少在Solaris上)，结果是所有到服务器的连接均失败。例如：
    shell> mysqladmin version
mysqladmin: connect to server at '' failed;
error: 'Can't connect to mysql server on localhost (146)'

    解决它的方法是杀死mysqld服务器并且重启它。这只有当我们强迫服务器停止并马上进行重启时在发生。

  • 使用MIT-pthreads，sleep()系统调用不是可中断的SIGINT（break)。这只有在你运行mysqladmin --sleep时才能注意到。你在中断起作用并且进程停止之前必须等待sleep()终止。
  • 当链接时，你可能会收到这样的警告消息(至少在Solaris上)；他们可以被忽视：
    ld: warning: symbol `_iob' has differing sizes:
    (file /my/local/pthreads/lib/libpthread.a(findfp.o) value=0x4;
file /usr/lib/libc.so value=0x140);
    /my/local/pthreads/lib/libpthread.a(findfp.o) definition taken
ld: warning: symbol `__iob' has differing sizes:
    (file /my/local/pthreads/lib/libpthread.a(findfp.o) value=0x4;
file /usr/lib/libc.so value=0x140);
    /my/local/pthreads/lib/libpthread.a(findfp.o) definition taken
  • 一些其他的警告也可被忽略：
    implicit declaration of function `int strtoll(...)'
implicit declaration of function `int strtoul(...)'
  • 我们还没有让readline可在MIT-pthreads上工作。（这不需要，但是可能某些人有兴趣。）

4.10 Perl 安装说明

4.10.1 在Unix上安装Perl

Perl对MySQL的支持借助DBI/DBD客户接口而提供。见20.5 MySQL Perl API。Perl DBD/DBI客户代码要求Perl 5.004或以后版本。如果你有Perl的一个更旧的版本，接口将不能工作。

MySQL Perl支持也要求你安装了MySQL客户编程支持。如果你从RPM文件安装MySQL，客户程序在客户RPM中，但是客户编程支持在开发者RPM。确定你安装了后一个RPM 。

对于版本3.22.8，Perl支持是与主要MySQL发行版本单独分发。如果你想要安装Perl支持，你需要的文件能从http://www.mysql.com/Contrib获得。

Perl 分发以压缩的tar档案提供，并且有一个类似“MODULE-VERSION.tar.gz”的名字，这里MODULE是模块名字并且VERSION是版本号。你应该得到Data-Dumper、DBI和Msql-Mysql-modules分发并按此次序安装他们。安装过程显示出在下面，显示的例子针对Data-Dumper模块, 但是所有3个过程是相同的。

  1. 解包分发到当前目录：
    shell> gunzip < Data-Dumper-VERSION.tar.gz | tar  xvf -

    这个命令创建的一个名为“Data-Dumper-VERSION”的目录。

  2. 进入解包分发的顶级目录：
    shell> cd  Data-Dumper-VERSION
  3. 构造分发并且编译所有东西：
    shell> perl Makefile.PL
shell> make
shell> make test
shell> make install

make test命令很重要，因为它验证模块正在工作。注意：在你Msql-Mysql-modules安装期间运行该命令试验接口代码时，MySQL服务器必须正在运行，否则测试将失败。

无论何时你安装一个新版本的MySQL，重建并且重新安装Msql-Mysql-modules分发是一个好主意, 特别是如果你在升级MySQL后，观察所有异常，如你的DBI脚本核心倾倒(core dump)。

如果你没有权限在系统目录下安装Perl模块，或如果你安装本地Perl模块，下列参考书可以帮助你：

http://www.iserver.com/support/contrib/perl5/modules.html

在标题Installing New Modules that Require Locally Installed Modules下面查找。

4.10.2 在Win32上安装ActiveState Perl

在 Win32 上安装 ActiveState Perl的MySQL DBD的模块, 你应该做下列步骤：

  • 打开一个DOS shell。
  • 如果需要，设置HTTP_proxy变量。例如, 你可以试一试：set HTTP_proxy=my.proxy.com:3128
  • 启动PPM程序：C:\perl\bin\ppm.pl
  • 如果你还没有这样做，安装DBI： install DBI
  • 如果成功，安装DBD::mysql：http://www.mysql.com/Contrib/ppd/DBD-mysql.ppd

如果你不能使上述步骤工作，你应该安装MyODBC驱动程序并且通过ODBC连接MySQL服务器。

use DBI;
$dbh= DBI->connect("DBI:ODBC:$dsn","$user","$password") ||
  die "Got error $DBI::errstr when connecting to $dsn\n";

4.10.3 在Win32上安装MySQL Perl分发

MySQL Perl分发包含DBI、DBD:MySQL和DBD:ODBC。

  • 从http://www.mysql.com/download.html得到Win32的Perl分发。
  • 在C:解压缩分发，这样你得到一个“C:\PERL”目录。
  • 增加目录“C:\PERL\BIN”到你的路径。
  • 增加目录“C:\PERL\BIN\MSWin32-x86-thread”或“C:\PERL\BIN\MSWin32-x86”到你的路径。
  • 在 DOS shell执行perl -v测试perl的运行。

4.10.4 使用PerlDBI/DBD接口的问题

如果 Perl 报告它不能找到../mysql/mysql.so模块，那么问题可能是该Perl不能找到共享库文件“libmysqlclient.so”。

你可用下列任何一个方法修正它这：

  • 用perl Makefile.PL -static而非perl Makefile.PL编译Msql-Mysql-modules分发。
  • 拷贝libmysqlclient.so到其他共享库文件所在的目录(可能是“/usr/lib”或“/lib”)。
  • 在Linux上，你可以把libmysqlclient.so所在目录的路径名加到“/etc/ld.so.conf”文件中。
  • 把libmysqlclient.so所在目录的路径名加到LD_RUN_PATH环境变量中。

如果你从DBD-mysql得到下列错误，你可能正在使用gcc（或使用一个旧的用gcc编译的二进制代码)：

/usr/bin/perl: can't resolve symbol '__moddi3'
/usr/bin/perl: can't resolve symbol '__divdi3'

当“mysql.so”库文件被构造时候，为链接命令加上-L/usr/lib/gcc-lib/... -lgcc(当你编译Perl客户时检查针对“mysql.so”的make输出)。-L选项应该指定“libgcc.a”在你系统上所在目录的路径名。

这个问题的另一个原因可能是Perl和MySQL都不是用gcc编译的。在这种情况下，你可以都用gcc编译以解决不匹配。

如果你想要在一个不支持动态链接(象SCO那样)的系统上使用Perl模块，你可以产生包括DBI和DBD-mysql的Perl的一个静态版本。这种运行方法是你生成一个链接了DBI代码的Perl版本并在最新的Perl上安装它，然后你使用它来构造附加链接了DBD代码的Perl版本，并且安装它。

在 SCO 上，你必须有下列环境变量设置：

shell> LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib:/usr/progressive/lib
或
shell> LD_LIBRARY_PATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib
shell> LIBPATH=/usr/lib:/lib:/usr/local/lib:/usr/ccs/lib:/usr/progressive/lib:/usr/skunk/lib
shell> MANPATH=scohelp:/usr/man:/usr/local1/man:/usr/local/man:/usr/skunk/man:

首先, 在DBI分发所在目录下运行下列命令，创造包括一个静态链接的Perl DBI：

shell> perl Makefile.PL LINKTYPE=static
shell> make
shell> make install
shell> make perl

然后你必须安装新的Perl。make perl的输出将显示正确的你需要执行施行安装的make的命令。在SCO上，是make -f Makefile.aperl inst_perl MAP_TARGET=perl.

接下来，在Msql-Mysql-modules分发所在目录下，使用刚才创建的Perl来创建同样包括一个静态链接的PerlDBD::mysql的另一个Perl：

shell> perl Makefile.PL LINKTYPE=static
shell> make
shell> make install
shell> make perl

最后, 你应该安装这个新的Perl。而且，make perl的输出指出使用的命令。

4.11 系统特定的问题

下面的章节说明在从源代码分发安装MySQL时，发生在特定的系统上并已观察到的一些问题。

4.11.1 Solaris注意事项

在Solaris上，甚至在你解开MySQL分发以前，你可能陷入困境！Solaris tar不能处理长文件名字，因此你在打开MySQL时，可能看到这样的一个错误：

x mysql-3.22.12-beta/bench/Results/ATIS-mysql_odbc-NT_4.0-cmp-db2,informix,ms-sql,mysql,oracle,solid,sybase, 0 bytes, 0 tape blocks
tar: directory checksum error

在这种情况下，你必须使用 GNU tar(gtar) 打开分发。你能在http://www.mysql.com/Downloads/找到为Solaris的一个预编译的拷贝。

Sun的原生线程只工作在Solaris 2.5和更高版本上。对于2.4和更早的版本，MySQL将自动地使用 MIT-pthreads 。见4.9 MIT-pthreads 注意事项。

如果你从配置得到下列错误：

checking for restartable system calls... configure: error can not run test
programs while cross compiling

这意味着你的编译器安装有些问题！在这种情况下，你应该升级编译器到一个更新的版本。你也可以把下列行插入到config.cache文件来解决这个问题：

ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'}

如果你在一个SPARC上使用Solaris，推荐的编译器是egcs1.1.2 或更新。你能在http://egcs.cygnus.com/找到它。注意：egs1.1.1 和gcc2.8.1 不能在 SPARC 上可靠地工作！

当使用时egcs1.1.2时，推荐的configure命令行是：

shell> CC=gcc CFLAGS="-O6" \
       CXX=gcc CXXFLAGS="-O6 -felide-constructors -fno-exceptions -fno-rtti" \
       ./configure --prefix=/usr/local/mysql --with-low-memory

如果你有Sun Workshop 4.2 编译器，你能这样运行configure：

CC=cc CFLAGS="-xstrconst -Xa -xO4 -native -mt" CXX=CC CXXFLAGS="-xO4 -native -noex -mt" ./configure --prefix=/usr/local/mysql

shell> CC=cc CFLAGS="-Xa -fast -xO4 -native -xstrconst -mt" \
       CXX=CC CXXFLAGS="-noex -XO4 -mt" \
       ./configure

你也可以编辑configure脚本改变该行：
#if !defined(__STDC__) || __STDC__ != 1

为：
#if !defined(__STDC__)

如果你使用-Xc选项打开__STDC__，Sun编译器不能用 Solaris 的“pthread.h”头文件编译。这是Sun的一个bug。

如果mysqld在运行时发出显示在下面的错误消息，你已经尝试用Sun编译器编译MySQL，没有启用多线程选择(-mt)：

libc internal error: _rmutex_unlock: rmutex not held

增加-mt到CFLAGS和CXXFLAGS并且再试一试。

如果你在用gcc编译MySQL时得到下列错误，它意味着你的gcc没有对你的Solaris版本进行配置！

shell> gcc -O3 -g -O2 -DDBUG_OFF  -o thr_alarm ...
./thr_alarm.c: In function `signal_hand':
./thr_alarm.c:556: too many arguments to function `sigwait'

在这种情况下正确的做法是得到最新版本的egcs，并且用你当前的gcc编译器编译它！至少对于 Solaris 2.5，几乎所有的gcc二进制版本都有旧的、不可用的包含文件，将破怀使用线程的所有程序的文件(并且可能是其他的程序)！

Solaris不提供所有系统库的静态版本(libpthreads和libdl)，所以你不能用--static编译MySQL。如果你尝试这样做，你将得到错误：

ld: fatal: library -ldl: not found

如果太多进程试图很快地连接mysqld，你将在MySQL日志文件中看见这个错误：

Error in accept: Protocol error

你可以试着用--set-variable back_log=50选项启动服务器作为它的一个解决办法。

如果你正在链接你自己的MySQL客户，当你试着执行它时，你可能得到下列错误：

ld.so.1: ./my: fatal: libmysqlclient.so.#: open failed: No such file or directory

这个问题能用下列方法之一避免：

  • 用下列标志链接客户(而不是-Lpath)： -Wl,r/full-path-to-libmysqlclient.so。
  • 拷贝libmysqclient.so到“/usr/lib”。
  • 在运行你的客户程序前，把libmysqlclient.so所在目录的路径名加到LD_RUN_PATH的环境变量中。

4.11.2 Solaris 2.7 注意事项

通常你能在 Solaris 2.7 上使用 Solaris 2.6 二进制代码。大多数Solaris 2.6 的问题也适用于Solaris 2.7。

注意：MySQL3.23.4 和更高版本应该能自动检测 Solaris 2.7 并且启用下列问题的解决办法！

Solaris 2.7 在包括文件中有一些bug，在使用gcc时，你可以看见下列错误：

/usr/include/widec.h:42: warning: `getwc' redefined
/usr/include/wchar.h:326: warning: this is the location of the previous
definition

如果出现这种情况，你可以做下列事情解决这个问题：

拷贝/usr/include/widec.h到.../lib/gcc-lib/os/gcc-version/include并且改变第41行：

#if     !defined(lint) && !defined(__lint)

为

#if     !defined(lint) && !defined(__lint) && !defined(getwc)

另外，你可以直接编辑“/usr/include/widec.h”。这两种方法，在你进行修正以后，你应该删除“config.cache”并且再运行configure！

如果当你运行make时，你得到象这样错误，那是因为configure没检测“curses.h”文件(可能因为/usr/include/widec.h的错误)：

In file included from mysql.cc:50:
/usr/include/term.h:1060: syntax error before `,'
/usr/include/term.h:1081: syntax error before `;'

解决它的方案是做下列步骤之一：

  • 如上所述编辑“/usr/include/widec.h”并且再次运行configure。
  • 从“config.h”文件删除#define HAVE_TERM行并再次运行make。
  • 用CFLAGS=-DHAVE_CURSES CXXFLAGS=-DHAVE_CURSES ./configure进行配置。

4.11.3 Solaris x86 注意事项

如果你正在在 Solaris x86上使用gcc或egcs，并且你碰到了在装载时的核心倾倒（core dump）问题，你应该使用下列configure命令：

shell> CC=gcc CFLAGS="-O6 -fomit-frame-pointer" \
       CXX=gcc \
       CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" \
       ./configure --prefix=/usr/local/mysql

用libstdc++库和与C++异常处理来避免这个问题。

如果这没有帮助，你应该编译一个调试版本并且用一个踪迹文件运行它或在gdb下运行它。见G.1 调试一个 MySQL 服务器。

4.11.4 SunOS 4 注意事项

在 SunOS 4 上， 需要MIT-pthreads 编译MySQL，反过来这意味着你将需要GNU make。

一些SunOS 4系统的动态库和libtool有问题。你可以使用下列configure行来避免这个问题：

shell> ./configure --disable-shared --with-mysqld-ldflags=-all-static

当编译readline时，你可能得到关于重复定义的警告，这些可以被忽略。

当编译mysqld时候， 将有一些implicit declaration of function警告，这些可以被忽略。

4.11.5 Linux 注意事项(所有Linux版本)

MySQL在Linux上使用 LinuxThreads 。如果你正在使用一个没有glibc2的老的Linux版本，你必须在尝试编译MySQL前安装LinuxThreads。http://www.mysql.com/Downloads/Linux

注意：但你做INSERT DELAYED时，所用的包括2.1.1及以前的glibc版本在pthread_mutex_timedwait处理上有一个致命错误，如果你正在使用INSERT DELAYED，你必须把下列补丁加到你的glibc库中：http：//www.mysql.com/Downloads/Patches/glibc-pthread_cond_timedwait.patch。MySQL 3.23.7包含了对这个错误的一个临时解决办法。

如果你不能启动mysqld或如果mysql_install_db不工作，请继续读下去！这仅发生在有LinuxThreads问题或libc/glibc库为题的Linux系统上。有很多简单的解决办法让MySQL工作！最简单是使用针对Linux x86的二进制版本的MySQL（不是RPM)，这个版本的一个好的方面是它可能比你编译你自己的任何版本快10%！见10.2.1 编译和链接如何影响 MySQL 的速度。

二进制分发的一个已知问题是与使用libc的更老的Linux系统（如RedHat 4.x 或 Slackware)，你将得到有关主机名解决的一些非致命问题。见4.6.3.1 Linux注意事项。

使用libc.so.5.3.12，myisamchk将挂起，升级到最新libc以解决这个问题。

当使用 LinuxThreads 时，你将看到最少 3 进程在运行。这些事实上的线程，对LinuxThreads管理器将有一个线程，一个线程处理连接，还有一个线程处理告警和信号。

如果你用ps看到了一个死掉的mysqld守护进程，这通常意味着你发现了MySQL里面的一个错误或你有一个被破坏的数据库表。见18.1 如果MySQL总是崩溃怎么办。

如果你正在使用LinuxThreads并且mysqladmin shutdown不工作，你必须升级到 LinuxThreads 0.7.1 或更新。

如果你正在使用 RedHat ，你可能得到象这样的错误：

/usr/bin/perl is needed...
/usr/sh is needed...
/usr/sh is needed...

如果是这样，你应该升级rpm版本到“rpm-2.4.11-1.i386.rpm”和“rpm-devel-2.4.11-1.i386.rpm”(或以后)。

你能从ftp://ftp.redhat.com/updates/4.2/i386得到RedHat 4.2的库文件升级，或对其他分发http://www.sunsite.unc.edu/pub/Linux/distributions/redhat/code/rpm/。

如果你正在链接你自己的MySQL客户并且得到错误：

ld.so.1: ./my: fatal: libmysqlclient.so.4: open failed: No such file or directory

当执行它们时，这个问题可用下列方法之一避免：

  • 用下列标志链接客户(而不是-Lpath)： -Wl,r/path-libmysqlclient.so。
  • 拷贝libmysqclient.so到“/usr/lib”。
  • 在运行你的客户程序前，把libmysqlclient.so所在目录的路径名加到LD_RUN_PATH的环境变量中。

如果你正在使用 Fujitsu 编译器(fcc / FCC)，编译MySQL你将有一些问题，因为 Linux 头文件面向gcc。

下列configure行应该与fcc/FCC工作：

CC=fcc CFLAGS="-O -K fast -K lib -K omitfp -Kpreex -D_GNU_SOURCE -DCONST=const \
-DNO_STRTOLL_PROTO" CXX=FCC CXXFLAGS="-O -K fast -K lib  -K omitfp \
-K preex --no_exceptions --no_rtti -D_GNU_SOURCE -DCONST=const \
-Dalloca=__builtin_alloca -DNO_STRTOLL_PROTO '-D_EXTERN_INLINE=static __inline'" \
./configure --prefix=/usr/local/mysql --enable-assembler \
--with-mysqld-ldflags=-all-static --disable-shared --with-low-memory

4.11.5.1 Linux-x86 注意事项

MySQL要求libc版本 5.4.12 或更新，已知可工作在libc 5.4.46。glibc版本2.0.6和以后版本应该也工作。使用RedHat的glibc RPM有一些问题，所以如果你有问题，检查是否有任何更新！glibc2.0.7-19和2.0.7-29 RPM已知可以工作。

在一些更老的 Linux 分发上，configure可能产生象这样的一个错误：

Syntax error in sched.h. Change _P to __P in the /usr/include/sched.h file.
See the Installation chapter in the Reference Manual.

按照错误消息所说的去做，并且给只有一条下划线的_P宏增加一个额外下划线 ('__P'), 然后再试一试。

在编译时，你可能得到一些警告；显示在下面的那些可以被忽略：

mysqld.cc -o objs-thread/mysqld.o
mysqld.cc: In function `void init_signals()':
mysqld.cc:315: warning: assignment of negative value `-1' to `long unsigned int'
mysqld.cc: In function `void * signal_hand(void *)':
mysqld.cc:346: warning: assignment of negative value `-1' to `long unsigned int'

在Debian GNU/Linux上，如果你想要在系统启动时自动启动MySQL，做下列命令：

shell> cp support-files/mysql.server /etc/init.d/mysql.server
shell> /usr/sbin/update-rc.d mysql.server defaults 99

mysql.server可以在MySQL安装目录的“share/mysql”目录下面找到, 或在MySQL源代码树的“support-files”目录下找到。

如果mysqld在它启动时总是核心倾倒(core dump), 问题可能是你有一个老版本的“/lib/libc.a”，重命名它，然后删除“sql/mysqld”并且重新make install再试一试。这个问题在一些 Slackware 安装上被报告了。有最新版本的glibc的RedHat 5.0也有一些类似的问题。见4.11.5.2 RedHat 5.0 注意事项。

如果再链接mysqld时，你得到下列错误, 它意味着你的“libg++.a”没有正确安装：

/usr/lib/libc.a(putc.o): In function `_IO_putc':
putc.o(.text+0x0): multiple definition of `_IO_putc'

像这样运行configure，你能避免使用“libg++.a”：

shell> CXX=gcc ./configure

4.11.5.2 RedHat 5.0 注意事项

如果你在RedHat上有MySQL的任何问题，你应该开始升级glibc到最新可能的版本！

如果你安装所有的官方RedHat补丁(包括glibc-2.0.7-19和glibc-devel-2.0.7-19)，MySQL的二进制代码和源代码分发运行应该没有任何麻烦！

因为在glibc2.0.5里面有关如何释放pthread_key_create变量有一个错误，更新是需要的。用glibc2.0.5，你必须使用一个静态地链接的MySQL二进制分发。如果你想要从源代码编译，你必须安装来自于http://www.mysql.com/Downloads/Linux 的LinuxThreads修正版本或升级你的glibc。

如果你有一个不正确的glibc或LinuxThreads版本，其结果是mysqld在每个连接以后崩溃。例如，mysqladmin version完成后，mysqld将崩溃！

另一个不正确的库的症状是当mysqld启动时，马上崩溃。在一些Linux系统上，这个问题可以通过这样的配置来修正：

shell> ./configure -- with-mysqld-ldflags=-all-static

在Redhat 5.0上，容易的方法是安装glibc2.0.7-19 RPM并运行configure --with-mysqld-ldflags=-all-static选项。

对于glibc2.0.7的源代码分发，容易运用并被MySQL测试的一个补丁可以在下面找到：

http://www.mysql.com/Download/Linux/glibc-2.0.7-total-patch.tar.gz

如果当你构造MySQL时，你有类似于这些崩溃的经历, 你总能下载到最新的MySQL二进制版本。这是静态链接的以避免库冲突而且应该在所有的Linux系统上工作！

MySQL自带一个内部的调试器可以有很多信息产生踪迹文件，能被用来发现并解决大量不同的问题。见G.1 调试一个MySQL服务器。

4.11.5.3 RedHat 5.1 注意事项

RedHat 5.1的glibc(glibc2.0.7-13 )有一个内存缺陷，所以要得到一个稳定的MySQL版本，你必须升级glibc到2.0.7-19、降级glibc或使用一个mysqld的二进制版本。如果你不这样做，你将碰到内存问题(存储器溢出，等等, 等等)。在这种情况下，最常见的错误是：

Can't create a new thread (errno 11). If you are not out of available
memory, you can consult the manual for any possible OS dependent bug

在你升级到glibc2.0.7-19以后，你可以用动态链接(缺省)配置MySQL，但是在你从源代码安装了glibc 2.0.7-19之前，你不能运行configure --with-mysqld-ldflags=-all-static选项！

你可以用rpm -q glibc检查你有glibc哪个版本。

4.11.5.4 Linux-SPARC 注意事项

在一些实现中，readdir_r()被破坏了。其症状是SHOW DATABASES总是返回一个空集合。这可以通过在编译前从“config.h”中删除HAVE_READDIR_R进行更正。

有些问题将需要给你的Linux安装打补丁。补丁可在http://www.mysql.com/patches/Linux-sparc-2.0.30.diff找到，这个补丁是针对Linux分发“sparclinux-2.0.30.tar.gz”，它们可从vger.rutgers.edu（一个从来没有与官方的2.0.30版合并的版本)得到。你也必须安装LinuxThreads 0.6或更新。

感谢jacques@solucorp.qc.ca提供这个信息。

4.11.5.5 Linux-Alpha注意事项

在Linux-Alpha上的大问题仍然是在这个平台上的glibc的线程有一些问题。你应该从得到你能找到的最新glibc版本开始。

注意：在你运行任何使用线程的程序之前(象mysqld、thr_alarm或thr_lock)，你应该增减共享存储器的限制(用ulimit)。如果你忘记这样做，MySQL基准测试已知是失败的！

用下列命令配置MySQL：

shell> CC=gcc CCFLAGS="-Dalpha_linux_port" \
       CXX=gcc CXXFLAGS="-O3 -Dalpha_linux_port -felide-constructors -fno-exceptions -fno-rtti" \
       ./configure --prefix=/usr/local/mysql

试试编译mysys/thr_lock和mysys/thr_alarm，测试这些程序的运行！（不用参数调用每一个，如果一切正常，每个应该以test_succeeded结束。）

在安装MySQL以后，在safe_mysqld里去掉ulimit命令的注释，并加入选项以增加共享存储器。

注意对MySQL来说，Linux-Alpha仍然是一个alpha质量的平台。用最新glibc，你有一个让它工作的很好机会。

如果你用信号方面的问题(MySQL出人意料地在高负载下死掉)，你可能找到了一个线程和信号有关的OS错误。在这种情况下，你可以告诉MySQL如下配置以不使用信号：

shell> CFLAGS=-DDONT_USE_THR_ALARM \
       CXXFLAGS=-DDONT_USE_THR_ALARM \
       ./configure ...

这不影响MySQL性能，但是有副作用，就是你不能用mysqladmin kill或mysqladmin shutdown杀死在一个连接上“睡眠”的客户。相反，当客户发出下一个命令时，它将死掉。

4.11.5.6 MkLinux 注意

MySQL应该能工作在有最新glibc包的MkLinux上(用glibc2.0.7测试过)。

4.11.5.7 Qube2 Linux注意事项

为了让MySQL在Qube2上工作，(Linux Mips)，你需要最新的glibc库(glibc-2.0.7-29C2已知可工作)。你也必须使用egcsC++编译器(egcs-1.0.2-9或更新)。

4.11.6 Alpha-DEC-Unix 注意事项

当在Digital UNIX下编译线程程序时，文档推荐对于cc和cxx使用-pthread选项而且库文件用-lmach -lexc（除了-lpthread外)。你应该象下面这样运行configure：

shell> CC="cc -pthread" CXX="cxx -pthread -O" \
       ./configure --with-named-thread-libs="-lpthread -lmach -lexc -lc"

当编译mysqld时，你可能看见这样一些警告：

mysqld.cc: In function void handle_connections()':
mysqld.cc:626: passing long unsigned int *' as argument 3 of
accept(int,sockadddr *, int *)'

你可以安全地忽略这些警告，他们的发生是因为configure只能检测出错误，而不是警告。

如果你直接从命令行启动服务器，当你退出时，你可能有死掉的问题。（当你退出时，你的重要进程收到一个SIGHUP信号)，如果如此，试着象这样启动服务器：

shell> nohup  mysqld [options] &

nohup使得跟随它的命令忽视从终端发来的任何SIGHUP信号了。另外，通过运行safe_mysqld启动服务器，它为你使用nohup调用mysqld。

4.11.7 Alpha-DEC-OSF1注意事项

如果你有编译问题并安装了DECCC和gcc，尝试这样运行configure：

shell> CC=cc CFLAGS=-O CXX=gcc CXXFLAGS=-O3 \
       ./configure --prefix=/usr/local/mysql

如果你得到“c_asm.h”文件的问题，你可以创建并使用一个“哑(dummy)”“c_asm.h”文件：

shell> touch include/c_asm.h
shell> CC=gcc CFLAGS=-I./include \
       CXX=gcc CXXFLAGS=-O3 \
       ./configure --prefix=/usr/local/mysql

在OSF1 V4.0D和编译器"DEC C V5.6-071 on Digital UNIX V4.0 (Rev. 878)" 上，编译器有了一些奇怪的行为(未定义asm标志)。/bin/ld好象也被破坏(当链接mysqld时，发生_exit undefined问题)。在这个系统上，从OSF 4.0C的版本替换了/bin/ld后，我们设法用下列configure命令行编译MySQL，：

shell> CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql

用Digital编译器“C++ V6.1-029”，下列命令应该工作：

CC=cc -pthread
CFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host
CXX=cxx -pthread
CXXFLAGS=-O4 -ansi_alias -ansi_args -fast -inline speed -speculate all -arch host
export CC CFLAGS CXX CXXFLAGS
./configure --prefix=/usr/mysql/mysql --with-low-memory --enable-large-files \
--with-mysqld-ldflags=-all-static --disable-shared --with-named-thread-libs="-lmach -lexc -lc"

在OSF1的某些版本中，alloca()函数被破坏，通过删除定义'HAVE_ALLOCA'的“config.h”的行更正它。

alloca()函数也可能在/usr/include/alloca.h里面有一个不正确的原型，源于此的警告可以忽略。

configure将自动地使用下列线程库： --with-named-thread-libs="-lpthread -lmach -lexc -lc"。

当使用gcc时，你也可以试试这样运行configure：

shell> CFLAGS=-D_PTHREAD_USE_D4  CXX=gcc  CXXFLAGS=-O3  ./configure ……

如果你的信号有问题(MySQL出人意料地在高负载下死掉)，你可能找到了一个线程和信号有关的OS错误。在这种情况下，你可以告诉MySQL如下配置以不使用信号：

shell> CFLAGS=-DDONT_USE_THR_ALARM \
       CXXFLAGS=-DDONT_USE_THR_ALARM \
       ./configure ...

这不影响MySQL性能，但是有负面效应，就是你不能用mysqladmin kill或mysqladmin shutdown杀死在一个连接上“睡眠”的客户。相反，当客户发出下一个命令时，它将死掉。

4.11.8 SGI-Irix 注意事项

你可能需要在运行configure后且在编译前去掉在“config.h”里面一些东西的定义(underfine)。

在一些Irix实现中，alloca()函数被破坏。如果mysqld服务器死于一些SELECT语句，把“config.h”定义HAVE_ALLOC和HAVE_ALLOCA_H的行删除即可。如果mysqladmin create不工作，把“config.h”定义HAVE_READDIR_R的行删除，你也可能必须删除HAVE_TERM_H行。

SGI推荐你将本页上的所有补丁作为一个整体来安装：http://support.sgi.com/surfzone/patches/patchset/6.2_indigo.rps.html

最小地，你应该安装最新的核心卷(rollup)、最新的rld卷和最新的libc卷。

很明确，对于pthreads支持，你需要本页上所有的POSIX补丁：

http://support.sgi.com/surfzone/patches/patchset/6.2_posix.rps.html

如果在编译“mysql.cc”时，你得到类似于下面的错误:

"/usr/include/curses.h", line 82: error(1084): invalid combination of type

那么，在你的MySQL源代码树的顶级目录打下列命令：

shell> extra/replace bool curses_bool < /usr/include/curses.h > include/curses.h
shell> make

应该也有安排上的问题报告。如果只有一个线程正在运行，事情会变慢的。通过启动另外一个客户来避免它，这可以导致此后其他线程的执行速度增加2到10倍。这是Irix线程难以理解的问题；你可能必须临时准备找出解决方案直到它能被修正。

如果你正在用gcc编译，你可以使用下列configure命令：

shell> CC=gcc CXX=gcc CXXFLAGS=-O3 \
       ./configure --prefix=/usr/local/mysql --with-thread-safe-client --with-named-thread-libs=-lpthread

4.11.9 FreeBSD 注意事项

对于运行MySQL，FreeBSD 3.x是被推荐的，因为其线程包是更加完整。

最容易因此是比较受喜欢的安装方法是使用mysql服务者和 mysql客户的移植，可从http://www.freebsd.org得到。

使用这些给你的东西：

  • 一个全优化的工作在你的FreeBSD版本上的MySQL。
  • 自动配置和构造。
  • 启动脚本安装在/usr/local/etc/rc.d。
  • 用pkg_info -L察看哪个文件被安装的能力，并且如果你在那台机器上不再想要MySQL，用pkg_delete完全删除它们。

建议在FreeBSD 2.x版上使用 MIT-pthreads，在版本3和以上版本用原生线程。在一些2.2.x的以后版本使用原生线程运行是可能的，但是你可能碰到mysqld关掉的问题。

确定让你的名字解析程序安装正确，否则当连接mysqld时，你可能会经历解析延时或失败。

保证在“/etc/hosts”文件中的localhost入口是正确的(否则你与数据库连接时将有问题)。“/etc/hosts”文件应该以一行开始：

127.0.0.1  localhost  localhost.your.domain

如果你注意到configure使用 MIT-pthreads，你应该阅读MIT-pthreads注意事项，见4.9 MIT-pthreads 注意事项。

如果你从make install得到一个它不能找到“/usr/include/pthreads”的错误，configure没有检测出你需要 MIT-pthreads。通过执行这些命令修正它：

shell> rm config.cache
shell> ./configure --with-mit-threads

FreeBSD make的行为与make GNU略有不同。如果你有make相关问题，你应该安装GNU make。

FreeBSD也已知有一个非常低的缺省文件句柄限制。见18.11 文件没找到。去掉在safe_mysqld中的ulimit -n 小节的注释或在/etc/login.conf为mysqld用户提高限制(并用cap_mkdb /etc/login.conf重建它)，如果你不使用缺省，也要保证你为此用户在口令文件(用法：chpass mysqld-user-name ）。

你用SELECT NOW()返回GMT形式的值而不是你的本地时间，如果有这样的问题，你必须设定TZ环境变量为你的当前时区的。这应该设置服务器运行的环境，例如在safe_mysqld或mysql.server里。

为了得到一个安全并且稳定的系统，你应该只仅使用被标记为-STABLE的FreeBSD内核。

4.11.10 NetBSD 注意事项

为了NetBSD上编译，你需要GNU make，否则当make试图在C++文件上运行lint时，编译将崩溃。

4.11.11 OpenBSD 2.5 注意事项

在OpenBSD 2.5上，你可以用下列选项编译带原生线程的MySQL：

CFLAGS=-pthread  CXXFLAGS=-pthread  ./configure -- with-mit-threads=no

4.11.12 BSD/OS 注意事项

4.11.12.1 BSD/OS 2.x 注意事项

如果在编译MySQL时，你得到下列错误, 你对虚存的ulimit值是太低了：

item_func.h: In method `Item_func_ge::Item_func_ge(const Item_func_ge &)':
item_func.h:28: virtual memory exhausted
make[2]: *** [item_func.o] Error 1

试试使用ulimit -v 80000并再运行make。如果这还不行并且你正在使用bash，试试换到csh或sh；一些BSDI用户报告了与bash和ulimit有关问题。

如果你正在使用gcc，你也可能必须为configure使用--with-low-memory标志才能编译“sql_yacc.cc”。

你用SELECT NOW()返回GMT形式的值而不是你的本地时间，如果有这样的问题，你必须设定TZ环境变量为你的当前时区的。这应该为服务器运行的环境设置，例如在safe_mysqld或mysql.server里。

4.11.12.2 BSD/OS 3.x 注意事项

升级到BSD/OS 3.1。如果那不可能，安装BSDI patch M300-038。

在配置MySQL时，使用下列命令:

shell> env CXX=shlicc++ CC=shlicc2 \
       ./configure \
           --prefix=/usr/local/mysql \
           --localstatedir=/var/mysql \
           --without-perl \
           --with-unix-socket-path=/var/mysql/mysql.sock

下列也已知可用：

shell> env CC=gcc CXX=gcc CXXFLAGS=-O3 \
       ./configure \
           --prefix=/usr/local/mysql \
           --with-unix-socket-path=/var/mysql/mysql.sock

如果你愿意，你可以改变目录地点，或不指定任何地点而使用缺省。

如果你在重负再下的性能有问题，试试使用对safe_mysqld使用--skip-thread-priority选项！这将以相同优先级运行所有线程；在BSDI 3.1上，这得到较好的性能(至少直到BSDI修正其线程调度程序)。

如果你在编译时得到virtual memory exhausted错误，试试使用ulimit -v 80000并再运行make。如果这还不行并且你正在使用bash，试试换到csh或sh；一些BSDI用户报告了与bash和ulimit有关问题。

4.11.12.3 BSD/OS 4.x 注意事项

BSDI 4.x有一些线程有关的错误。如果你想要在这上面使用MySQL，你应该安装所有与线程相关的补丁，至少应该安装M400-023。

4.11.13 SCO 注意事项

当前的移植仅在“sco3.2v5.0.4”和“sco3.2v5.0.5”系统上被测试，在“sco 3.2v4.2”一个移植也有很大进展。

此时在OpenServer上推荐的编译器是gcc 2.95.2，用它你应该能编译MySQL：

CC=gcc CXX=gcc ./configure ... (options)
  1. 对于OpenServer 5.0.X，你需要在Skunkware 95上使用GDS(95q4c)，这是必要的，因为在Skunkware 97上的GNU gcc 2.7.2 没有GNU as。你也可以使用egcs1.1.2或更新：http://www.egcs.com/。如果你正在使用egcs1.1.2，你必须执行下列命令：
    shell> cp -p /usr/include/pthread/stdtypes.h \
/usr/local/lib/gcc-lib/i386-pc-sco3.2v5.0.5/egcs-2.91.66/include/pthread/
  2. 对该产品和开发系统，你需要GCC 2.5.?的移植。他们在这个SCO UNIX版本上是必需的，你不能只使用GCC Dev系统。
  3. 你应该得到 FSU Pthreads 包并且首先安装它，它可在http://www.cs.wustl.edu/~ schmidt/ACE_wrappers/FSU-threads.tar.gz找到。你也可以从ftp://www.mysql.com/pub/mysql/Downloads/SCO/FSU-threads-3.5c.tar.gz得到一个预编译的包。
  4. FSU Pthreads能用带tcpip的SCO UNIX 4.2编译，或OpenServer 3.0或Open Desktop 3.0(OS 3.0 ODT 3.0)，安装带有使用一个GCC 2.5.X ODT的SCO开发系统，或对OS 3.0你将需要一个GCC 2.5.？的良好移植。 没有一个良好的移植会有很多问题。对这个产品的移植需要SCO UNIX开发系统，没有它，你正缺少所需的库和链接器。
  5. 为了在你的系统上构造FSU Pthreads，做下列工作：
    1. 在“thread/src”目录下运行./configure并且选择SCO OpenServer选项。这个命令拷贝“Makefile.SCO5”到“Makefile”。
    2. 运行make。
    3. 为了在缺省的“/usr/include”目录安装，作为root登录，然后cd 到“thread/src”目录，并运行make install。
  6. 记得在制作MySQL时要使用GNU make。
  7. 在OSR 5.0.5上，你应该使用下列配置命令行：
    shell> CC="gcc -DSCO" CXX="gcc -DSCO" ./configure

    需要-DSCO帮助配置正确检测一些线程函数。如果你忘记-DSCO，在编译时，你将得到下列错误消息：
    my_pthread.c: In function `my_pthread_mutex_init':
my_pthread.c:374: `pthread_mutexattr_default' undeclared (first use this function)
  8. 如果你不是作为root启动safe_mysqld，你将可能每进程只有缺省的110个打开文件。mysqld将在日志文件写下关于此的注解。
  9. 用SCO 3.2 V5.0.5，你应该使用一个FSU Pthreads版本3.5c或更新。下列configure命令应该工作：
    shell> CC="gcc -belf" ./configure --prefix=/usr/local/mysql --disable-shared
  10. 用SCO 3.2V4.2，你应该使用一个FSU Pthreads版本3.5c或更新。下列configure命令应该工作：
    shell> CFLAGS="-D_XOPEN_XPG4" CXX=gcc CXXFLAGS="-D_XOPEN_XPG4" \
       ./configure \
           --with-debug --prefix=/usr/local/mysql \
           --with-named-thread-libs="-lgthreads -lsocket -lgen -lgthreads" \
           --with-named-curses-libs="-lcurses"

    你可能得到一些包括文件的某些问题。在这种情况下，你能在ftp://www.mysql.com/pub/mysql/Downloads/SCO/SCO-3.2v4.2-includes.tar.gz找到新的SCO特定的包括文件。你应该在你的MySQL源代码树的“include”目录下打开这个文件。

SCO开发注意事项：

  • MySQL应该自动地检测FSU Pthreads并且用-lgthreads -lsocket -lgthreads选项链接mysqld。
  • SCO开发库在FSU Pthreads是重入(reentrant)的。SCO宣称它的库函数是重入的，因此他们一定在FSU Pthreads中是重入的。在 OpenServer上的 FSU Pthreads 试图使用SCO方案制作重入的库。
  • FSU Pthreads(至少在www.mysql.com的版本)链接了GNU malloc，如果你甭到内存使用的问题，确定“gmalloc.o”被包含在“libgthreads.a”和“libgthreads.so”中。
  • 在FSU Pthreads中，下列系统调用是pthreads感知的：read()、write()、getmsg()、connect()、accept()、select()和wait()。

如果你想要在SCO上安装DBI，你必须编辑在DBI-xxx和每个子目录下的“Makefiles”：

OLD:                                  NEW:
CC = cc                               CC = gcc -belf
CCCDLFLAGS = -KPIC -W1,-Bexport       CCCDLFLAGS = -fpic
CCDLFLAGS = -wl,-Bexport              CCDLFLAGS =

LD = ld                               LD = gcc -belf -G -fpic
LDDLFLAGS = -G -L/usr/local/lib       LDDLFLAGS = -L/usr/local/lib
LDFLAGS = -belf -L/usr/local/lib      LDFLAGS = -L/usr/local/lib

LD = ld                               LD = gcc -belf -G -fpic
OPTIMISE = -Od         		      OPTIMISE = -O1

OLD:
CCCFLAGS = -belf -dy -w0 -U M_XENIX -DPERL_SCO5 -I/usr/local/include

NEW:
CCFLAGS = -U M_XENIX -DPERL_SCO5 -I/usr/local/include

这时如果他们用icc或cc编译，Perl动态装载器(dynaloader)将不装载DBI模块。

当用cc编译时，Perl工作得最好。

4.11.14 SCO Unixware 7.0 注意事项

你必须使用一个最新的MySQL版本，至少是3.22.13，因为该版本在Unixware下面解决一些移植性问题。

在UnixWare 7.0.1上，我们可用下列configure的命令编译MySQL：

shell> CC=cc CXX=CC ./configure --prefix=/usr/local/mysql

4.11.15 IBM-AIX 注意事项

xlC自动检测从Autoconf丢失，当使用 IBM 编译器时，需要如下这样一个configure命令：

shell> CC="xlc_r -ma -O3 -qstrict -DHAVE_INT_8_16_32" \
CXX="xlC_r -ma -O3 -qstrict -DHAVE_INT_8_16_32" \
./configure

如果你正在使用egcs编译MySQL，你必须使用-fno-exceptions标志，因为egcs得异常处理不是对线程安全的！（这用egcs1.1被测试过)。在 AIX 上使用egcs和gcc，我们推荐下列configure行：

shell> CXX=gcc \
       CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti" \
       ./configure --prefix=/home/monty --with-debug --with-low-memory

如果你用信号问题(MySQL出人意料地在高负载下死掉)，你可能发现了与线程和信号有关的一个OS错误。在这种情况下，你可以用如下配置告诉MySQL不使用信号：

shell> CFLAGS=-DDONT_USE_THR_ALARM CXX=gcc \
       CXXFLAGS="-felide-constructors -fno-exceptions -fno-rtti -DDONT_USE_THR_ALARM" \
       ./configure --prefix=/home/monty --with-debug --with-low-memory

这不影响MySQL性能，但是有副作用，就是你不能用mysqladmin kill或mysqladmin shutdown杀死在一个连接上“睡眠”的客户。相反，当客户发出下一个命令时，它将死掉。

在 AIX 的一些版本上用libbind.a链接使得getservbyname核心倾倒(core dump)，这是AIX的一个bug并且应该被报告到IBM了。

4.11.16 HP-UX 注意事项

在 HP-UX 上编译MySQL时，有一些“小”问题。我们推荐您使用gcc而不是HP-UX自己的编译器，因为gcc生成更好一些的代码！

我们推荐在HP-UX上使用gcc 2.95，不使用高度优化标志(类似-O6)，因为这在 HP-UX 上可能不安全。

注意MIT-pthreads不能用 HP-UX 编译器编译，因为它不能编译.S（汇编器)文件。

下列配置行应该工作：

CFLAGS="-DHPUX -I/opt/dce/include" CXXFLAGS="-DHPUX \
-I/opt/dce/include -felide-constructors -fno-exceptions \
-fno-rtti" CXX=gcc ./configure --with-pthread \
--with-named-thread-libs='-ldce' --prefix=/usr/local/mysql --disable-shared

如果你正在编译gcc2.95本身，如果你想要用MIT-pthreads编译MySQL，你不应该用DCE库(libdce.a或libcma.a)链接它。如果你混合DCE和MIT-pthreads包，你将得到一个使得你不能连接的mysqld。当你编译gcc2.95时，删除DCE库！

4.11.17 MacOS X 注意事项

顺着MacOS X移植的链接可以得到能让MySQL载MacOS上工作的信息，见1.8 有用的MySQL相关链接。

MySQL3.23.7 应该包括所有必要的MacOSX上配置它的补丁。然而在配置MySQL前，你必须首先安装来自MacOSX 的MySql服务器的pthread 包。

你可能也想要把一个别名加到你的shell资源文件中以便从命令行访问mysql和mysqladmin。

alias mysql '/usr/local/mysql/bin/mysql'
alias mysqladmin '/usr/local/mysql/libexec/mysqladmin'

4.12 Win32 注意事项

这节描述在Win32上安装和使用MySQL，这也在MySQL Win32分发所带的“readme”文件中描述。

4.12.1 在Win32上安装MySQL

如果你没有一个注册的MySQL版本，你应该首先下载共享软件版本，从：

MySQL 3.21.29

如果你准备从一些其他程序连接MySQL，你也可能需要MyODBC驱动程序。你可在MySQL下载页找到。

安装任何一个分发，在某个空目录解压缩它并且运行Setup.exe程序。

缺省地，MySQL-Win32被配置安装在“C:\mysql”。如果你想要在其它地方安装MySQL，在“C:\mysql”安装它，然后将安装移到你想要的地方。如果你真的移走MySQL，你必须通过提供选项给mysqld告诉mysqld那里的所有一切，使用C:\mysql\bin\mysqld --help显示所有的选项目！例如，如果你移动MySQL分发到“D:\programs\mysql”，你必须用D:\programs\mysql\bin\mysqld --basedir D:\programs\mysql来启动mysqld。

用登记的MySQL版本,你也可以创建一个“C:\my.cnf”文件来保存用于MySQL服务器的任何缺省选项。拷贝文件“\mysql\my-example.cnf”到“C:\my.cnf”并且编辑它来适用于你的安装。注意你应该用"/"而不是"\"指定所有的路径。如果你使用“\”，你需要指定两次(“\\”)，因为在MySQL 中“\”是转义字符，见4.15.4 选项文件。

4.12.2 在Win95/Win98上启动MySQL

MySQL使用 TCP/IP 把一个客户连接到一个服务器。（这将允许在你的网络上任何机器连接你的MySQL服务器)。因此，你必须在启动MySQL前在你的机器上安装TCP/IP，你可以在你的Windows CDROM上找到TCP/IP 。

注意：如果你正在使用一个旧的Win95版本(例如OSR2)，很有可能你有一个老的Winsock包！MySQL需要Winsock 2！你可从微软得到最新的Winsock。Win98有新的Winsock 2库作为缺省，这样上述不适用于Win98。

你能使用2个不同的MySQL服务器：

mysqld | 用完整调试和自动存储器分配检查编译
mysqld-opt | 对Pentium 处理器优化。

上面两个应该在任何 > = i386的Intel处理器上工作 。

为了启动mysqld服务器，你应该启动一个MSDOS窗口并键入：

C:\mysql\bin\mysqld

这将在一个没有窗口的背景启动mysqld。

你可以这样杀死MySQL服务器，执行：

C:\mysql\bin\mysqladmin -u root shutdown

注意Win95/Win98不支持命名管道的创建。在Win95/Win98上，你只能使用命名管道连接运行在一个NT服务器上的远程MySQL。

4.12.3 在NT上启动MySQL

Win95/Win98小节也适用于在NT上的MySQL，有下列差别：

为了是MySQL用TCP/IP工作，你必须安装服务包3(service pack 3)(或更新)！

对于NT，服务器名字是mysqld-nt。通常你应该在 NT 上安装MySQL作为一种服务：

C:\mysql\bin\mysqld-nt --install

（你可以在 NT 上使用mysqld或mysqld-opt服务器，但是那些不能作为一种服务启动或使用命名管道。）

你可以用下列命令启动和停止MySQL服务：

NET START mysql
NET STOP mysql

注意在这种情况下，你不能对mysqld-nt使用任何其他选项!

如果你需要用任何选项启动mysqld-nt，你也可以作为在NT上的一个独立程序运行mysqld-nt！如果你在NT上没有选项启动mysqld-nt，mysqld-nt尝试启动自己作为一种有默认选项的服务。如果你停止了mysqld-nt，你必须用NET START mysql启动它。

服务用MySql名字被安装，一旦安装，它必须使用服务控制管理器(SCM)实用程序启动服务(在控制面板中找到)或使用NET START MySQL命令。如果需要任何选项，在你启动MySQL服务前必须作为SCM实用程序的“启动参数”指定它们。一旦运行，可使用mysqladmin或从SCM实用程序或使用命令NET STOP MySQL停止mysqld-nt。如果你使用SCM停止mysqld-nt，SCM有一条关于mysqld shutdown normally奇怪的消息，当作为一种服务运行时，mysqld-nt没有控制台的存取权限，所以没有消息可以看见。

在NT上你可以得到下列服务错误消息：

Permission Denied （权限拒绝） | 意味着它不能找到mysqld-nt.exe
Cannot Register （不能登记） | 意味着路径是不正确的

如果你作为一种服务安装mysqld-nt有问题，尝试用完整的路径启动它：

C:\mysql\bin\mysqld --install

如果这还不工作，你能通过在注册表修正路径使得mysqld-nt正确启动！

如果你不想作为一种服务启动mysqld-nt，你可以如下启动它：

C:\mysql\bin\mysqld-nt --standalone

或

C:\mysql\bin\mysqld-nt --standalone --debug

最新的版本在“C:\mysqld.trace”给你一个调试踪迹。

4.12.4 在 Win32 上运行 MySQL

MySQL在所有Win32平台上支持TCP/IP和NT上命名管道。如果客户安装了TCP/IP，缺省是对NT上的本地连接使用命名管道而对所有其他情形使用TCP/IP，主机名指定使用哪个协议：

主机名 | 协议
空 (没有） | 在NT上，首先尝试命名管道；如果它不工作，使用TCP/IP。在Win95/Win98上，使用TCP/IP。
. | 命名管道
localhost | TCP/IP到当前主机
主机名 | TCP/IP

通过指定命名管道--pipe选项，你可以强制一个MySQL客户使用命名管道。使用--socket选项指定管道的名字。

通过执行下列命令，你能测试MySQL是否正在工作：

C:\mysql\bin\mysqlshow
C:\mysql\bin\mysqlshow -u root mysql
C:\mysql\bin\mysqladmin version status proc
C:\mysql\bin\mysql test

如果在Win95/Win98上mysqld很慢地回答连接，可能你的DNS有问题。在这种情况中下，用--skip-name-resolve启动mysqld并且在MySQL授权表中仅使用localhost和IP数字。在你连接运行在NT上一个mysqld-nt的MySQL服务器时，使用--pipe指定命名管道使用的参数，你也能避开DNS，对大多数MySQL客户是可行的。

有2个版本的MySQL命令行工具：

mysql | 用原生Win32编译，它提供很有有限的文本编辑能力。
mysqlc | 用Cygnus GNU 编译器和库编译，它提供readline编辑。

如果你想使用mysqlc.exe，你必须拷贝“C:\mysql\lib\cygwinb19.dll”到“\windows\system”（或类似的地方)。

在Win32上缺省的权限给所有本地用户以所有数据库的完全权限。为了使MySQL更安全，你应该为每个用户设置口令并删除mysql.user中有Host='localhost'和User=''的行。

你也应该为root用户增加一个口令：（下列例子通过删除匿名用户，允许任何人存取“测试”数据库）

C:\mysql\bin\mysql mysql
mysql> DELETE FROM user WHERE Host='localhost' AND User='';
mysql> QUIT
C:\mysql\bin\mysqladmin reload
C:\mysql\bin\mysqladmin -u root password your_password

在你设置了口令以后，如果你想要关掉mysqld服务器, 你能使用这个命令做到：

mysqladmin -- user=root -- password=your_password  shutdown

如果你正在使用在windows下的MySQL共享软件版本，上面的命令将以 parse error near 'SET OPTION password'的错误而失败，这是因为，这是共享软件版本，它基于MySQL 3.21，没有SET PASSWORD命令。

对共享软件版本，你能如下设置root用户口令：

C:\mysql\bin\mysql mysql
mysql> UPDATE user SET password=PASSWORD('your password') WHERE user='root';
mysql> QUIT
C:\mysql\bin\mysqladmin reload

有注册的MySQL版本，你能很容易地用GRANT和REVOKE命令增加新用户和更改权限，见7.26 GRANT和REVOKE句法。对Windows 的共享软件版本，必须使用INSERT、UPDATE和DELETE在mysql数据库中的一个表来管理用户和他们的权限，见6.13 存取拒绝（Access denied）的错误原因。

4.12.5 用SSH从Win32连接一个远程MySQL

这是一个关于怎样用SSH 得到一个安全的连接远程MySQL服务器的注意事项(David Carlson)。

  • 在你的windows机器上安装SSH客户 - 我使用了一个来自http://www.doc.ic.ac.uk/~ci2/ssh/的免费SSH客户。其他有用的链接：http://www.npaci.edu/Security/npaci_security_software.html和http://www.npaci.edu/Security/samples/ssh32_windows/index.html.
  • 启动SSH。设置主机名字 = 你的MySql服务器名或IP地址，设置userid=你的用户名登录到你的服务器。
  • 点击“local forwords”。设定local port: 3306, host: localhost, remote port: 3306
  • 保存一切，否则下次你将必须再做一遍。
  • 用SSH登录到你的服务器。
  • 启动一些ODBC应用程序(例如Access）。
  • 创造一个新文件并且用ODBC驱动程序链接到mySQL，就像你通常做的一样，除了对服务器用用户“localhost”。

搞定。它对一个直接的因特网连接工作得很好。我有些问题，SSH与我的Win95网络和Wingate有冲突 - 但是那将是张贴在其他软件公司的用户组的话题！

4.12.6 MySQL-Win32与Unix MySQL比较

MySQL- Win32现在已经证明了自己很稳定。这个版本得MySQL有与对应的Unix版本同样的特征，除了下面：

Win95和线程
Win95 为每个线程的创建损失大约200个字节的内存。因此，如果你进行许多连接，你不应该在Win95运行mysqld很长时间，因为MySQL的每个连接都创建一个新线程！WinNT和Win98不能容忍这个bug。
阻塞式读（blocking read）
MySQL为每个连接使用一个阻塞式读取，这意味着：
  • 一个连接将不在8个小时后自动被断开，就像MySQL的Unix版本所发生的。
  • 如果一个连接“挂起”，不杀死MySQL就不可能打破它。
  • mysqladmin kill在一个睡眠的连接上将不工作。
  • 只要有睡眠的连接，mysqladmin shutdown不能中途中断。

我们计划在不久的将来修正它。

UDF函数
暂时MySQL-Win32不支持用户可定义函数。
DROP DATABASE
你不能抛弃一个正在被某些线程使用的数据库。
从任务管理器杀死MySQL
在Windows95上，你不能从任务管理器或用shutdown实用程序杀死MySQL。你必须用mysqladmin shutdown关闭它。
大小写区分的名字
文件名在Win32上是忽略大小写的，因此Win32上的MySQL数据库和表的名字也是忽略大小写的。唯一的限制是数据库和表的名字必须在整个一个给定的语句中大小写是一样的，因为它用my_table和MY_TABLE都指向同一个表子，下列查询将不工作：
SELECT * FROM my_table WHERE MY_TABLE.col=1;
“ \ ”目录字符
在Win95上的路径名组成由“\”字符分隔，它在MySQL中也是转义字符。如果你正在使用LOAD DATA INFILE或SELECT ... INTO OUTFILE，你必须用两个“\”字符或使用Unix风格的文件名“/”字符：
LOAD DATA INFILE "C:\\tmp\\skr.txt" INTO TABLE skr;
SELECT * FROM skr INTO OUTFILE 'C:/tmp/skr.txt';
Can't open named pipe错误
如果你使用NT上的MySQL-Win32共享软件版本，用最新的mysql客户，你将得到下列错误：
error 2017: can't open named pipe to host: . pipe...

这是因为NT上MySQL正式版本缺省地使用命名管道。你能通过为新MySQL客户使用--host=localhost选项或创建一个包含下列信息的文件“C:\my.cnf”来避免这个错误：

[client]
host = localhost
Access denied for user错误
在访问在同一机器上的一个MySQL服务器时，如果你得到Access denied for user: 'some-user@unknown' to database 'mysql'的错误，这意味着MySQL不能正确解释你的主机名。为了修正它，你应该创建一个文件“\windows\hosts”，有下列信息：
127.0.0.1  localhost

对于可能想要帮助我们做好Win32版本的任何人，这里有的一些开放的问题：

  • 制作一个单用户MYSQL.DLL服务器。这应该包括一个标准MySQL服务器的一切，除了线程创建外。这将使MySQL在不需要一个真正的客户机/服务器和不需要从其他主机存取服务器的应用程序时更容易使用。
  • 为MySQL安装增加一些漂亮的“start”和“shutdown”图标。
  • 为MySQL启动选项创建造一个工具管理注册表条目。注册表条目的度缺已经被编码进mysqld.cc，但是它应该重新编码而更加面向“参数”，该工具应该也能更新“ \my.cnf”文件，如果用户比较喜欢使用它而不是注册表。
  • 当用--install登记mysqld作为一种服务（在 NT 上 )时，如果你也可以在命令行上增加缺省选项，它将更好，目前解决办法是更新“C:\my.cnf”文件。
  • 当你挂起一个运行Win95的膝上计算机时，当膝上计算机被恢复时，mysqld守护程序不接受新连接。我们不知道这是否 Win95、TCP/IP或MySQL的问题。
  • 能从任务管理器杀死mysqld将绝对是好事，目前，你必须使用mysqladmin shutdown。
  • 移植用在 mysql命令行工具的readline到Win32。
  • 标准的GUI版本MySQL客户(mysql、mysqlshow、mysqladmin和mysqldump) 将更好。
  • 如果在“net.c”中的套接字“读”和“写”函数是可中断的，那将更好。这将有可能在Win32上用mysqladmin kill杀死打开的线程。
  • 制作有关哪些Windows程序能工作在MySQL-Win32/MyODBC和必须做什么在能让他们工作的文档。
  • mysqld总是在“C”处启动而不在缺省地点，我们想让mysqld使用当前地点用于排序顺序。
  • 移植sqlclient到Win32(几乎完成)并加入更多的特征！
  • 把更多的选项加到Mysql Manager。
  • 在服务器和客户之间改变通讯协议，使用Windows内部通讯而不是套接字和TCP/IP。
  • 用.DLL实现UDF函数。
  • 增加宏以使用由Win32提供的更快的对线程安全的增加/减少方法。

其他Win32特定问题在MySQL-Win32分发的“README”文件中描述。

4.13 OS/2 注意事项

MySQL使用太多的打开文件。因此，你应该增加类似下面的东西到你的“CONFIG.SYS”文件：

SET EMXOPT=-c -n -h1024

如果你不这样做，你将可能碰到下列错误：

File 'xxxx' not found (Errcode: 24)

当OS/2 Warp 3上使用MySQL时，要求FixPack 29或以上。用OS/2 Wrap 4，要求FixPack 4或以上。这是Pthreads库的一个要求。MySQL必须安装在支持长文件名的一个分区上，如HPFS、FAT32等等。

“INSTALL.CMD”脚本必须从OS/2'自己的“CMD.EXE”运行并且不能工作在替代品如“4OS2.EXE”。

“scripts/mysql-install-db”脚本已经被重新命名了：它现在调用“install.cmd”并且是一个 REXX 手迹，将安装缺省的MySQL安全配置并为MySQL创建WorkPlace Shell 图标。

动态模块支持通过编译但没有充分测试，动态模块应该使用Pthreads运行时刻库编译。

gcc -Zdll -Zmt -Zcrtdll=pthrdrtl -I../include -I../regex -I.. \
    -o example udf_example.cc -L../lib -lmysqlclient udf_example.def
mv example.dll example.udf

注意：由于OS/2的限制，UDF模块名字的词干不能超过8个字符。模块被存储在“/mysql2/udf”目录；safe-mysqld.cmd脚本将把这个目录放在BEGINLIBPATH环境变量中。当使用UDF模块时，指定的扩展名被忽略--它被假定为“.udf”。例如，在 Unix上，共享模块可能被命名为“example.so”并且你可以象这样从它装载函数：

CREATE FUNCTION metaphon RETURNS STRING SONAME "example.so";

正是OS/2，模块将被命名为“example.udf”，但是你不指定模块扩展名：
CREATE FUNCTION metaphon RETURNS STRING SONAME "example";

4.14 TcX二进制代码

作为一种服务，TcX提供一套MySQL的二进制分发，它在TcX或在客户友好地给与我们访问他们机器的权限的站点上被编译。

这些分发用scripts/make_binary_distribution生成并且用下列编译器和选项配置：

SunOS 4.1.4 2 sun4c with gcc 2.7.2.1
CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --disable-shared
SunOS 5.5.1 sun4u with egcs 1.0.3a
CC=gcc CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-low-memory
SunOS 5.6 sun4u with egcs 2.90.27
CC=gcc CFLAGS="-O6 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-low-memory
SunOS 5.6 i86pc with gcc 2.8.1
CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-low-memory
Linux 2.0.33 i386 with pgcc 2.90.29 (egcs 1.0.3a)
CFLAGS="-O6 -mpentium -mstack-align-double -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -mpentium -mstack-align-double -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --enable-assembler --with-mysqld-ldflags=-all-static
SCO 3.2v5.0.4 i386 with gcc 2.7-95q4
CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
AIX 2 4 with gcc 2.7.2.2
CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
OSF1 V4.0 564 alpha with gcc 2.8.1
CC=gcc CFLAGS=-O CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql --with-low-memory
Irix 6.3 IP32 with gcc 2.8.0
CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql
BSDI BSD/OS 3.1 i386 with gcc 2.7.2.1
CC=gcc CXX=gcc CXXFLAGS=-O ./configure --prefix=/usr/local/mysql
BSDI BSD/OS 2.1 i386 with gcc 2.7.2
CC=gcc CXX=gcc CXXFLAGS=-O3 ./configure --prefix=/usr/local/mysql

任何有比上述配置更优的选项的人总是能把他们寄给开发者邮件列表中。

MySQL3.22以前的RPM分发是用户贡献的，自3.22开始，一些RPM是TcX 生成的。

4.15 安装后期的设置和测试

一旦你已经安装了MySQL（从一个二进制代码或源代码分发)，你需要初始化授权表，启动服务器并且保证服务器正确运行。你也可以希望安排服务器在你的系统开机和关机时自动地被启动和停止。

通常，对从源代码分发的安装，你象这样安装授权表并启动服务器：

shell> ./scripts/mysql_install_db
shell> cd mysql_installation_directory
shell> ./bin/safe_mysqld &

对二进制分发，这样做：

shell> cd mysql_installation_directory
shell> ./bin/mysql_install_db
shell> ./bin/safe_mysqld &

测试在MySQL发行的顶级目录是最容易进行的。对二进制分发，这是你的安装目录(典型地类似“/usr/local/mysql”)。对源代码分发，这是你的MySQL源代码树的主目录。

在本小节和以后的小节中，下列命令中，BINDIR是到程序如mysqladmin和safe_mysqld被安装地点的路径。对二进制分发，是在分发内的“bin”目录。对源代码分发，BINDIR可能是“/usr/local/bin”，除非在你运行configure时指定了一个“ /usr/local”以外的安装目录。EXECDIR是mysqld服务器安装的地点，对二进制分发，这与BINDIR一样。对源代码分发，EXECDIR可能是“/usr/local/libexec”。

测试详细在下面描述：

  1. 如果必要，启动mysqld服务器并且建立初始MySQL授权表，包含决定用户如何被允许连接服务器的权限。这通常用mysql_install_db脚本做：
    shell> scripts/mysql_install_db

    典型地，mysql_install_db仅在你第一次安装MySQL时需要运行，因此，如果你正在升级现有的安装，你可以跳过这一步。（然而，mysql_install_db的使用相当安全，并且将不更新已经存在的任何表，因此如果你是不能肯定做什么，你总是可以运行mysql_install_db。) mysql_install_db在mysql数据库里创建6个表(user、db、host、tables_priv、columns_priv和func)，初始权限的描述在6.10 设置初始MySQL权限给出。简单地说，这些权限允许MySQL root用户做任何事情，并且允许任何人创建立或使用一个名字以'test'或'test_'开始的数据库。如果你不设置权限表，当你启动服务器时，下列错误将在日志文件出现：

    mysqld: Can't find file: 'host.frm'

    如果你不是通过明显地执行./bin/safe_mysqld来启动MySQL，上述错误可能也发生在MySQL二进制代码分发！你可能需要作为root运行mysql_install_db，然而，如果你喜欢， 如果用户能在数据库目录读并且写文件，你可以作为一个非特权(非--root)用户运行MySQL服务器。作为一个非特权用户运行MySQL的指令在18.8 怎样作为一个一般用户运行 MySQL中给出。如果你有mysql_install_db的问题，见4.15.1 运行mysql_install_db的问题。因为mysql_install_db在MySQL发行中，还有一些其他方法运行它：

    • 你可能想在运行mysql_install_db前编辑它，改变被安装到授权表中的初始权限。如果你想要在有相同权限的很多机器安装MySQL，这很有用。在这种情况下，你可能应该只需要增加几个额外的INSERT语句到mysql.user和mysql.db表中！
    • 如果你想要在安装授权表后改变什么，你可以运行mysql_install_db，然后使用mysql -u root mysql作为MySQL root用户连接授权表，发出SQL语句直接修改授权表。
    • 在已经创建了授权表后，有可能全部再次创建。如果你已经安装了表但是随后又想要在编辑mysql_install_db以后再创建，你可能想要这样做。

    关于这些选项的更多信息，见6.10 建立初始MySQL权限。

  2. 象这样启动MySQL服务器：
    shell> cd mysql_installation_directory
shell> bin/safe_mysqld &

    如果你启动服务器的问题，见4.15.2 启动MySQL服务器的问题.

  3. 使用mysqladmin证实服务器正在运行。下列命令提供简单的测试来检查服务器启动和连接的应答：
    shell> BINDIR/mysqladmin version
shell> BINDIR/mysqladmin variables

    从mysqladmin version的输出根据你的平台和MySQL版本略有不同，但是应该类似如下显示：
    shell> BINDIR/mysqladmin version
mysqladmin  Ver 6.3 Distrib 3.22.9-beta, for pc-linux-gnu on i686
TCX Datakonsult AB, by Monty

Server version          3.22.9-beta
Protocol version        10
Connection              Localhost via UNIX socket
TCP port                3306
UNIX socket             /tmp/mysql.sock
Uptime:                 16 sec

Running threads: 1  Questions: 20  Reloads: 2  Open tables: 3

    为了感觉你能用BINDIR/mysqladmin做其他事情，用--help选项调用它。

  4. 证实你能关掉服务器：
    shell> BINDIR/mysqladmin -u root shutdown
  5. 证实你能重启服务器。使用safe_mysqld或直接调用mysqld进行，例如：
    shell> BINDIR/safe_mysqld --log &

    如果safe_mysqld失败，从MySQL安装目录尝试运行它(如果你已经不在那里)。如果还不工作，见4.15.2 启动MySQL服务器的问题。

  6. 运行一些简单的测试证实服务器正在工作。输出应该类似于下面所显示的：
    shell> BINDIR/mysqlshow
+-----------+
| Databases |
+-----------+
| mysql     |
+-----------+

shell> BINDIR/mysqlshow mysql
Database: mysql
+--------------+
|    Tables    |
+--------------+
| columns_priv |
| db           |
| func         |
| host         |
| tables_priv  |
| user         |
+--------------+

shell> BINDIR/mysql -e "select host,db,user from db" mysql
+------+--------+------+
| host | db     | user |
+------+--------+------+
| %    | test   |      |
| %    | test_% |      |
+------+--------+------+

    在“sql-bench”目录(在MySQL安装目录下)下还有基准测试套件，你能用来比较在不同的平台上MySQL表现如何。“ sql-bench/Results”目录包含对不同的数据库和平台许多运行结果。为了运行所有的测试，执行这些命令：

    shell> cd sql-bench
shell> run-all-tests

    如果你没有“sql-bench”目录，你可能在对二进制分发使用一个RPM（源代码分发的RPM包括基准目录)。在这种情况下，在你能使用它以前，你必须首先安装基准套件。从MySQL 3.22开始，有名为“mysql-bench-VERSION-i386.rpm”的基准RPM包，它们包含基准代码和数据。如果你有源代码分发，你也可以在“tests”子目录下运行测试。例如，运行“auto_increment.tst”，这样做：

    shell> BINDIR/mysql -vvf test < ./tests/auto_increment.tst

    期望的结果被显示在“ ./tests/auto_increment.res”文件中。

4.15.1 运行mysql_install_db的问题

这节列出在你运行mysql_install_db时，你可能遇见的问题：

mysql_install_db不安装授权表
在显示下列消息以后，你可以发现mysql_install_db不能安装授权表并终止：
starting mysqld daemon with databases from XXXXXX
mysql daemon ended

在这种情况下，你应该很小心地检验日志文件！日志文件应该位于目录“XXXXXX”，用错误消息命名，并且应该指出为什么mysqld没启动。如果你不理解发生的事情，当你使用mysqlbug邮寄一份错误报告时，包含日志文件！见2.3 怎样报告错误或问题。

已经有一个mysqld守护程序在运行
在这种情况下，你可能根本不必运行mysql_install_db。当你第一次安装MySQL时，你必须只运行mysql_install_db一次。
当一个守护进程正在运行时，安装第二个mysqld守护进程不工作
这只有在当你已经有已存在的MySQL安装但是想要把新安装放在一个不同的地方时才会发生(例如，为了测试或者也许你简单地想要同时运行2个安装)。通常当你试着运行第二个服务器时，发生的问题是它试图和旧一个使用同样的套接字和端口。在这种情况下，你将得到错误消息：Can't start server: Bind on TCP/IP port: Address already in use或Can't start server : Bind on unix socket...你能用一个不同的套接字和端口启动新的服务器，如下：
shell> MYSQL_UNIX_PORT=/tmp/mysqld-new.sock
shell> MYSQL_TCP_PORT=3307
shell> export MYSQL_UNIX_PORT MYSQL_TCP_PORT
shell> scripts/mysql_install_db
shell> bin/safe_mysqld &

在这以后，你应该编辑你的服务器引导脚本手迹用不同的套接字和端口启动两个守护进程。例如，它能调用safe_mysqld两次，但是对每次调用使用不同的--socket、--port和--basedir选项。

你没有“ /tmp ”的写权限
如果你没有写权限在缺省地方(在“/tmp”里)创建一个套接字文件，或没有在“/tmp”创建临时文件的许可，在运行mysql_install_db或当启动或使用mysqld时，你将得到一个错误。你可以如下地指定一个不同的套接字和临时目录：
shell> TMPDIR=/some_tmp_dir/
shell> MYSQL_UNIX_PORT=/some_tmp_dir/mysqld.sock
shell> export TMPDIR MYSQL_UNIX_PORT

“some_tmp_dir”应该是你有写许可的某个目录的路径。在这以后，你应该能运行mysql_install_db并且这些命令启动服务器：

shell> scripts/mysql_install_db
shell> BINDIR/safe_mysqld &
mysqld立刻崩溃
如果你正在运行RedHat 5.0，有一个比2.0.7-5旧的glibc版本，你应该保证你安装了glibc所有补丁！在MySQL邮件档案中有很多关于它的信息。邮件档案的链接可在联机MySQL文档页得到。也可见4.11.5 Linux 注意事项(所有Linux版本）。你也可以手工启动mysqld，使用--skip-grant选项并且增加使用mysql本身的权限信息：
shell> BINDIR/safe_mysqld --skip-grant &
shell> BINDIR/mysql -u root mysql

从mysql，手工执行在mysql_install_db里面的SQL命令。保证你随后运行mysqladmin reload告诉服务器再装入授权表。

4.15.2 启动MySQL服务器的问题

通常，你用3个方法之一启动mysqld服务器：

  • 通过调用mysql.server。这个脚本主要用于系统启动和关闭，更全面的描述在4.15.3 自动启动和停止MySQL。
  • 通过调用safe_mysqld，它试图为mysqld决定正确的选项并然后用那些选择运行它。
  • 通过直接调用mysqld。

无论你使用哪个方法启动服务器，如果它没有正确启动，检查日志文件看你是否能发现为什么。日志文件位于数据目录(对二进制分发一般是“/usr/local/mysql/data”，对源代码分发是“/usr/local/var”)。用“host_name.err”和“host_name.log”形式的名字在数据目录下查找文件，这里host_name是你服务器主机的名字，然后检查这些文件的最后几行：

shell> tail host_name.err
shell> tail host_name.log

当mysqld守护进程启动时，它把目录改变到数据目录。这是它期望写日志文件和pid(进程ID)文件的地方，和它期望在那儿找到数据库。

数据目录地点是在分发编译时定死的。然而，如果mysqld期望它在你的系统上其他某个地方找到数据目录，它将工作不正常。如果你有不正确路径的问题，你可使用--help选项调用mysqld，找到mysqld允许什么选项和缺省路径设置是什么。你能通过指定正确的路径作为mysqld命令行参数来覆盖缺省值。（这些选择也能用于safe_mysqld。）

通常你应该只需要告诉mysqld基本目录，在它下面安装MySQL。你可以用--basedir选项做到，你也能使用--help检查改变路径选项的效果(注意，--help 必须是mysqld命令的最后选项)。例如：

shell> EXECDIR/mysqld --basedir=/usr/local --help

一旦你确定你想要的路径设置，不用--help选项启动服务器。

如果你得到下列错误，它意味着mysqld正在试图使用某些其他程序(或其他mysqld服务器)已经正在使用TCP/IP端口或套接字：

Can't start server: Bind on TCP/IP port: Address already in use
  或
Can't start server : Bind on unix socket...

使用ps保证你没有另外一个mysqld服务器正在运行。如果你不能发现其他运行的服务器，你可以尝试执行命令telnet your-host-name tcp-ip-port-number并且按几次RETURN键，如果你没有得到一个错误消息，像telnet: Unable to connect to remote host: Connection refused，某个东西正在使用mysqld正在试图使用的TCP/IP端口，见4.15.1 运行mysql_install_db的问题和19.3 在同一台机器上运行多个MySQL服务器。

safe_mysqld脚本被编写以便能正常地启动一个从MySQL源代码或二进制代码版本安装的服务器，就算这些在稍微不同的地点安装服务器。safe_mysqld希望这些条件之一是真的：

  • 服务器和数据库能在相对safe_mysqld被调用的目录下找到。safe_mysqld在它的工作目录下面找“bin”和“data”目录(对二进制分发)或“libexec”和“var”目录(对源代码分发)。如果你从你的MySQL安装目录(例如，对二进制分发为“/usr/local/mysql”)执行safe_mysqld，这个条件应该满足。
  • 如果服务器和数据库不能在相对其工作目录找到，safe_mysqld试图通过绝对路径找到他们。典型的地点是“ /usr/local/libexec”和“/usr/local/var”。实际的地点在构造来自分发的safe_mysqld时确定，如果MySQL安装在一个标准的地点，他们应该是正确的。

因为safe_mysqld将试图在相对它自己的工作目录下找到服务器和数据库，你可以在任何地方安装MySQL的二进制分发，只要你从MySQL安装目录启动safe_mysqld即可：

shell> cd mysql_installation_directory
shell> bin/safe_mysqld &

如果safe_mysqld失败，甚至在从MySQL安装目录调用时，你可以修改它以便使用到mysqld路径并且对你的系统的路径选项是正确的。注意，如果在将来你升级MySQL，你的safe_mysqld修改版本将被覆盖，因此你应该做一个你能重新安装的编辑过的版本的拷贝。

如果mysqld当前正在运行，通过执行这个命令，你能发现它正在使用什么路径设置：

shell> mysqladmin variables

或

shell> mysqladmin -h 'your-host-name' variables

如果safe_mysqld启动服务器但是你不能与它连接，你应该保证你在“/etc/hosts”里面有一个条目，看起来像这样：

127.0.0.1  localhost

这个问题仅发生在没有一个能工作的线程库的系统上并且对该系统MySQL必须配置为使用MIT-pthreads。

4.15.3 自动启动和停止MySQL

mysql.server脚本可以被用来启动或停止服务器，通过用start或stop参数调用它：

shell> mysql.server start
shell> mysql.server stop

mysql.server可在MySQL安装目录下的“share/mysql”目录里找到，或在MySQL源代码树的“support-files”目录下找到。

在mysql.server启动服务器之前，它把目录改变到MySQL安装目录，然后调用safe_mysqld。如果你有在一个非标准的地点安装的二进制分发，你可能需要编辑mysql.server。修改它，运行safe_mysqld前，cd到正确的目录。如果你想要作为一些特定的用户运行服务器，你可以改变mysql_daemon_user=root行使用其他用户，你也能修改mysql.server把其他选项传给safe_mysqld。

mysql.server stop通过向服务器发出一个信号停止它。你可手工执行mysqladmin shutdown关闭服务器。

当你开始使用MySQL作为生产应用时，你可能想要增加这些启动并且停止命令到在你的“/etc/rc * 文件中适当的地方。注意如果你修改mysql.server，那么如果某个时候你升级MySQL时，你的修改版本将被覆盖，因此你应该做一个你可重新安装的编辑过的版本的拷贝。

如果你的系统使用“/etc/rc.local”启动外部脚本，你应该添加下列到其中：

/bin/sh -c 'cd /usr/local/mysql ; ./bin/safe_mysqld &'

你也可以在一个全局“/etc/my.cnf”文件中增加mysql.server的选项。一个典型的“/etc/my.cnf”文件可能看起来像这样：

mysqld]
datadir=/usr/local/mysql/var
socket=/tmp/mysqld.sock
port=3306

[mysql.server]
user=mysql
basedir=/usr/local/mysql

mysql.server脚本使用下列变量：user、datadir、basedir、bindir和pid-file。

见4.15.4 选项文件。

4.15.4 选项文件

MySQL3.22 可以从选项文件中为服务器和客户读取缺省启动选项。

在Unix上，MySQL从下列文件读取缺省选择：

文件名 | 用途
/etc/my.cnf | 全局选项
DATADIR/my.cnf | 服务器特定的选项目
~/.my.cnf | 用户特定的选项

DATADIR是MySQL的数据目录(典型地对二进制安装是“/usr/local/mysql/data”或对源代码安装是“/usr/local/var”)。注意：这是在配置时间指定的目录，不是mysqld启动时用--datadir指定的目录！(--datadir在服务器寻找选项文件的地方无效，因为它以前寻找他们，它处理任何命令行参数。）

MySQL在Win32上从下列文件读取缺省选项：

文件名 | 用途
windows-system-directory\my.ini
C:\my.cnf | 全局选项
C:\mysql\data\my.cnf | 服务器特定的选项

注意，在Win32上你应该用/而不是\指定所有的路径，如果你使用\，你需要指定两个，因为在MySQL里面\是转义字符。

MySQL试图以上述所列的顺序读取选项文件。如果存在多个选项文件，在一个后面文件读取的选项优先于在先前读取的一个文件中指定的同一个选项，在命令行上指定的选项优先于在任何选项文件指定了的选项。有些选择能使用环境变量指定，在命令行或在选项文件指定的选项优先于环境变量。

下列程序支持选项文件：mysql、mysqladmin、mysqld、mysqldump、mysqlimport、mysql.server、myisamchk和myisampack。

你能使用选项文件指定一个程序支持的任意长的选项！用--help选项运行程序可得到的可用选项的表。

一个选项文件可以包含下列形式的行：

#comment
注释行以“#”或“;”开始，空行被忽略。
[group]
group是你想为其设置选项的程序或组的名字。在一个组行后，任何option或set-variable行应用于命名的组，直到选择文件结束或其他组的给出。
option
这等价于在命令行上的--option。
option=value
这等价于在命令行上的--option=value。
set-variable = variable=value
这等价于在命令行上的--set-variable variable=value。该语法必须被用来设置一个mysqld变量。

client组允许你指定适用于所有MySQL客户的选项(不是mysqld)。这是理想的组来指定你用来与服务器连接的口令。（但是保证只是选项文件本身是可读的和可写的。）

注意，对域选项和值，所有头部和尾部空白自动被删除。你可以在的值串中使用转义顺序“\b”、“\t”、“\n”、“\r”、“\\”和“\s”(“\s”==空白)。

这是一个典型的全局选项文件：

[client]
port=3306
socket=/tmp/mysql.sock
[mysqld]
port=3306
socket=/tmp/mysql.sock
set-variable = key_buffer=16M
set-variable = max_allowed_packet=1M

[mysqldump]
quick

这是典型的用户选项文件：

[client]
# The following password will be sent to all standard MySQL clients
password=my_password

[mysql]
no-auto-rehash

如果你有一个源代码分发，你将在“support-files”目录下找到一个名为“my-example.cnf”样品配置文件。如果你有二进制分发，在“DIR/share/mysql”目录下查找，在此DIR是MySQL安装目录的路径(一般是“/usr/local/mysql”)。你可以拷贝“my-example.cnf”到你的主目录(重新命名拷贝为“.my.cnf”)来试验。

为了告诉一个MySQL程序不读任何选项文件，在命令行上指定--no-defaults作为第一个选项。这必须是第一个选项，否则它将无效！如果你想检查使用哪个选项，你可以给出--print-defaults选项作为第一个选项。

如果你想要强制使用一个特定配置文件，你可以使用选项--defaults-file=full-path-to-default-file。如果你这样做，只有指定的文件将被读取。

开发者注意：选项文件的处理简单地通过处理所有在任何命令行前参数的匹配选项来实现(即，在适当的组里的选项)，这对使用多次指定的一个选项的最后实例的程序工作的很好。如果你有这样一个处理多重指定选项但不读选项文件的旧程序， 你只需要增加2行给与它那种能力。检查任何标准的MySQL客户的源代码看怎样做。

4.16 升级/降级MySQL时有什么特别的事情要做？

只要你有MySQL同一个的基础版本，你总可以在同样的体系结构上的不同版本之间的移动MySQL表格(form)和数据文件。当前的基础版本是3。如果你通过重新编译MySQL改变字符集（也可以改变排序顺序)，你必须在所有的表上运行myisamchk -r -q，否则你的索引不能正确被排序。

如果你偏执于或担心新版本，你总能重新命名的旧mysqld为类似于mysqld-'old-version-number'。那么如果你的新mysqld做一些意外的事情，你可以简单地关掉它并重启你的旧mysqld！

当你做一个升级时，当然你也应该备份你的旧数据库。有时有点偏执狂是好的！

在升级后，如果你重新编译客户程遇到问题，像Commands out of sync或意外的核心倾倒，在编译你的程序时，你可能使用了一个旧的头文件或库文件。在这种情况下，你应该检查你的“mysql.h”文件和“libmysqlclient.a”库文件的日期以证实他们来自新的MySQL发行。如果不是，请重新编译你的程序！

如果你有些问题，新的mysqld服务器不想启动或你不能没有口令连接，检查你确实没有来自你的旧安装的一些旧的“my.cnf”文件！你可以用program-name --print-defaults检查。如果这输出任何非程序名字的任何东西，你有一个活跃my.cnf文件将可以影响一些事情！

无论何时你安装一个新版本的MySQL，重新构造并重新安装Msql-Mysql-modules分发是一个好主意，特别是在升级MySQL后，如果你注意到诸如你的所有DBI脚本倾倒核心症状。

4.16.1 从一个3.22版本升级到3.23

MySQL 3.23支持新MyISAM类型和旧ISAM类型的表。你不必须变换你的旧式表给3.23使用。缺省地，所有的新表将用类型MyISAM创建（除非你使用--default-table-type=isam选项启动mysqld）。你可以用ALTER TABLE或Perl脚本mysql_convert_table_format将一个ISAM表转换成一个MyISA表。

3.22和3.21客户将毫无问题地与一个3.23服务器一起工作。

当升级到3.23时，下面列出你必须注意的事情：

  • INNER和DELAYED现在是保留字。
  • FLOAT(X)现在是一个真正的浮点类型。
  • 当声明DECIMAL(length,dec)时，长度参数不再包括一个符号或小数点位置。
  • 一个TIME字符串必须是下列现有格式之一：[[[DAYS] [H]H:]MM:]SS[.fraction]或[[[[[H]H]H]H]MM]SS[.fraction]。
  • 现在，LIKE使用'='同样的字符比较规则比较字符串。如果你要求旧的行为，你可以用CXXFLAGS=-DLIKE_CMP_TOUPPER标志编以MySQL。
  • REGEXP现在对正常(不是二进制的)字符串是忽略大小写的。
  • 在你检查/修复表时，对MyISAM表(.MYI)，你应该使用myisamchk，而对ISAM(.ISM)表使用isamchk。
  • 如果你想要你的mysqldumps在MySQL3.22和3.23之间兼容，你应该不使用mysqldump的--opt或--full选项。
  • 检查所有对DATE_FORMAT()的调用，保证在在每个格式字符前有一个“%”。
  • mysql_fetch_fields_direct现在是函数(它以前是一个宏)并且它返回一个指向MYSQL_FIELD的指针而不是一个MYSQL_FIELD。
  • mysql_num_fields()可以不再被用在一个MYSQL*对象上(它现在是一个函数，拿MYSQL_RES*作为一个参数）。相反你现在应该使用mysql_field_count()。
  • 在MySQL3.22，SELECT DISTINCT ...的输出几乎总是被排序的。在3.23上，你必须使用GROUP BY或ORDER BY获得排序的输出。
  • 如果没有匹配的行，SUM()现在返回NULL，而不是 0。这是遵照ANSI SQL。
  • 新的限制词：CASE、THEN、WHEN、ELSE和END。

4.16.2 从一个3.21版本升级到3.22

没有影响相容性的东西在3.21和3.22之间已改变。唯一的缺陷是用DATE类类型创建的新表将使用新方法存储日期。你不能从一个mysqld旧版本存取这些新字段。

在安装MySQL3.22 以后，你应该启动新的服务器并且然后运行mysql_fix_privilege_tables脚本。这将增加你使用GRANT命令所需的新权限。如果你忘记了这个，当你试着使用ALTER TABLE, CREATE INDEX或DROP INDEX时，你将得到Access denied。如果你的MySQL根用户要求一个口令，你应该把它作为一个参数给mysql_fix_privilege_tables。

mysql_real_connect()的C API接口改变了。如果你有一个旧的客户程序调用该函数，你必须放一个0作为新db参数(或为了快速连接重新编码发送的db单元的客户)。你在mysql_real_connect()前也必须调用mysql_init()！做这个改变允许新的mysql_options()函数在MYSQL处理程序结构中保存选项。

4.16.3 从一个3.20版本升级到3.21

如果你正在运行一个比3.20.28旧的版本并且想要换到3.21.x，你需要做下列事情：

你能用safe_mysqld --old-protocol启动mysqld3.21服务器从3.20分发的客户使用它。在这种情况下，新客户函数mysql_errno()将不返回任何服务器错误，而仅仅是CR_UNKNOWN_ERROR(但是它为客户错误服务)并且服务器使用旧的passwd() 检查而非新的一个。

如果你在而不是对mysqld使用--old-protocol选项，你将需要做下列改变：

  • 所有的客户代码必须重新编译。如果你正在使用ODBC，你必须得到新的MyODBC 2.x驱动程序。
  • 脚本scripts/add_long_password必须运行以便变换在mysql.user表中的Password字段为CHAR(16)。
  • 所有在mysql.user中的口令必须被重新赋值(为了得到62位而非31位口令)。
  • 表格式没变化，因此你不必须变换任何表。

MySQL3.20.28和以上版本可以处理新的user表格式而不影响客户。如果你有一个比3.20.28早的MySQL版本，如果你变换user表，口令将不再与之工作。因此为了安全，你首先应该升级到至少3.20.28并且然后升级到3.21.x。

新的客户代码可与一个3.20.x 版的mysqld服务器一起工作，因此如果你遇到3.21.x的问题，你可以使用旧的3.20.x服务器而无须重新编译客户。

如果你对mysqld不使用--old-protocol选项，旧的客户将发出错误消息：

ERROR: Protocol mismatch. Server Version = 10 Client Version = 9

新的Perl DBI/DBD接口也支持旧的mysqlperl接口。如果你使用mysqlperl，你必须做的唯一改变是改变到connect()函数的参数。新参数是：host、database、user、password（user和password参数改变了位置)。见20.5.2 DBI接口。

下列变化可能影响到旧的应用程序的查询：

  • 现在HAVING必须在任何ORDER BY子句前被指定。
  • LOCATE()参数被交换了。
  • 有一些新的保留字。最著名是DATE、TIME和TIMESTAMP。

4.16.4 升级到其他体系结构

如果你正在使用MySQL3.23，你能在不同的支持同样浮点格式的体系结构之间拷贝.frm、.MYI和.MYD。(MySQL考虑了任何字节交换的问题)。

MySQL ISAM数据“ *.ISD”和索引文件“ *.ISM”文件是依赖于系统结构并在某些情况下依赖于OS。如果你想要移动你的应用程序到有与你当前系统不同的体系结构或OS的其他机器上，你不应该试图通过简单地拷贝文件到另外的机器上来移动一个数据库，相反使用mysqldump。

缺省地，mysqldump将创建一个满是SQL语句的文件，然后你可以把文件转移到其他机器上并且把它作为mysql客户的输入。

试一试mysqldump --help看可得到什么选项。如果你正在移动数据到一个更新的MySQL版本，你应该用得到的更新的版本使用mysqldump --opt得到一个快速、紧凑的倒出(dump)。

最容易(尽管不是最快)的在2台机器之间移动一个数据库的方法是在数据库所在的机器上运行下列命令：

shell> mysqladmin -h 'other hostname' create db_name
shell> mysqldump --opt db_name \
        | mysql -h 'other hostname' db_name

如果你想要在一个慢的网络上从一台远程机器上拷贝一个数据库，你可以使用：

shell> mysqladmin create db_name
shell> mysqldump -h 'other hostname' --opt --compress db_name \
    | mysql db_name

你也可以在一个文件中存储结果, 然后把文件转移到目标机器并且在那里装载文件到数据库。例如，你能象这样在源机器上倾倒一个数据库到一个文件：

shell> mysqldump --quick db_name | gzip > db_name.contents.gz

（本例创建的文件被压缩) 转移包含数据库内容的文件到目标机器，并且在那里运行这些命令：

shell> mysqladmin create db_name
shell> gunzip < db_name.contents.gz | mysql db_name

你也可以使用mysqldump和mysqlimport完成数据库转移。对大数据库表，这比简单地使用mysqldump更快。在下列命令中，DUMPDIR代表你用来存储来自mysqldump的输出的目录的完整的路径。

首先，为输出文件和倾倒数据库创建目录：

shell> mkdir DUMPDIR
shell> mysqldump --tab=DUMPDIR db_name

然后转移在DUMPDIR目录下的文件到目标机器的一些相应目录并且在那里装载文件到MySQL：

shell> mysqladmin create db_name           # create database
shell> cat DUMPDIR/*.sql | mysql db_name   # create tables in database
shell> mysqlimport db_name DUMPDIR/*.txt   # load data into tables

另外，别忘记拷贝mysql数据库，因为那是授权表(user、db、host)被存储的地方。你可能必须作为MySQL root用户在新机器上运行命令，直到你让mysql数据库到位。

当你在新机器上导入mysql数据库后，执行mysqladmin flush-privileges以便服务器再次装入授权表信息。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-5 MySQL 与标准如何兼容？

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

5 MySQL与标准的兼容性？

5.1 MySQL对ANSI SQL92扩充

MySQL包含了一些可能在其他SQL数据库找不到的扩充。要注意如果你使用他们，你的代码将不与其他SQL服务器兼容。在一些情况下，你可以编写包括MySQL扩展的代码，但是仍然是可移植的，通过使用/*! ... */形式的注释。在这种情况下，MySQL将进行词法分析并且执行在注释内的代码，好像它是任何其它MySQL语句，但是其他SQL服务器将忽略扩展。例如：

SELECT /*! STRAIGHT_JOIN */ col_name FROM table1,table2 WHERE ...

如果你在'!'后增加一个版本数字，该语法将仅在MySQL版本是等于或比使用的版本数字新时才执行：

CREATE /*!32302 TEMPORARY */ TABLE (a int);

上面的意思是如果你有3.23.02或更新，那么MySQL将使用TEMPORARY关键词。

MySQL扩展被列在下面：

  • 字段类型MEDIUMINT、SET、ENUM和不同的BLOB和TEXT类型。
  • 字段属性AUTO_INCREMENT、BINARY、UNSIGNED和ZEROFILL。
  • 缺省地，所有的字符串比较是忽略大小写的，由当前的字符集决定了(缺省为ISO-8859-1 Latin1)排序顺序。如果你不喜欢这样，你应该用BINARY属性或使用BINARY强制符声明列，它导致根据MySQL服务器主机的ASCII顺序进行排序。
  • MySQL将每个数据库映射一个MySQL数据目录下面的目录，将数据库表映射到数据库目录下的数据库文件名。这有2个含意：
    • 在区分大小写文件名的操作系统(象大多数 Unix 系统一样)上的MySQL中数据库名字和表名是区分大小写的。如果你有困难记得表名，接受一个一致的约定，例如总是用小写名字创建数据库和表。
    • 数据库、表、索引、列或别名可以以数字开始(但是不能仅由数字组成)。
    • 你可以使用标准的系统命令备份、重命名、移动、删除和拷贝表。例如，重命名一个表，重命名“.MYD”、“.MYI”和“.frm”文件为相应的表。
  • 在SQL语句中，你可以用db_name.tbl_name语法访问不同数据库中的表。一些SQL服务器提供同样的功能但是称它们为这User space（用户空间）。MySQL不支持类似在create table ralph.my_table...IN my_tablespace中的表空间。
  • LIKE在数字列上被允许。
  • 在一SELECT语句里面使用INTO OUTFILE和STRAIGHT_JOIN。见7.12 SELECT句法.
  • 在一个SELECT语句中SQL_SMALL_RESULT选项。
  • EXPLAIN SELECT得到如何联结表的描述。
  • 在一个CREATE TABLE语句里面使用索引、在字段前缀上的索引和使用INDEX或KEY。见7.7 CREATE TABLE 句法。
  • CREATE TABLE使用TEMPORARY或IF NOT EXISTS。
  • 使用COUNT(DISTINCT list)，这里“list”超过一个元素。
  • 在一个ALTER TABLE语句里面使用CHANGE col_name、DROP col_name或DROP INDEX。见7.8 ALTER TABLE句法。
  • 在一个ALTER TABLE里面语句使用IGNORE。
  • 在一个ALTER TABLE语句中使用多重ADD、ALTER、DROP或CHANGE子句。
  • 使用带关键词IF EXISTS的DROP TABLE。
  • 你能用单个DROP TABLE语句抛弃多个表。
  • DELETE语句的LIMIT子句。
  • INSERT和REPLACE语句的DELAYED子句。
  • INSERT, REPLACE, DELETE和UPDATE语句的LOW_PRIORITY子句。
  • 使用LOAD DATA INFILE。在多数情况下，这句法与Oracle的LOAD DATA INFILE兼容。见7.16 LOAD DATA INFILE 句法。
  • OPTIMIZE TABLE语句。见7.9 OPTIMIZE TABLE句法。
  • SHOW语句。见7.21 SHOW句法(得到表、列等的信息)。
  • 字符串可以被“"”或“'”包围，而不只是“'”。
  • 使用“\”转义字符。
  • SET OPTION语句。见7.25 SET OPTION句法。
  • 你不需要命名所有在GROUP BY部分的被选择的列。这为一些很特定的情况给出更好的性能，而不是一般的查询。见7.4.13 用于GROUP BY子句的函数。
  • 为了方便来自于SQL环境其他为用户，MySQL对许多函数支持别名。例如，所有的字符串功能都支持ANSI SQL句法和 ODBC句法。
  • MySQL理解||和&&意味着逻辑的OR和AND，就像在C程序语言中。在MySQL中，||和OR是同义词，&&和AND是同义词。正因为这个好的句法，MySQL对字符串并置的不支持ANSI SQL ||操作符；相反使用CONCAT()，因为CONCAT()接受任何数量的参数，很容易把||操作符使用变换到MySQL。
  • CREATE DATABASE或DROP DATABASE。见7.5 CREATE DATABASE句法。
  • %操作符是MOD()一个同义词，即，N % M等价于MOD(N,M)。%支持C程序员并与PostgreSQL兼容。
  • =, <>, <=,<, >=,>, <<, >>, <=>, AND, OR或LIKE操作符可以放在SELECT语句的FROM左边用于比较列。例如：
    mysql> SELECT col1=1 AND col2=2 FROM tbl_name;
  • LAST_INSERT_ID()函数。见20.4.29 mysql_insert_id()。
  • 扩展的正则表达式操作符REGEXP和NOT REGEXP。
  • CONCAT()或CHAR()有一个参数或超过2个参数。（在MySQL中，这些函数可取任何数量的参数。）
  • BIT_COUNT(), CASE, ELT(), FROM_DAYS(),
    FORMAT(), IF(), PASSWORD(), ENCRYPT(),
    md5(), ENCODE(), DECODE(), PERIOD_ADD(),
    PERIOD_DIFF(), TO_DAYS(),或WEEKDAY()函数。
  • 使用TRIM()整修子串。ANSI SQL 只支持单个字符的删除。
  • GROUP BY函数STD(), BIT_OR()和BIT_AND()。
  • 使用REPLACE而不是DELETE+INSERT。见7.15 REPLACE句法。
  • FLUSH flush_option语句。
  • 在一个语句用:=设置变量的可能性：
    SELECT @a:=SUM(total),@b=COUNT(*),@a/@b AS avg FROM test_table;
SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;

5.2 以ANSI模式运行MySQL

如果你用--ansi选项启动mysqld，MySQL的下列行为改变。

  • ||是字符串并置而不是OR。
  • 可在一个函数名字之间与“(”有任何数量的空格。这也使所有的功能名字成为保留词。
  • "将是一个标识符引号字符(象MySQL `引号字符一样)而不是一个字符串引号字符。
  • REAL将是FLOAT一个同义词，不是DOUBLE一个同义词。

5.3 MySQL相比ANSI SQL92的差别

我们尝试使得MySQL遵照ANSI SQL标准和ODBC SQL标准，但是在一些情况下，MySQL做一些不同的事情：

  • --只是一个注释，如果后面跟一个白空字符。见5.4.7 `--'作为一个注释的开始。
  • 对于VARCHAR列，当值被存储时，拖后的空格被删除。见E MySQL已知的错误和设计缺限。
  • 在一些情况下，CHAR列偷偷地被改变为VARCHAR列。见7.7.1 平静的列指定变化。
  • 当你删除一个表时，对表的权限不自动地废除。你必须明确地发出一个REVOKE来废除对一个表的权限。见7.26 GRANT和REVOKE句法。

5.4 MySQL缺乏的功能

下列功能在当前的MySQL版本是没有的。对于一张优先级表指出何时新扩展可以加入MySQL, 你应该咨询在线MySQL TODO 表。这是本手册最新的TODO表版本。见F 我们想要在未来加入到MySQL的事情列表(TODO)。

5.4.1 子选择

在MySQL中下列语句还不能工作：

SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
SELECT * FROM table1 WHERE id NOT IN (SELECT id FROM table2);

然而，在很多情况下，你可以重写查询，而不用子选择：

SELECT table1.* FROM table1,table2 WHERE table1.id=table2.id;
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id where table2.id IS NULL

对于更复杂的子查询，通常你可以创建临时的表保存子查询。然而在一些情况下，这种选择将行不通。最经常遇到的情形是DELETE语句，对于它标准SQL不支持联结(join)(除了在子选择)。对于这种情况，有2个可用选择，直到子选择被MySQL支持。

第一个选择是使用一种过程化的程序语言(例如Perl或PHP)来提交一个SELECT查询获得要被删除记录主键，并然后使用这些值构造DELETE语句(DELETE FROM ... WHERE ... IN (key1, key2, ...))。

第二个选择是使用交互式SQL自动构造一套DELETE语句，使用MySQL扩展CONCAT()（代替标准||操作符)。例如：

SELECT CONCAT('DELETE FROM tab1 WHERE pkid = ', tab1.pkid, ';')
  FROM tab1, tab2
 WHERE tab1.col1 = tab2.col2;

你可以把这个查询放在一个脚本文件并且从它重定向输入到mysql命令行解释器，将其输出作为管道返回给解释器的第2个实例：

prompt> mysql --skip-column-names mydb < myscript.sql | mysql mydb

MySQL仅支持INSERT ... SELECT ...和REPLACE ... SELECT ...，独立的子选择将可能在3.24.0得到，然而，在其他环境下，你现在可以使用函数IN()。

5.4.2 SELECT INTO TABLE

MySQL还不支持Oracle SQL的扩展：SELECT ... INTO TABLE ....，相反MySQL支持ANSI SQL句法INSERT INTO ... SELECT ...，基本上他们是一样的。

另外，你可使用SELECT INTO OUTFILE...或CREATE TABLE ... SELECT解决你的问题。

5.4.3 事务处理

不支持事务处理。MySQL将在短时间内支持原子(atomic)操作，它象没有回卷的事务。用原子操作，你能执行一组INSERT/SELECT/whatever 命令并且保证没有其他线程介入。在本文中，你通常不会需要回卷。目前，你可通过使用LOCK TABLES和UNLOCK TABLES命令阻止其他线程的干扰。见7.24 LOCK TABLES/UNLOCK TABLES句法。

5.4.4 存储过程和触发器

一个存储过程是能在服务器中编译并存储的一套SQL命令。一旦这样做了，顾客不需要一直重新发出全部查询，而可以参考存储过程。因为查询仅需一次词法分析并且较少的信息需要在服务器和客户之间传送，因此这提供了更好的性能。你与可以通过拥有在服务器中的函数库提升概念上的层次。

一个触发器是当一个特别的事件发生时，被调用的一个存储过程。例如，你可以安装一个存储过程，它在每次从一个交易表删除一条记录时触发，并且当它所有交易被删除时，自动地从一个客户表中删除相应的客户。

计划修改的语言将能处理存储过程，但是没有触发器。触发器通常使每件事情变慢，即使对他们不需要的查询。

为了俩解什么时候MySQL可能得到存储过程，见F 我们想在未来加入到MySQL的事情列表(TODO)。

5.4.5 外键

注意，在SQL中外键不用于联结表，而主要用于检查参考完整性(RI)。如果你想要得到用一个SELECT语句从多个表得到结果， 你通过联结表做！

SELECT * from table1,table2 where table1.id = table2.id;

见7.13 JOIN句法。见8.3.5 使用外键。

在MySQL里存在FOREIGN KEY句法仅仅为了与其他SQL供应商的CREATE TABLE命令相兼容；它不做任何事情。没有ON DELETE ...的FOREIGN KEY句法主要用于文档目的。一些ODBC应用程序可以使用它自动生成WHERE子句，但是这通常很容易的覆盖。 FOREIGN KEY有时用作一个约束检查，但是如果行以正确的顺序被插入表，该检查实际上是不必要的。MySQL仅仅支持这些子句(不考虑是否他们工作!)，因为一些应用程序要求他们存在。

在MySQL中，你可以解决ON DELETE ...没被实现的问题，，在你从一个用外键的表删除记录时，通过为一个应用程序增加适当的DELETE语句即可。实际上，这很快(在一些情况下更快)并且比使用外键更比便于移植。

在不久的将来我们将扩充FOREIGN KEY实现，以便至少信息将在表说明文件中保存并且可以由mysqldump和ODBC检索。

5.4.5.1 不使用外键的理由

有很多与FOREIGN KEY有关的问题我们不知道从哪儿开始：

  • 外键使生活更复杂，因为外键的定义必须存储在一个数据库中并且实现他们将破坏使用能被移动、拷贝和删除文件的全部“好方法”。
  • 速度影响对INSERT和UPDATE语句是可怕的，并且在这种情况下几乎所有的FOREIGN KEY检查都是无用的，因为不管怎样你通常以正确的顺序在正确的表中插入记录。
  • 当更新一张表时，也有在许多表上保存锁的需求，因为副作用可以串联通过全部数据库。首先从一张表中删除记录并且随后从其他表中删除他们，这更快。
  • 你再也不可以通过做一个全面的表删除并随后恢复所有的记录的方法来恢复一张表(从新来源或从一个备份)。
  • 如果你有外键，你不能倾倒和恢复表，除非你以一个非常特定的做这些。
  • 很容易做一个“允许的”的循环定义使得不可能用一个单个create语句重建每一个表，就算定义可行又可用。

FOREIGN KEY唯一好的方面是它给ODBC和一些其他客户程序检查一张表如何被连接的能力，并且使用它们显示出连接图表并帮助构造应用。

MySQL不久将存储FOREIGN KEY定义以便一个客户能询问并收到原来的连接如何进行的一个答案。当前的“.frm 文件格式没有它应有的地位。

5.4.6 视图

MySQL不支持视图，但是它在TODO上。

5.4.7 '--'作为一个注释的开始

有些其他SQL数据库使用'--'开始注释。MySQL有“#”作为开始数注释的字符，即使mysql命令行工具删除以'--'开始的所有行。你也可以在MySQL中使用C注释风格/* this is a comment */。见7.29 注释句法。

MySQL3.23.3和以上版本支持'--'注释风格，只要注释跟在一个空格之后。这是因为这种退化的注释风格已经引起用像下列代码那样的自动生成的SQL查询的许多问题，这里我们自动地为!payment!插入支付值：

UPDATE tbl_name SET credit=credit-!payment!

你想出当payment的值是负的时将发生什么吗？

因为1--1在SQL中是合法的，我们认为'--'开始注释是可怕的。

然而在MySQL 3.23中，你可使用：1-- This is a comment

如果你正在运行一个比3.23早的MySQL的版本，下列的讨论才涉及你：

如果你在一个文本文件中有一个SQL程序，它包含'--'注释，你应该使用：

shell> replace " --" " #" < text-file-with-funny-comments.sql \
         | mysql database

而不是通常：
shell> mysql database < text-file-with-funny-comments.sql

你也可以“现场”编辑命令文件将'--'注释改为'#'注释：

shell> replace " --" " #" -- text-file-with-funny-comments.sql

用这个命令改回他们：

shell> replace " #" " --" -- text-file-with-funny-comments.sql

5.5 MySQL 遵循什么标准？

Entry level SQL92。ODBC level 0-2。

5.6 怎样处理没有COMMIT/ROLLBACK

MySQL不支持COMMIT-ROLLBACK。问题是有效地处理COMMIT-ROLLBACK将需要完全不同于MySQL今天使用的表布局。MySQL也将需要额外的线程在表上做自动清除工作，而且磁盘用量将更高。这将使MySQL比现今慢上大约2-4倍。MySQL比几乎所有其他SQL数据库都快(一般至少快2-3倍)。原因之一就是缺少COMMIT-ROLLBACK。

目前，我们是更多地实现SQL服务器语言(象存储过程)，有了它，你将确实很少需要COMMIT-ROLLBACK，这也将得到更好的性能。

通常需要事务的循环可以借助LOCK TABLES进行编码，并且当你能即时地更新记录时，你不需要光标(cursor)。

我们在TODO上有事务和光标，然而并非相当优先。如果我们实现这些，将作为CREATE TABLE的选项，那意味着COMMIT-ROLLBACK将仅工作在那些表上，以便速度损失仅仅强加在那些表上。

我们在TcX有一个更大的需求，一个比100%通用数据库的真正快速的数据库。无论何时我们发现一个方法来实现这些特征而没有任何速度损失，我们将可能做它。暂时，有许多更重要的事情要做。检查TODO，看我们此时如何将事情优先排列。（有的较高级别支持的客户可以改变它，因此事情是可以重新优先化的。）

当前的问题实际上是ROLLBACK，没有ROLLBACK，你能用LOCK TABLES做任何COMMIT动作。为了支持ROLLBACK，MySQL将必须被改变以存储所有的旧记录，如果发出ROLLBACK，它们被更新的并且将任何东西恢复到起点。对于简单的情形，这不是难做的 (当前isamlog可以用于此目的)，但是为ALTER/DROP/CREATE TABLE实现ROLLBACK将是更困难的。

避免使用ROLLBACK，你可以使用下列策略：

  1. 使用LOCK TABLES ...锁住所有你想要存取的数据库表。
  2. 测试条件。
  3. 如果一切无误，更新。
  4. 使用UNLOCK TABLES释放你的锁。

这通常比使用可能带ROLLBACK的交易是一个更快的方法，尽管不总是这样。这个解决方案不能处理的唯一状况是当某人在更新当中杀死线程时。在这种情况下，所有的锁将被释放，但是一些更改不能被执行。

你也可使函数以单个操作更新记录。你能通过使用下列技术得到一个很有效率的应用程序：

  • 相对他们的当前的值修改字段
  • 仅仅更新那些实际上更改的字段

例如，当我们正在更新一些客户信息时，我们仅仅更新那些改变了的客户数据并只测试没有任何数据的改变，或数据取决于改变的数据，与原来的行相比变化了。对于改变了的数据的测试用WHERE子句在UPDATE语句中完成。如果记录没被更新，我们给客户一条消息：“你改变了的一些数据已被其他用户改变了”，然后我们在一个窗口中显示新行对照旧行，因此用户能决定他该使用哪个版本的客户记录。

这给了我们类似于“列锁定”的东西，但是实际上甚至更好，因为我们仅仅更新某些列，使用相对于他们的当前值的值。这意味着典型的UPDATE语句看上去象这些一样东西：

UPDATE tablename SET pay_back=pay_back+'relative change';

UPDATE customer
  SET
    customer_date='current_date',
    address='new address',
    phone='new phone',
    money_he_owes_us=money_he_owes_us+'new_money'
  WHERE
    customer_id=id AND address='old address' AND phone='old phone';

正如你能看到的，这是很有效的并且就算其他客户已经改变了pay_back或money_he_owes_us列的也能工作。

在许多情况下，为管理一些表格的唯一标识符目的，用户已经想要ROLLBACK或LOCK TABLES。这可用一个AUTO_INCREMENT列和一个SQL函数LAST_INSERT_ID()或C API函数mysql_insert_id()更高效地处理。见20.4.29 mysql_insert_id()。

在TcX，我们从来没有任何对行级锁定的需求，因为我们总是能通过编码解决它。一些情况下需要确实行锁定，但是他们是很少见的。如果你想要行级锁定，你可以在表中使用标志列并且这样做：

UPDATE tbl_name SET row_flag=1 WHERE id=ID;

如果行被找到发现并且row_flag在原来的行已经不是1，对受影响的行数MySQL返回1。

你可以想到它，因为MySQL把上面的查询变为：

UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-6 MySQL 存取权限系统

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

6 MySQL 存取权限系统

MySQL有一个先进但非标准的安全/权限系统。本节描述它的工作原理。

6.1 权限系统做什么

MySQL权限系统的主要功能是证实连接到一台给定主机的一个用户，并且赋予该用户在一个数据库上select、 insert、update和delete的权限。

附加的功能包括有一个匿名的用户和对于MySQL特定的功能例如LOAD DATA INFILE进行授权及管理操作的能力。

6.2 MySQL 用户名和口令

由MySQL使用用户名和口令的方法与Unix或Windows使用的方式有很多不同之处：

  • MySQL使用于认证目的的用户名，与Unix用户名(登录名字)或Windows用户名无关。缺省地，大多数MySQL客户尝试使用当前Unix用户名作为MySQL用户名登录，但是这仅仅为了方便。客户程序允许用-u或--user选项指定一个不同的名字，这意味着无论如何你不能使得一个数据库更安全，除非所有的MySQL用户名都有口令。任何人可以试图用任何名字连接服务器，而且如果他们指定了没有口令的任何名字，他们将成功。
  • MySQL用户名最长可以是16各字符；典型地，Unix用户名限制为8个字符。
  • MySQL口令与Unix口令没关系。在你使用登录到一台Unix机器口令和你使用在那台机器上存取一个数据库的口令之间没有必要有关联。
  • MySQL加密口令使用了一个Unix登录期间所用的不同算法，见7.4.12 杂项函数一节中描述PASSWORD()和ENCRYPT()函数部分。

6.3 与MySQL服务器连接

当你想要存取一个MySQL服务器时，MySQL客户程序一般要求你指定连接参数：你想要联接的主机、你的用户名和你的口令。例如，mysql客户可以象这样启动(可选的参数被包括在“[”和“]”之间)：

shell> mysql [-h host_name][-u user_name][-pyour_pass ]

-h, -u和-p选项的另一种形式是--host=host_name、--user=user_name和--password=your_pass。注意在-p或--password=与跟随它后面的口令之间没有空格。

注意：在命令行上指定一个口令是不安全的！随后在你系统上的任何用户可以通过打类似这样的命令发现你的口令：ps auxww。见4.15.4 选项文件。

对于命令行没有的联接参数，mysql使用缺省值：

  • 缺省主机名是localhost。
  • 缺省用户名是你的Unix登录名。
  • 如果没有-p，则没有提供口令。

这样, 对一个Unix用户joe，下列命令是等价的：

shell>mysql -h localhost -u joe
shell>mysql -h localhost
shell>mysql -u joe
shell>mysql

其它MySQL客户程序有同样表现。

在Unix系统上，当你进行一个连接时，你可以指定要使用的不同的缺省值，这样你不必每次在你调用一个客户程序是在命令行上输入他们。这可以有很多方法做到：

  • 你能在你的主目录下“.my.cnf”的配置文件的[client]小节里指定连接参数。文件的相关小节看上去可能像这样：
    [client]
host=host_name
user=user_name
password=your_pass

    见4.15.4 选项文件。

  • 你可以用环境变量指定连接参数。主机可用MYSQL_HOST指定，MySQL用户名字可用USER指定(仅对 Windows)，口令可用MYSQL_PWD指定（但是这不安全，见下一节) 。

如果连接参数以多种方法被指定，在命令行上被指定的值优先于在配置文件和环境变量中指定的值，而在配置文件指定的值优先于在环境变量指定的值。

6.4 使你的口令安全

以一种暴露的可被其他用户发现的方式指定你的口令是不妥当的。当你运行客户程序时，你可以使用下列方法指定你的口令，还有每个方法的风险评估：

  • 使用一个在命令行上-pyour_pass或--password=your_pass的选项。这很方便但是不安全，因为你的口令对系统状态程序(例如ps)变得可见，它可以被其他的用户调用来显示命令行。(一般MySQL客户在他们的初始化顺序期间用零覆盖命令行参数，但是仍然有一个短暂间隔时间内参数值可见的。）
  • 使用一个-p或--password选项(没有指定your_pass值)。在这种情况下，客户程序请求来自终端的口令：
    shell>mysql - u  user_name - p
Enter password: ********

    客户回应“*”字符到作为输入你的口令的终端使得旁观者不能看见它。因为它对其他用户不可见，与在命令行上指定它相比，这样进入你的口令更安全。然而，这个输入一个口令的方法仅仅为你交互式运行程序是合适的。如果你想要从非交互式运行的一个脚本调用一个客户，就没有从终端输入入口令的机会。

  • 在一个配置文件中存储你的口令。例如，你可你的主目录的“.my.cnf”文件中的[client]节列出你的口令：
    [client]
password=your_pass

    如果你在“.my.cnf”里面存储口令，文件应该不是组或世界可读或可写的。保证文件的存取模式是400或600。见4.15.4 选项文件。

  • 你可在MYSQL_PWD环境变量中存储口令，但是这个方法必须想到是极不安全的且应该不使用。ps的某些版本包括显示运行进程的环境的选项；如果你设定MYSQL_PWD，你的口令将对所有人是显而易见的，甚至在没有这样一个版本的ps系统上，假设没有其他方法观察到进程环境是不明智的。

总之，最安全的方法是让客户程序提示口令或在一个适当保护的“.my.cnf”文件中指定口令。

6.5 MySQL提供的权限

权限信息用user、db、host、tables_priv和columns_priv表被存储在mysql数据库中(即在名为mysql的数据库中)。在MySQL启动时和在6.9 权限修改何时生效所说的情况时，服务器读入这些数据库表内容。

本手册所用的涉及由MySQL提供的权限名称显示在下表，还有在授权表中每个权限的表列名称和每个权限有关的上下文：

权限 | 列 | 上下文
select | Select_priv | 表
insert | Insert_priv | 表
update | Update_priv | 表
delete | Delete_priv | 表
index | Index_priv | 表
alter | Alter_priv | 表
create | Create_priv | 数据库、表或索引
drop | Drop_priv | 数据库或表
grant | Grant_priv | 数据库或表
references | References_priv | 数据库或表
reload | Reload_priv | 服务器管理
shutdown | Shutdown_priv | 服务器管理
process | Process_priv | 服务器管理
file | File_priv | 在服务器上的文件存取

select、insert、update和delete权限允许你在一个数据库现有的表上实施操作。

SELECT语句只有在他们真正从一个表中检索行是才需要select权限，你可以执行某个SELECT语句，甚至没有任何到服务器上的数据库里的存取任何东西的许可。例如，你可使用mysql客户作为一个简单的计算器：

mysql> SELECT 1+1;
mysql> SELECT PI()*2;

index权限允许你创建或抛弃(删除)索引。

alter权限允许你使用ALTER TABLE。

create和drop权限允许你创建新的数据库和表，或抛弃(删除)现存的数据库和表。

注意：如果你将mysql数据库的drop权限授予一个用户，该用户能抛弃存储了MySQL存取权限的数据库！

grant权限允许你把你自己拥有的那些权限授给其他的用户。

file权限给予你用LOAD DATA INFILE和SELECT ... INTO OUTFILE语句读和写服务器上的文件，任何被授予这个权限的用户都能读或写MySQL服务器能读或写的任何文件。

其余的权限用于管理性操作，它使用mysqladmin程序实施。下表显示mysqladmin支配每个管理性权限允许你执行的命令：

优惠 | 权限拥有者允许执行的命令
reload | reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tables
shutdown | shutdown
precess | processlist, kill

reload命令告诉服务器再读入授权表，refresh命令清洗所有表并打开和关闭记录文件，flush-privileges是reload的一个同义词，其它flush-*命令执行类似refresh的功能，但是范围更有限，并且在某些情况下可能更好用。例如，如果你只是想清洗记录文件，flush-logs比refresh是更好的选择。

shutdown命令关掉服务器。

processlist命令显示在服务器内执行的线程的信息。kill命令杀死服务器线程。你总是能显示或杀死你自己的线程，但是你需要process权限来显示或杀死其他用户启动的线程。

总的说来，只授予权限给需要他们的那些用户是一个好主意，但是你应该在授予某个权限时试验特定的警告：

  • grant权限允许用户放弃他们的权限给其他用户。2个有不同的权限并有grant权限的用户可以合并权限。
  • alter权限可以用于通过重新命名表来推翻权限系统。
  • file权限可以被滥用在服务器上读取任何世界可读(world-readable，即任何人可读)的文件到一张数据库表，然后其内容能用SELECT被存取。
  • shutdown权限通过终止服务器可以被滥用完全拒绝为其他用户服务, 。
  • precess权限能被用来察看当前执行的查询的普通文本，包括设定或改变口令查询。
  • 在mysql数据库上的权限能被用来改变口令和其他存取权限信息。（口令被加密存储，所以一个恶意的用户不能简单地读取他们。然而，有足够的权限，同一个用户能用不同的一个代替一个口令。）

有一些事情你不能用MySQL权限系统做到：

  • 你不能明显地指定一个给定用户应该被拒绝存取。即，你不能明显地匹配一个用户并且然后拒绝连接。
  • 你不能指定一个用户有权创建立或抛弃一个数据库中的表，也不能创建或抛弃数据库本身。

6.6 权限系统工作原理

MySQL权限系统保证所有的用户可以严格地做他们假定被允许做的事情。当你连接一个MySQL服务器时， 你的身份由你从那连接的主机和你指定的用户名来决定，系统根据你的身份和你想做什么来授予权限。

MySQL在认定身份中考虑你的主机名和用户名字，是因为有很小的原因假定一个给定的用户在因特网上属于同一个人。例如，用户从whitehouse.gov连接的bill不必和从mosoft.com连接bill是同一个人。 MySQL通过允许你区分在不同的主机上碰巧有同样名字用户来处理它：你可以对从whitehouse.gov连接授与bill一个权限集，而为从microsoft.com的连接授予一个不同的权限集。

MySQL存取控制包含2个阶段：

  • 阶段1：服务器检查你是否允许连接。
  • 阶段2：假定你能连接，服务器检查你发出的每个请求。看你是否有足够的权限实施它。例如，如果你从数据库中一个表精选(select)行或从数据库抛弃一个表，服务器确定你对表有select权限或对数据库有drop权限。

服务器在存取控制的两个阶段使用在mysql的数据库中的user、db和host表，在这些授权表中字段如下：

表名称 | user | db | host
范围字段 | Host | Host | Host
 | User | Db | Db
 | Password | User |
权限字段 | Select_priv | Select_priv | Select_priv
 | Insert_priv | Insert_priv | Insert_priv
 | Update_priv | Update_priv | Update_priv
 | Delete_priv | Delete_priv | Delete_priv
 | Index_priv | Index_priv | Index_priv
 | Alter_priv | Alter_priv | Alter_priv
 | Create_priv | Create_priv | Create_priv
 | Drop_priv | Drop_priv | Drop_priv
 | Grant_priv | Grant_priv | Grant_priv
 | Reload_priv |  |
 | Shutdown_priv |  |
 | Process_priv |  |
 | File_priv |  |

对存取控制的第二阶段(请求证实)，如果请求涉及表，服务器可以另外参考tables_priv和columns_priv表。这些表的字段如下：

表名称 | tables_priv | columns_priv
范围字段 | Host | Host
 | Db | Db
 | User | User
 | Table_name | Table_name
 |  | Column_name
权限字段 | Table_priv | Column_priv
 | Column_priv |
其他字段 | Timestamp | Timestamp
 | Grantor |

每个授权表包含范围字段和权限字段。

范围字段决定表中每个条目的范围，即，条目适用的上下文。例如, 一个user表条目的Host和User值为'thomas.loc.gov'和'bob'将被用于证实来自主机thomas.loc.gov的bob对服务器的连接。同样，一个db表条目的Host、User和Db字段的值是'thomas.loc.gov'、'bob'和'reports'将用在bob从主机联接thomas.loc.gov存取reports数据库的时候。 tables_priv和columns_priv表包含范围字段，指出每个条目适用的表或表／列的组合。

对于检查存取的用途，比较Host值是忽略大小写的。User、Password、Db和Table_name值是区分大小写的。Column_name值在MySQL3.22.12或以后版本是忽略大小写的。

权限字段指出由一个表条目授予的权限，即，可实施什么操作。服务器组合各种的授权表的信息形成一个用户权限的完整描述。为此使用的规则在6.8 存取控制, 阶段2：请求证实描述。

范围字段是字符串，如下所述；每个字段的缺省值是空字符串：

字段名 | 类型
Host | CHAR(60)
User | CHAR(16)
Password | CHAR(16)
Db | CHAR(64) | (tables_priv和columns_priv表为CHAR(60)）

在user、db和host表中，所有权限字段被声明为ENUM('N','Y')--每一个都可有值'N'或'Y'，并且缺省值是'N'.

在tables_priv和columns_priv表中，权限字段被声明为SET字段：

表名 | 字段名 | 可能的集合成员
tables_priv | Table_priv | 'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter'
tables_priv | Column_priv | 'Select', 'Insert', 'Update', 'References'
columns_priv | Column_priv | 'Select', 'Insert', 'Update', 'References'

简单地说，服务器使用这样的授权表：

  • user表范围字段决定是否允许或拒绝到来的连接。对于允许的连接，权限字段指出用户的全局(超级用户)权限。
  • db和host表一起使用：
    • db表范围字段决定用户能从哪个主机存取哪个数据库。权限字段决定允许哪个操作。
    • 当你想要一个给定的db条目应用于若干主机时，host表作为db表的扩展被使用。例如，如果你想要一个用户能在你的网络从若干主机使用一个数据库，在用户的db表的Host条目设为空值，然后将那些主机的每一个移入host表。这个机制详细描述在6.8 存取控制, 阶段2：请求证实。
  • tables_priv和columns_priv表类似于db表，但是更精致：他们在表和列级应用而非在数据库级。

注意管理权限(reload, shutdown, 等等)仅在user表中被指定。这是因为管理性操作是服务器本身的操作并且不是特定数据库，因此没有理由在其他授权表中列出这样的权限。事实上，只需要请教user表来决定你是否执行一个管理操作。

file权限也仅在user表中指定。它不是管理性权限，但你读或谢在服务器主机上的文件的的能力独立于你正在存取的数据库。

当mysqld服务器启动时，读取一次授权表内容。对授权表的更改生效在6.9 权限更改何时生效描述。

当你修改授权表的内容时，确保你按你想要的方式更改权限设置是一个好主意。为帮助诊断问题，见6.13 “存取拒绝引起”错误的原因。对于安全问题上的忠告，见6.14 怎么对使MySQL安全对抗解密高手。

一个有用的诊断工具是mysqlaccess脚本，由Carlier Yves 提供给MySQL分发。使用--help选项调用mysqlaccess查明它怎样工作。注意：mysqlaccess仅用user、db和host表仅检查存取。它不检查表或列级权限。

6.7 存取控制, 阶段1：连接证实

当你试图联接一个MySQL服务器时，服务器基于你的身份和你是否能通过供应正确的口令验证身份来接受或拒绝连接。如果不是，服务器完全具结你的存取，否则，服务器接受连接，然后进入阶段2并且等待请求。

你的身份基于2个信息：

  • 你从那个主机连接
  • 你的MySQL用户名

身份检查使用3个user表(Host, User和Password)范围字段执行。服务器只有在一个user表条目匹配你的主机名和用户名并且你提供了正确的口令时才接受连接。

在user表范围字段可以如下被指定：

  • 一个Host值可以是主机名或一个IP数字，或'localhost'指出本地主机。
  • 你可以在Host字段里使用通配符字符“%”和“_”。
  • 一个Host值'%'匹配任何主机名，一个空白Host值等价于'%'。注意这些值匹配能创建一个连接到你的服务器的任何主机！
  • 通配符字符在User字段中不允许，但是你能指定空白的值，它匹配任何名字。如果user表匹配到来的连接的条目有一个空白的用户名，用户被认为是匿名用户(没有名字的用户)，而非客户实际指定的名字。这意味着一个空白的用户名被用于在连接期间的进一步的存取检查(即，在阶段2期间)。
  • Password字段可以是空白的。这不意味着匹配任何口令，它意味着用户必须不指定一个口令进行连接。

非空白Password值代表加密的口令。 MySQL不以任何人可以看的纯文本格式存储口令，相反，正在试图联接的一个用户提供的口令被加密(使用PASSWORD()函数)，并且与存储了user表中的已经加密的版本比较。如果他们匹配，口令是正确的。

下面的例子显示出各种user表中Host和User条目的值的组合如何应用于到来的连接：

Host 值 | User 值 | 被条目匹配的连接
'thomas.loc.gov' | 'fred' | fred, 从thomas.loc.gov 连接
'thomas.loc.gov' | '' | 任何用户, 从thomas.loc.gov连接
'%' | 'fred' | fred, 从任何主机连接
'%' | '' | 任何用户, 从任何主机连接
'%.loc.gov' | 'fred' | fred, 从在loc.gov域的任何主机连接
'x.y.%' | 'fred' | fred, 从x.y.net、x.y.com,x.y.edu等联接。（这或许无用）
'144.155.166.177' | 'fred' | fred, 从有144.155.166.177 IP 地址的主机连接
'144.155.166.%' | 'fred' | fred, 从144.155.166 C类子网的任何主机连接

既然你能在Host字段使用IP通配符值(例如，'144.155.166.%'匹配在一个子网上的每台主机)，有可能某人可能企图探究这种能力，通过命名一台主机为144.155.166.somewhere.com。为了阻止这样的企图，MySQL不允许匹配以数字和一个点起始的主机名，这样，如果你用一个命名为类似1.2.foo.com的主机，它的名字决不会匹配授权表中Host列。只有一个IP数字能匹配IP通配符值。

一个到来的连接可以被在user表中的超过一个条目匹配。例如，一个由fred从thomas.loc.gov的连接匹配多个条目如上所述。如果超过一个匹配，服务器怎么选择使用哪个条目呢？服务器在启动时读入user表后通过排序来解决这个问题，然后当一个用户试图连接时，以排序的顺序浏览条目，第一个匹配的条目被使用。

user表排序工作如下，假定user表看起来像这样：

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| %         | root     | ...
| %         | jeffrey  | ...
| localhost | root     | ...
| localhost |          | ...
+-----------+----------+-

当服务器在表中读取时，它以最特定的Host值为先的次序排列('%'在Host列里意味着“任何主机”并且是最不特定的)。有相同Host值的条目以最特定的User值为先的次序排列(一个空白User值意味着“任何用户”并且是最不特定的)。最终排序的user表看起来像这样：

+-----------+----------+-
| Host      | User     | ...
+-----------+----------+-
| localhost | root     | ...
| localhost |          | ...
| %         | jeffrey  | ...
| %         | root     | ...
+-----------+----------+-

当一个连接被尝试时，服务器浏览排序的条目并使用找到的第一个匹配。对于由jeffrey从localhost的一个连接，在Host列的'localhost'条目首先匹配。那些有空白用户名的条目匹配连接的主机名和用户名。（'%'/'jeffrey'条目也将匹配，但是它不是在表中的第一匹配。）

这是另外一个例子。假定user桌子看起来像这样：

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-

排序后的表看起来像这样：

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

一个由jeffrey从thomas.loc.gov的连接被第一个条目匹配，而一个由jeffrey从whitehouse.gov的连接被第二个匹配。

普遍的误解是认为，对一个给定的用户名，当服务器试图对连接寻找匹配时，明确命名那个用户的所有条目将首先被使用。这明显不是事实。先前的例子说明了这点，在那里一个由jeffrey从thomas.loc.gov的连接没被包含'jeffrey'作为User字段值的条目匹配，但是由没有用户名的题目匹配！

如果你有服务器连接的问题，打印出user表并且手工排序它看看第一个匹配在哪儿进行。

6.8 存取控制，阶段2：请求证实

一旦你建立了一个连接，服务器进入阶段2。对在此连接上进来的每个请求，服务器检查你是否有足够的权限来执行它，它基于你希望执行的操作类型。这正是在授权表中的权限字段发挥作用的地方。这些权限可以来子user、db、host、tables_priv或columns_priv表的任何一个。授权表用GRANT和REVOKE命令操作。见7.26 GRANT和REVOKE 句法。（你可以发觉参考6.6 权限系统怎样工作很有帮助，它列出了在每个权限表中呈现的字段。）

user表在一个全局基础上授予赋予你的权限，该权限不管当前的数据库是什么均适用。例如，如果user表授予你delete权限， 你可以删除在服务器主机上从任何数据库删除行！换句话说，user表权限是超级用户权限。只把user表的权限授予超级用户如服务器或数据库主管是明智的。对其他用户，你应该把在user表中的权限设成'N'并且仅在一个特定数据库的基础上授权， 使用db和host表。

db和host表授予数据库特定的权限。在范围字段的值可以如下被指定：

  • 通配符字符“%”和“_”可被用于两个表的Host和Db字段。
  • 在db表的'%'Host值意味着“任何主机”，在db表中一个空白Host值意味着“对进一步的信息咨询host表”。
  • 在host表的一个'%'或空白Host值意味着“任何主机”。
  • 在两个表中的一个'%'或空白Db值意味着“任何数据库”。
  • 在两个表中的一个空白User值匹配匿名用户。

db和host表在服务器启动时被读取和排序(同时它读user表)。db表在Host、Db和User范围字段上排序，并且host表在Host和Db范围字段上排序。对于user表，排序首先放置最特定的值然后最后最不特定的值，并且当服务器寻找匹配入条目时，它使用它找到的第一个匹配。

tables_priv和columns_priv表授予表和列特定的权限。在范围字段的值可以如下被指定：

  • 通配符“%”和“_”可用在使用在两个表的Host字段。
  • 在两个表中的一个'%'或空白Host意味着“任何主机”。
  • 在两个表中的Db、Table_name和Column_name字段不能包含通配符或空白。

tables_priv和columns_priv表在Host、Db和User字段上被排序。这类似于db表的排序，尽管因为只有Host字段可以包含通配符，但排序更简单。

请求证实进程在下面描述。（如果你熟悉存取检查的源代码，你会注意到这里的描述与在代码使用的算法略有不同。描述等价于代码实际做的东西；它只是不同于使解释更简单。）

对管理请求(shutdown、reload等等)，服务器仅检查user表条目，因为那是唯一指定管理权限的表。如果条目许可请求的操作，存取被授权了，否则拒绝。例如，如果你想要执行mysqladmin shutdown，但是你的user表条目没有为你授予shutdown权限，存取甚至不用检查db或host表就被拒绝。（因为他们不包含Shutdown_priv行列，没有这样做的必要。）

对数据库有关的请求(insert、update等等)，服务器首先通过查找user表条目来检查用户的全局(超级用户)权限。如果条目允许请求的操作，存取被授权。如果在user表中全局权限不够，服务器通过检查db和host表确定特定的用户数据库权限：

  1. 服务器在db表的Host、Db和User字段上查找一个匹配。 Host和User对应连接用户的主机名和MySQL用户名。Db字段对应用户想要存取的数据库。如果没有Host和User的条目，存取被拒绝。
  2. 如果db表中的条目有一个匹配而且它的Host字段不是空白的，该条目定义用户的数据库特定的权限。
  3. 如果匹配的db表的条目的Host字段是空白的，它表示host表列举主机应该被允许存取数据库的主机。在这种情况下，在host表中作进一步查找以发现Host和Db字段上的匹配。如果没有host表条目匹配，存取被拒绝。如果有匹配，用户数据库特定的权限以在db和host表的条目的权限，即在两个条目都是'Y'的权限的交集(而不是并集！)计算。（这样你可以授予在db表条目中的一般权限，然后用host表条目按一个主机一个主机为基础地有选择地限制它们。）

在确定了由db和host表条目授予的数据库特定的权限后，服务器把他们加到由user表授予的全局权限中。如果结果允许请求的操作，存取被授权。否则，服务器检查在tables_priv和columns_priv表中的用户的表和列权限并把它们加到用户权限中。基于此结果允许或拒绝存取。

用布尔术语表示，前面关于一个用户权限如何计算的描述可以这样总结：

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges

它可能不明显，为什么呢，如果全局user条目的权限最初发现对请求的操作不够，服务器以后把这些权限加到数据库、表和列的特定权限。原因是一个请求可能要求超过一种类型的权限。例如，如果你执行一个INSERT ... SELECT语句，你就都要insert和select权限。你的权限必须如此以便user表条目授予一个权限而db表条目授予另一个。在这种情况下，你有必要的权限执行请求，但是服务器不能自己把两个表区别开来；两个条目授予的权限必须组合起来。

host表能被用来维护一个“安全”服务器列表。在TcX，host表包含一个在本地的网络上所有的机器的表，这些被授予所有的权限。

你也可以使用host表指定不安全的主机。假定你有一台机器public.your.domain，它位于你不认为是安全的一个公共区域，你可以用下列的host表条目子允许除了那台机器外的网络上所有主机的存取：

+--------------------+----+-
| Host               | Db | ...
+--------------------+----+-
| public.your.domain | %  | ... (所有权限设为 'N')
| %.your.domain      | %  | ... (所有权限设为 'Y')
+--------------------+----+-

当然，你应该总是测试你在授权表中的条目(例如，使用mysqlaccess)让你确保你的存取权限实际上以你认为的方式被设置。

6.9 权限更改何时生效

当mysqld启动时，所有的授权表内容被读进存储器并且从那点生效。

用GRANT、REVOKE或SET PASSWORD对授权表施行的修改会立即被服务器注意到。

如果你手工地修改授权表(使用INSERT、UPDATE等等)，你应该执行一个FLUSH PRIVILEGES语句或运行mysqladmin flush-privileges告诉服务器再装载授权表，否则你的改变将不生效，除非你重启服务器。

当服务器注意到授权表被改变了时，现存的客户连接有如下影响：

  • 表和列权限在客户的下一次请求时生效。
  • 数据库权限改变在下一个USE db_name命令生效。

全局权限的改变和口令改变在下一次客户连接时生效。

6.10 建立初始的MySQL权限

在安装MySQL后，你通过运行scripts/mysql_install_db安装初始的存取权限。见4.7.1 快速安装概述。 scripts/mysql_install_db脚本启动mysqld服务器，然后初始化授权表，包含下列权限集合：

  • MySQL root用户作为可做任何事情的一个超级用户被创造。连接必须由本地主机发出。注意：出世的root口令是空的，因此任何人能以root而没有一个口令进行连接并且被授予所有权限。
  • 一个匿名用户被创造，他可对有一个'test'或以'test_'开始的名字的数据库做任何时期事情，连接必须由本地主机发出。这意味着任何本地用户能连接并且视为匿名用户。
  • 其他权限被拒绝。例如，一般用户不能使用mysqladmin shutdown或mysqladmin processlist。

注意：对Win32的初始权限是不同的。见4.12.4 在Win32上运行MySQL。

既然你的安装初始时广开大门，你首先应该做的事情之一是为MySQL root用户指定一个口令。你可以做如下(注意，你使用PASSWORD()函数指定口令)：

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;

在MySQL 3.22和以上版本中，你可以使用SET PASSWORD语句：

shell> mysql -u root mysql
mysql> SET PASSWORD FOR root=PASSWORD('new_password');

设置口令的另一种方法是使用mysqladmin命令：

shell> mysqladmin -u root password new_password

注意：如果你使用第一种方法在user表里直接更新口令，你必须告诉服务器再次读入授权表(用FLUSH PRIVILEGES)，因为否则改变将不被注意到。

一旦root口令被设置，此后当你作为root与服务器连接时，你必须供应那个口令。

你可能希望让root口令为空白以便当你施行附加的安装时，你不需要指定它或测试，但是保证在任何真实的生产工作中使用你的安装之前，设置它。

看看scripts/mysql_install_db脚本，看它如何安装缺省的权限。你可用它作为一个研究如何增加其他用户的基础。

如果你想要初始的权限不同于上面描述的那些，在你运行mysql_install_db之前，你可以修改它。

为了完全重建权限表，删除在包含mysql数据库的目录下所有“*.frm”,“*.MYI”和“*.MYD”文件。（这是在数据库目录下面命名为“mysql”的目录，当你运行mysqld --help时，它被列出。)然后运行mysql_install_db脚本，可能在首先编辑它拥有你想要的权限之后。

注意：对于比MySQL 3.22.10旧的版本，你不应该删除“*.frm”文件。如果你偶然做了，你应该在运行mysql_install_db之前你的MySQL分发中拷回它们。

6.11 向MySQL增加新用户权限

你可以有2个不同的方法增加用户：通过使用GRANT语句或通过直接操作MySQL授权表。比较好的方法是使用GRANT语句，因为他们是更简明并且好像错误少些。

下面的例子显示出如何使用mysql客户安装新用户。这些例子假定权限根据以前的章节描述的缺省被安装。这意味着为了改变，你必须在mysqld正在运行同一台机器上，你必须作为MySQL root用户连接，并且root用户必须对mysql数据库有insert权限和reload管理权限。另外，如果你改变了root用户口令，你必须如下的mysql命令指定它。

你可以通过发出GRANT语句增加新用户：

shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;

这些GRANT语句安装3个新用户：

monty
可以从任何地方连接服务器的一个完全的超级用户，但是必须使用一个口令('something'做这个。注意，我们必须对monty@localhost和monty@"%"发出GRANT语句。如果我们增加localhost条目，对localhost的匿名用户条目在我们从本地主机连接接时由mysql_install_db创建的条目将优先考虑，因为它有更特定的Host字段值，所以以user表排列顺序看更早到来。
admin
可以从localhost没有一个口令进行连接并且被授予reload和process管理权限的用户。这允许用户执行mysqladmin reload、mysqladmin refresh和mysqladmin flush-*命令，还有mysqladmin processlist。没有授予数据库有关的权限。他们能在以后通过发出另一个GRANT语句授权。
dummy
可以不用一个口令连接的一个用户，但是只能从本地主机。全局权限被设置为'N'--USAGE权限类型允许你无需权限就可设置一个用户。它假定你将在以后授予数据库相关的权限。

你也可以直接通过发出INSERT语句增加同样的用户存取信息，然后告诉服务器再次装入授权表：

shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user SET Host='localhost',User='admin',
                 Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
                        VALUES('localhost','dummy','');
mysql> FLUSH PRIVILEGES;

取决于你的MySQL版本，对上述，你可能必须使用一个不同数目'Y'值(在3.22.11以前的版本有更少的权限列)。对admin用户，只用在3.22.11开始的版本具有的更加可读的INSERT扩充的语法。

注意，为了设置一个超级用户，你只需创造一个user表条目，其权限字段设为'Y'。不需要db或host表的条目。

在user表中的权限列不是由最后一个INSERT语句明确设置的(对dummy用户)，因此那些列被赋予缺省值'N'。这是GRANT USAGE做的同样的事情。

下列例子增加一个用户custom，他能从主机localhost、server.domain和whitehouse.gov连接。他只想要从localhost存取bankaccount数据库，从whitehouse.gov存取expenses数据库和从所有3台主机存取customer数据库。他想要从所有3台主机上使用口令stupid。

为了使用GRANT语句设置个用户的权限，运行这些命令：

shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON bankaccount.*
           TO custom@localhost
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON expenses.*
           TO custom@whitehouse.gov
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON customer.*
           TO custom@'%'
           IDENTIFIED BY 'stupid';

通过直接修改授权表设置用户权限，运行这些命令(注意，在结束时FLUSH PRIVILEGES)：

shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;

头3个INSERT语句增加user表条目，允许用户custom用给定口令从不同的主机进行连接，但是没有授予任何许可(所有权限被设置为缺省值'N')。后3个INSERT语句增加db表条目，授予custom以bankaccount、expenses和customer数据库权限，但是只能在从正确的主机存取时。通常，在授权表直接被修改时，服务器必须被告知再次装入他们(用FLUSH PRIVILEGES)以便使权限修改生效。

如果你想要给特定的用户从一个给定的域上的任何机器上存取权限，你可以发出一个如下的GRANT语句：

mysql> GRANT ...
           ON *.*
           TO myusername@"%.mydomainname.com"
           IDENTIFIED BY 'mypassword';

为了通过直接修改授权表做同样的事情，这样做：

mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
           PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;

你也可以使用xmysqladmin、mysql_webadmin甚至xmysql在授权表中插入、改变和更新值。你可以在MySQL的Contrib目录找到这些实用程序。

6.12 怎样设置口令

在前面小节的例子里说明了一个重要的原则：当你使用INSERT或UPDATE语句存储一个非空的口令时，你必须使用PASSWORD()函数加密它。这是因为在user表中以加密形式存储口令，而不是作为纯文本。如果你忘记这个事实，你可能像这样试图设置口令：

shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password) VALUES('%','jeffrey','biscuit');
mysql> FLUSH PRIVILEGES

结果是纯文本值'biscuit'作为口令被存储在user表中。在用户jeffrey试图用这个口令连接服务器时，mysql客户用PASSWORD()加密它并且将结果送给服务器，服务器比较在user表中的值(它是纯文本值'biscuit')和加密的口令(而不是 'biscuit')，比较失败并且服务器拒绝连接：

shell> mysql -u jeffrey -pbiscuit test
Access denied

因为当他们被插入user表时，口令必须被加密，相反，INSERT语句应该象这样被指定：

mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey',PASSWORD('biscuit'));

当你使用SET PASSWORD语句时，你也必须使用PASSWORD()函数：

mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit');

如果你使用GRANT ... IDENTIFIED BY语句或mysqladmin password命令设置口令，PASSWORD()函数是不必要的。他们都考虑到为你加密口令，多以你可像这样指定一个口令'biscuit'：

mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';

或

shell> mysqladmin -u jeffrey password biscuit

注意： PASSWORD()不是以在Unix口令加密的同样方法施行口令加密。你不应该假定如果你的Unix口令和你的MySQL口令是一样的，PASSWORD()将导致与在Unix口令文件被存储的同样的加密值。见6.2 MySQL 用户名和口令。

6.13 Access denied错误的原因

当你试着联接MySQL服务器时，如果你碰到Access denied错误，显示在下面的表指出一些你能用来更正这个问题的动作：

  • 你是在安装MySQL以后运行mysql_install_db的脚本，来设置初始授权表内容吗？如果不是，这样做。见6.10 设置初始MySQL权限。通过执行这个命令测试初始权限：
    shell> mysql -u root test

    服务器应该让你无误地连接。你也应该保证你在MySQL数据库目录有一个文件“user.MYD”。通常，它是“PATH/var/mysql/user.MYD”，在此PATH是MySQL安装根目录的路径。

  • 在一个新的安装以后，你应该连接服务器并且设置你的用户及其存取许可：
    shell> mysql -u root mysql

    服务器应该让你连接，因为MySQL root用户初始时没有口令。既然那也是一个安全风险，当你正在设置其他MySQL用户时，设定root口令是一件重要的事请。如果你作为root尝试连接并且得到这个错误：

    Access denied for user: '@unknown' to database mysql

    这意味着，你没有一个条目在user表中的一个User列值为'root'并且mysqld不能为你的客库解析主机名。在这种情况下，你必须用--skip-grant-tables选项重启服务器并且编辑你的“/etc/hosts”或“\windows\hosts”文件为你的主机增加一个条目。

  • 如果你从一个3.22.11以前的版本更新一个现存的MySQL安装到3.22.11版或以后版本，你运行了mysql_fix_privilege_tables脚本吗？如果没有，运行它。在GRANT语句变得能工作时，授权表的结构用MySQL 3.22.11修改 。
  • 如果你直接对授权表做修改(使用INSERT或UPDATE语句)并且你的改变似乎被忽略，记住，你必须发出一个FLUSH PRIVILEGES语句或执行一个mysqladmin flush-privileges命令导致服务器再次读入表，否则你的改变要道下一次服务器被重启时再生效。记住在你设定root口令以后，你将不需要指定它，直到在你清洗(flush)权限以后，因为服务器仍然不会知道你改变了口令！
  • 如果你的权限似乎在一个会话(session)当中改变了，可能是一个超级用户改变了他们。再次装入授权表作用于新客户连接，但是它也影响现存的连接，如6.9 权限改变何时生效小节所述。
  • 为了测试，用--skip-grant-tables选项启动mysqld守护进程，然后你可以改变MySQL授权表并且使用mysqlaccess脚本检查你的修改是否有如期的效果。当你对你的改变满意时，执行mysqladmin flush-privileges告诉mysqld服务器开始使用新的权限表。注意：再次装入授权表覆盖了--skip-grant-tables选项。这允许你告诉服务器开始使用授权表，而不用停掉并重启它。
  • 如果你有一个Perl、Python或ODBC程序的存取问题，试着用mysql -u user_name db_name或mysql -u user_name -pyour_pass db_name与服务器连接。如果你能用mysql客户连接，这是你程序的一个问题而不是存取权限的问题。（注意在-p和口令之间没有空格；你也能使用--password=your_pass句法指定口令。）
  • 如果你不能让口令工作，记得如果你用INSERT, UPDATE或SET PASSWORD语句设置口令，你必须使用PASSWORD()函数。如果你用GRANT ... INDENTIFIED BY语句或mysqladmin password命令指定口令，PASSWORD()函数是不需要的。见6.12 怎样设置口令。
  • localhost是你本地主机名的一个同义词，并且也是如果你不明确地指定主机而客户尝试连接的缺省主机。然而，如果你正在运行于一个使用MIT-pthreads的系统上，连接localhost是不行的(localhost连接使用Unix套接字进行，它没被 MIT-pthreads支持)，为了在这样的系统上避免这个问题，你应该使用--host选项明确地命名服务器主机，这将做一个 TCP/IP连接到mysqld服务器。在这种情况下，你必须有在服务器主机上的user表中条目的你真实的主机名。（即使你在服务器同一台的主机上运行一个客户程序，这也是真的。）
  • 当尝试用mysql -u user_name db_name与数据库连接时，如果你得到一个Access denied错误，你可能有与user桌有关的问题，通过执行mysql -u root mysql并且发出下面的SQL语句检查：
    mysql> SELECT * FROM user;

    结果应该包含一个有Host和User列的条目匹配你的计算机主机名和你的MySQL用户名。

  • Access denied错误消息将告诉你，你正在用哪个用户尝试登录，你正在试图用连接哪个主机，并且你是否正在使用一个口令。通常，你应该在user表中有一个条目，正确地匹配在错误消息给出的主机名和用户名。
  • 如果当你试着从一个不是MySQL服务器正在运行的主机上连接时，你得到下列错误，那么在user表中没有匹配那台主机行：
    Host ... is not allowed to connect to this MySQL server

    你可以通过使用mysql命令行工具（在服务器主机上！)修正它，把你正在试图连接的用户/主机名组合新加一行到user表中。如果你不在运行MySQL 3.22并且你不知道你正在从它连接的机器的IP数字或主机名，你应该把一个'%'条目作为Host列值放在user表中并且在服务器机器上使用--log选项重启mysqld。在试图从客户机器连接以后，在MySQL记录文件中的信息将显示你如何真正进行连接。（然后用在记录文件上面显示出的实际的主机名代替user表中的'%'条目。否则，你将有一个不安全的系统。）

  • 如果mysql -u root test工作但是mysql -h your_hostname -u root test导致Access denied，那么在user表中你可能没有你的主机的正确名字。这里的一个普遍的问题是在user表条目中的Host值指定一个唯一的主机名，但是你系统的名字解析例程返回一个完全正规的域名(或相反)。例如，如果你在user表中有一个主机是'tcx'的条目，但是你的 DNS告诉MySQL你的主机名是'tcx.subnet.se'，条目将不工作。尝试把一个条目加到user表中，它包含你主机的IP数字作为Host列的值。（另外，你可以把一个条目加到user表中，它有包含一个通配符如'tcx.%'的Host值。然而，使用以“%”结尾的主机名是不安全的并且不推荐！）
  • 如果mysql -u user_name test工作但是mysql -u user_name other_db_name不工作，对other_db_name，你在db表中没有没有一个条目列出。
  • 当在服务器机器上执行mysql -u user_name db_name时，它工作，但是在其它客户机器上执行mysql -h host_name -u user_name db_name时，它却不工作，你没有把客户机器列在user表或db表中。
  • 如果你不能弄明白你为什么得到Access denied，从user表中删除所有Host包含通配符值的条目(包含“%”或“_”的条目)。一个很普遍的错误是插入用Host='%'和User='some user'插入一个新条目，认为这将允许你指定localhost从同一台机器进行连接。它不工作的原因是缺省权限包括一个有Host='localhost'和User=''的条目，因为那个条目一个比'%'更具体的Host值'localhost'，当从localhost连接时，它用于指向新条目！正确的步骤是插入Host='localhost'和User='some_user'的第2个条目，或删除Host='localhost'和User=''条目。
  • 如果你得到下列错误，你可以有一个与db或host表有关的问题：
    Access to database denied

    如果从db表中选择了在Host列有空值的条目，保证在host表中有一个或多个相应的条目，指定运用db表中的哪些主机。如果在使用SQL命令SELECT ... INTO OUTFILE或LOAD DATA INFILE时，你得到错误，在user表中的你的条目可能启用file权限。

  • 记住，客户程序将使用在配置文件或环境变量被指定了的连接参数。如果当你不在命令行上指定他们时，一个客户似乎正在发送错误的缺省连接参数，检查你的环境和在你的主目录下的“.my.cnf”文件。你也可以检查系统范围的MySQL配置文件，尽管更不可能将在那里指定那个客户的连接参数。见4.15.4 选项文件。如果当你没有任何选项运行一个客户时，你得到Access denied，确认你没在任何选项文件里指定一个旧的口令！见4.15.4 选项文件。
  • 如果任何其它事情失败，用调试选项(例如，--debug=d,general,query)启动mysqld守护进程。这将打印有关尝试连接的主机和用户信息，和发出的每个命令的信息。见G.1 调试一个MySQL服务器。
  • 如果你有任何与MySQL授权表的其它问题，而且觉得你必须邮寄这个问题到邮寄表，总是提供一个MySQL授权表的倾倒副本(dump)。你可用mysqldump mysql命令倾倒数据库表。象平时一样，用mysqlbug脚本邮寄你的问题。在一些情况下你可能用--skip-grant-tables重启mysqld以便能运行mysqldump。

6.14 怎样使MySQL安全以对抗解密高手

当你连接一个MySQL服务器时，你通常应该使用一个口令。口令不以明文在连接上传输。

所有其它信息作为能被任何人读懂的文本被传输。如果你担心这个，你可使用压缩协议(MySQL3.22和以上版本)使事情变得更难。甚至为了使一切更安全，你应该安装ssh（见http://www.cs.hut.fi/ssh)。用它，你能在一个MySQL服务器与一个MySQL客户之间得到一个加密的TCP/IP连接。

为了使一个MySQL系统安全，强烈要求你考虑下列建议：

  • 对所有MySQL用户使用口令。记住，如果other_user没有口令，任何人能简单地用mysql -u other_user db_name作为任何其它的人登录。对客户机/服务器应用程序，客户可以指定任何用户名是常见的做法。在你运行它以前，你可以通过编辑mysql_install_db脚本改变所有用户的口令，或仅仅MySQL root的口令，象这样：
    shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;
  • 不要作为Unix的root用户运行MySQL守护进程。mysqld能以任何用户运行，你也可以创造一个新的Unix用户mysql使一切更安全。如果你作为其它Unix用户运行mysqld，你不需要改变在user表中的root用户名，因为MySQL用户名与Unix 用户名没关系。你可以作为其它Unix用户编辑mysql.server启动脚本mysqld。通常这用su命令完成。对于更多的细节，见18.8 怎样作为一个一般用户运行MySQL。
  • 如果你把一个Unix root用户口令放在mysql.server脚本中，确保这个脚本只能对root是可读的。
  • 检查那个运行mysqld的Unix用户是唯一的在数据库目录下有读/写权限的用户。
  • 不要把process权限给所有用户。mysqladmin processlist的输出显示出当前执行的查询正文，如果另外的用户发出一个UPDATE user SET password=PASSWORD('not_secure')查询，被允许执行那个命令的任何用户可能看得到。mysqld为有process权限的用户保留一个额外的连接, 以便一个MySQL root用户能登录并检查，即使所有的正常连接在使用。
  • 不要把file权限给所有的用户。有这权限的任何用户能在拥有mysqld守护进程权限的文件系统那里写一个文件！为了使这更安全一些，用SELECT ... INTO OUTFILE生成的所有文件对每个人是可读的，并且你不能覆盖已经存在的文件。file权限也可以被用来读取任何作为运行服务器的Unix用户可存取的文件。这可能被滥用，例如，通过使用LOAD DATA装载“/etc/passwd”进一个数据库表，然后它能用SELECT被读入。
  • 如果你不信任你的DNS，你应该在授权表中使用IP数字而不是主机名。原则上讲，--secure选项对mysqld应该使主机名更安全。在任何情况下，你应该非常小心地使用包含通配符的主机名！

下列mysqld选项影响安全：

--secure
由gethostbyname()系统调用返回的IP数字被检查，确保他们解析回到原来的主机名。这对某些外人通过模仿其它主机获得存取权限变得更难。这个选项也增加一些聪明的主机名检查。在MySQL3.21里，选择缺省是关掉的，因为它有时它花很长时间执行反向解析。MySQL 3.22缓存主机名并缺省地启用了这个选项。
--skip-grant-tables
这个选项导致服务器根本不使用权限系统。这给每个人以完全存取所有的数据库的权力！（通过执行mysqladmin reload，你能告诉一个正在运行的服务器再次开始使用授权表。)
--skip-name-resolve
主机名不被解析。所有在授权表的Host的列值必须是IP数字或localhost。
--skip-networking
在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进行。这个选项对使用MIT-pthreads的系统是不合适的，因为MIT-pthreads包不支持Unix套接字。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册- 7 MySQL 语言参考

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

7 MySQL语言参考

7.1 文字：怎么写字符串和数字

7.1.1 字符串

一个字符串是一个字符序列，由单引号(“'”)或双引号(“"”)字符(后者只有你不在ANSI模式运行)包围。例如：

'a string'
"another string"

在字符串内，某个顺序有特殊的意义。这些顺序的每一个以一条反斜线(“\”)开始，称为转义字符。MySQL识别下列转义字符：

\0
一个ASCII 0 (NUL)字符。
\n
一个新行符。
\t
一个定位符。
\r
一个回车符。
\b
一个退格符。
\'
一个单引号(“'”)符。
\"
一个双引号(“"”)符。
\\
一个反斜线(“\”)符。
\%
一个“%”符。它用于在正文中搜索“%”的文字实例，否则这里“%”将解释为一个通配符。
\_
一个“_”符。它用于在正文中搜索“_”的文字实例，否则这里“_”将解释为一个通配符。

注意，如果你在某些正文环境中使用“\%”或“\%_”，这些将返回字符串“\%”和“\_”而不是“%”和“_”。

有几种方法在一个字符串内包括引号：

  • 一个字符串内用“'”加引号的“'”可以被写作为“''”。
  • 一个字符串内用“"”加引号的“"”可以被写作为“""”。
  • 你可以把一个转义字符（“\”）放在引号前面。
  • 一个字符串内用“"”加引号的“'”不需要特殊对待而且不必被重复或转义。同理，一个字符串内用“'”加引号的与“"”也不需要特殊对待。

下面显示的SELECT演示引号和转义如何工作：

mysql> SELECT 'hello', '"hello"', '""hello""', 'hel''lo', '\'hello';
+-------+---------+-----------+--------+--------+
| hello | "hello" | ""hello"" | hel'lo | 'hello |
+-------+---------+-----------+--------+--------+

mysql> SELECT "hello", "'hello'", "''hello''", "hel""lo", "\"hello";
+-------+---------+-----------+--------+--------+
| hello | 'hello' | ''hello'' | hel"lo | "hello |
+-------+---------+-----------+--------+--------+

mysql> SELECT "This\nIs\nFour\nlines";
+--------------------+
| This
Is
Four
lines |
+--------------------+

如果你想要把二进制数据插入到一个BLOB列，下列字符必须由转义序列表示：

NUL
ASCII 0。你应该用'\0'（一个反斜线和一个ASCII '0'）表示它。
\
ASCII 92，反斜线。用'\\'表示。
'
ASCII 39，单引号。用“\'”表示。
"
ASCII 34，双引号。用“\"”表示。

如果你写C代码，你可以使用C API函数mysql_escape_string()来为INSERT语句转义字符。见20.3 C API 函数概述。在 Perl中，你可以使用DBI包中的quote方法变换特殊的字符到正确的转义序列。见20.5.2 DBI接口。

你应该在任何可能包含上述任何特殊字符的字符串上使用转义函数！

7.1.2 数字

整数表示为一个数字顺序。浮点数使用“.”作为一个十进制分隔符。这两种类型的数字可以前置“-”表明一个负值。

有效整数的例子：

1221
0
-32

有效浮点数的例子：

294.42
-32032.6809e+10
148.00

一个整数可以在浮点上下文使用；它解释为等值的浮点数。

7.1.3 十六进制值

MySQL支持十六进制值。在数字上下文，它们表现类似于一个整数(64位精度)。在字符串上下文，它们表现类似于一个二进制字符串，这里每一对十六进制数字被变换为一个字符。

mysql> SELECT 0xa+0
       -> 10
mysql> select 0x5061756c;
       -> Paul

十六进制字符串经常被ODBC使用，给出BLOB列的值。

7.1.4 NULL值

NULL值意味着“无数据”并且不同于例如数字类型的0为或字符串类型的空字符串。见18.15 NULL值问题。

当使用文本文件导入或导出格式(LOAD DATA INFILE, SELECT ... INTO OUTFILE)时，NULL可以用\N表示。见7.16 LOAD DATA INFILE句法。

7.1.5 数据库、表、索引、列和别名的命名

数据库、表、索引、列和别名的名字都遵守MySQL同样的规则:

注意，从MySQL3.23.6开始规则改变了，此时我们引入了用'引用的标识符(数据库、表和列命名)（如果你以ANSI模式运行，"也将用于引用标识符）。

标识符 | 最大长度 | 允许的字符
数据库 | 64 | 在一个目录名允许的任何字符，除了/.
表 | 64 | 在文件名中允许的任何字符，除了/或.
列 | 64 | 所有字符
别名 | 255 | 所有字符

注意，除了以上，你在一个标识符中不能有ASCII(0)或ASCII(255)。

注意，如果标识符是一个限制词或包含特殊字符，当你使用它时，你必须总是用`引用它：

SELECT * from `select` where `select`.id > 100;

在 MySQL的先前版本，命名规则如下：

  • 一个名字可以包含来自当前字符集的数字字母的字符和“_”和“$”。缺省字符集是ISO-8859-1 Latin1；这可以通过重新编译MySQL来改变。见9.1.1 用于数据和排序的字符集。
  • 一个名字可以以在一个名字中合法的任何字符开始。特别地，一个名字可以以一个数字开始(这不同于许多其他的数据库系统!)。然而，一个名字不能仅仅由数字组成。
  • 你不能在名字中使用“.”，因为它被用来扩充格式，你能用它引用列(见下面)。

建议你不使用象1e这样的名字，因为一个表达式如1e+1是二义性的。它可以解释为表达式1e + 1或数字1e+1。

在MySQL中，你能使用下列表格的任何一种引用列：

列引用 | 含义
col_name | 来自于任意表的列col_name，用于包含该表的一个列的查询中
tbl_name.col_name | 来自当前的数据库的表tbl_name的列col_name
db_name.tbl_name.col_name | 行列col_name从表格tbl_name数据库db_name。这个形式在MySQL3.22或以后版本可用。
`column_name` | 是一个关键词或包含特殊字符的列。

在一条语句的列引用中，你不必指定一个tbl_name或db_name.tbl_name前缀，除非引用会有二义性。例如，假定表t1和t2，每个均包含列c，并且你用一个使用t1和t2的SELECT语句检索c。在这种情况下，c有二义性，因为它在使用表的语句中不是唯一的，因此你必须通过写出t1.c或t2.c来指明你想要哪个表。同样，如果你从数据库db1中一个表t和在数据库db2的一个表t检索，你必须用db1.t.col_name和db2.t.col_name引用这些数据表的列。

句法.tbl_name意味着在当前的数据库中的表tbl_name，该句法为了ODBC的兼容性被接受，因为一些ODBC程序用一个“.”字符作为数据库表名的前缀。

7.1.5.1 名字的大小写敏感性

在MySQL中，数据库和表对应于在那些目录下的目录和文件，因而，内在的操作系统的敏感性决定数据库和表命名的大小写敏感性。这意味着数据库和表名在Unix上是区分大小写的，而在Win32上忽略大小写。

注意：在Win32上，尽管数据库和表名是忽略大小写的，你不应该在同一个查询中使用不同的大小写来引用一个给定的数据库和表。下列查询将不工作，因为它作为my_table和作为MY_TABLE引用一个表：

mysql> SELECT * FROM my_table WHERE MY_TABLE.col=1;

列名在所有情况下都是忽略大小写的。

表的别名是区分大小写的。下列查询将不工作，: 因为它用a和A引用别名：

mysql> SELECT col_name FROM tbl_name AS a
           WHERE a.col_name = 1 OR A.col_name = 2;

列的别名是忽略大小写的。

7.2 用户变量

MySQL支持线程特定的变量，用@variablename句法。一个变量名可以由当前字符集的数字字母字符和“_”、“$”和“.”组成。缺省字符集是ISO-8859-1 Latin1；这可以通过重新编译MySQL改变。见9.1.1 用于数据和排序的字符集。

变量不必被初始化。缺省地，他们包含NULL并能存储整数、实数或一个字符串值。当线程退出时，对于一个线程的所有变量自动地被释放。

你可以用SET句法设置一个变量：

SET @variable= { integer expression | real expression | string expression }
[,@variable= ...].

你也可以用@variable:=expr句法在一个表达式中设置一个变量：

select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
+----------------------+------+------+------+
| @t1:=(@t2:=1)+@t3:=4 | @t1  | @t2  | @t3  |
+----------------------+------+------+------+
|                    5 |    5 |    1 |    4 |
+----------------------+------+------+------+

（这里，我们不得不使用:=句法，因为=是为比较保留的）

7.3 列类型

MySQL支持大量的列类型，它可以被分为3类：数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述，并且总结每个列类型的存储需求，然后提供每个类中的类型性质的更详细的描述。概述有意简化，更详细的说明应该考虑到有关特定列类型的附加信息，例如你能为其指定值的允许格式。

由MySQL支持的列类型列在下面。下列代码字母用于描述中：

M
指出最大的显示尺寸。最大的合法的显示尺寸是 255 。
D
适用于浮点类型并且指出跟随在十进制小数点后的数码的数量。最大可能的值是30，但是应该不大于M-2。

方括号(“[”和“]”)指出可选的类型修饰符的部分。

注意，如果你指定一个了为ZEROFILL，MySQL将为该列自动地增加UNSIGNED属性。

TINYINT[(M)] [UNSIGNED] [ZEROFILL]
一个很小的整数。有符号的范围是-128到127，无符号的范围是0到255。
SMALLINT[(M)] [UNSIGNED] [ZEROFILL]
一个小整数。有符号的范围是-32768到32767，无符号的范围是0到65535。
MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]
一个中等大小整数。有符号的范围是-8388608到8388607，无符号的范围是0到16777215。
INT[(M)] [UNSIGNED] [ZEROFILL]
一个正常大小整数。有符号的范围是-2147483648到2147483647，无符号的范围是0到4294967295。
INTEGER[(M)] [UNSIGNED] [ZEROFILL]
这是INT的一个同义词。
BIGINT[(M)] [UNSIGNED] [ZEROFILL]
一个大整数。有符号的范围是-9223372036854775808到9223372036854775807，无符号的范围是0到18446744073709551615。注意，所有算术运算用有符号的BIGINT或DOUBLE值完成，因此你不应该使用大于9223372036854775807（63位)的有符号大整数，除了位函数！注意，当两个参数是INTEGER值时，-、+和*将使用BIGINT运算！这意味着如果你乘2个大整数(或来自于返回整数的函数)，如果结果大于9223372036854775807，你可以得到意外的结果。一个浮点数字，不能是无符号的，对一个单精度浮点数，其精度可以是<=24，对一个双精度浮点数，是在25 和53之间，这些类型如FLOAT和DOUBLE类型马上在下面描述。FLOAT(X)有对应的FLOAT和DOUBLE相同的范围，但是显示尺寸和小数位数是未定义的。在MySQL3.23中，这是一个真正的浮点值。在更早的MySQL版本中，FLOAT(precision)总是有2位小数。该句法为了ODBC兼容性而提供。
FLOAT[(M,D)] [ZEROFILL]
一个小(单精密)浮点数字。不能无符号。允许的值是-3.402823466E+38到-1.175494351E-38，0 和1.175494351E-38到3.402823466E+38。M是显示宽度而D是小数的位数。没有参数的FLOAT或有<24 的一个参数表示一个单精密浮点数字。
DOUBLE[(M,D)] [ZEROFILL]
一个正常大小(双精密)浮点数字。不能无符号。允许的值是-1.7976931348623157E+308到-2.2250738585072014E-308、 0和2.2250738585072014E-308到1.7976931348623157E+308。M是显示宽度而D是小数位数。没有一个参数的DOUBLE或FLOAT(X)（25 < = X < = 53）代表一个双精密浮点数字。
DOUBLE PRECISION[(M,D)] [ZEROFILL]

REAL[(M,D)] [ZEROFILL]
这些是DOUBLE同义词。
DECIMAL[(M[,D])] [ZEROFILL]
一个未压缩(unpack)的浮点数字。不能无符号。行为如同一个CHAR列：“未压缩”意味着数字作为一个字符串被存储，值的每一位使用一个字符。小数点，并且对于负数，“-”符号不在M中计算。如果D是0，值将没有小数点或小数部分。DECIMAL值的最大范围与DOUBLE相同，但是对一个给定的DECIMAL列，实际的范围可以通过M和D的选择被限制。如果D被省略，它被设置为0。如果M被省掉，它被设置为10。注意，在MySQL3.22里，M参数包括符号和小数点。
NUMERIC(M,D) [ZEROFILL]
这是DECIMAL的一个同义词。
DATE
一个日期。支持的范围是'1000-01-01'到'9999-12-31'。MySQL以'YYYY-MM-DD'格式来显示DATE值，但是允许你使用字符串或数字把值赋给DATE列。
DATETIME
一个日期和时间组合。支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。MySQL以'YYYY-MM-DD HH:MM:SS'格式来显示DATETIME值，但是允许你使用字符串或数字把值赋给DATETIME的列。
TIMESTAMP[(M)]
一个时间戳记。范围是'1970-01-01 00:00:00'到2037年的某时。MySQL以YYYYMMDDHHMMSS、YYMMDDHHMMSS、YYYYMMDD或YYMMDD格式来显示TIMESTAMP值，取决于是否M是14（或省略)、12、8或6，但是允许你使用字符串或数字把值赋给TIMESTAMP列。一个TIMESTAMP列对于记录一个INSERT或UPDATE操作的日期和时间是有用的，因为如果你不自己给它赋值，它自动地被设置为最近操作的日期和时间。你以可以通过赋给它一个NULL值设置它为当前的日期和时间。见7.3.6 日期和时间类型。
TIME
一个时间。范围是'-838:59:59'到'838:59:59'。MySQL以'HH:MM:SS'格式来显示TIME值，但是允许你使用字符串或数字把值赋给TIME列。
YEAR[(2|4)]
一个2或4位数字格式的年(缺省是4位)。允许的值是1901到2155，和0000（4位年格式），如果你使用2位，1970-2069( 70-69)。MySQL以YYYY格式来显示YEAR值，但是允许你把使用字符串或数字值赋给YEAR列。（YEAR类型在MySQL3.22中是新类型。）
CHAR(M) [BINARY]
一个定长字符串，当存储时，总是是用空格填满右边到指定的长度。M的范围是1 ～ 255个字符。当值被检索时，空格尾部被删除。CHAR值根据缺省字符集以大小写不区分的方式排序和比较，除非给出BINARY关键词。NATIONAL CHAR（短形式NCHAR)是ANSI SQL的方式来定义CHAR列应该使用缺省字符集。这是MySQL的缺省。CHAR是CHARACTER的一个缩写。
[NATIONAL] VARCHAR(M) [BINARY]
一个变长字符串。注意：当值被存储时，尾部的空格被删除(这不同于ANSI SQL规范)。M的范围是1 ～ 255个字符。 VARCHAR值根据缺省字符集以大小写不区分的方式排序和比较，除非给出BINARY关键词值。见7.7.1 隐式列指定变化。 VARCHAR是CHARACTER VARYING一个缩写。
TINYBLOB

TINYTEXT
一个BLOB或TEXT列，最大长度为255(2^8-1)个字符。见7.7.1 隐式列指定变化。
BLOB

TEXT
一个BLOB或TEXT列，最大长度为65535(2^16-1)个字符。见7.7.1 隐式列指定变化。
MEDIUMBLOB

MEDIUMTEXT
一个BLOB或TEXT列，最大长度为16777215(2^24-1)个字符。见7.7.1 隐式列指定变化。
LONGBLOB

LONGTEXT
一个BLOB或TEXT列，最大长度为4294967295(2^32-1)个字符。见7.7.1 隐式列指定变化
ENUM('value1','value2',...)
枚举。一个仅有一个值的字符串对象，这个值式选自与值列表'value1'、'value2', ...,或NULL。一个ENUM最多能有65535不同的值。
SET('value1','value2',...)
一个集合。能有零个或多个值的一个字符串对象，其中每一个必须从值列表'value1', 'value2', ...选出。一个SET最多能有64个成员。

7.3.1 列类型存储需求

对于每个由MySQL支持的列类型的存储需求在下面按类列出。

7.3.2 数字类型

列类型 | 需要的存储量
TINYINT | 1 字节
SMALLINT | 2 个字节
MEDIUMINT | 3 个字节
INT | 4 个字节
INTEGER | 4 个字节
BIGINT | 8 个字节
FLOAT(X) | 4 如果 X < = 24 或 8 如果 25 < = X < = 53
FLOAT | 4 个字节
DOUBLE | 8 个字节
DOUBLE PRECISION | 8 个字节
REAL | 8 个字节
DECIMAL(M,D) | M字节(D+2 , 如果M < D)
NUMERIC(M,D) | M字节(D+2 , 如果M < D)

7.3.3 日期和时间类型

列类型 | 需要的存储量
DATE | 3 个字节
DATETIME | 8 个字节
TIMESTAMP | 4 个字节
TIME | 3 个字节
YEAR | 1 字节

7.3.4 串类型

列类型 | 需要的存储量
CHAR(M) | M字节，1 <= M <= 255
VARCHAR(M) | L+1 字节, 在此L <= M和1 <= M <= 255
TINYBLOB, TINYTEXT | L+1 字节, 在此L< 2 ^ 8
BLOB, TEXT | L+2 字节, 在此L< 2 ^ 16
MEDIUMBLOB, MEDIUMTEXT | L+3 字节, 在此L< 2 ^ 24
LONGBLOB, LONGTEXT | L+4 字节, 在此L< 2 ^ 32
ENUM('value1','value2',...) | 1 或 2 个字节, 取决于枚举值的数目(最大值65535）
SET('value1','value2',...) | 1，2，3，4或8个字节, 取决于集合成员的数量(最多64个成员）

VARCHAR和BLOB和TEXT类型是变长类型，对于其存储需求取决于列值的实际长度(在前面的表格中用L表示)，而不是取决于类型的最大可能尺寸。例如，一个VARCHAR(10)列能保存最大长度为10个字符的一个字符串，实际的存储需要是字符串的长度(L)，加上1个字节以记录字符串的长度。对于字符串'abcd'，L是4而存储要求是5个字节。

BLOB和TEXT类型需要1，2，3或4个字节来记录列值的长度，这取决于类型的最大可能长度。

如果一个表包括任何变长的列类型，记录格式将也是变长的。注意，当一个表被创建时，MySQL可能在某些条件下将一个列从一个变长类型改变为一个定长类型或相反。见7.7.1 隐式列指定变化。

一个ENUM对象的大小由不同枚举值的数量决定。1字节被用于枚举，最大到255个可能的值；2个字节用于枚举，最大到65535 值。

一个SET对象的大小由不同的集合成员的数量决定。如果集合大小是N，对象占据(N+7)/8个字节，四舍五入为1，2，3，4或8 个字节。一个SET最多能有64个成员。

7.3.5 数字类型

MySQL支持所有的ANSI/ISO SQL92的数字类型。这些类型包括准确数字的数据类型(NUMERIC, DECIMAL, INTEGER,和SMALLINT)，也包括近似数字的数据类型(FLOAT, REAL,和DOUBLE PRECISION)。关键词INT是INTEGER的一个同义词，而关键词DEC是DECIMAL一个同义词。

NUMERIC和DECIMAL类型被MySQL实现为同样的类型，这在SQL92标准允许。他们被用于保存值，该值的准确精度是极其重要的值，例如与金钱有关的数据。当声明一个类是这些类型之一时，精度和规模的能被(并且通常是)指定；例如：

salary DECIMAL(9,2)

在这个例子中，9(precision)代表将被用于存储值的总的小数位数，而2(scale)代表将被用于存储小数点后的位数。因此，在这种情况下，能被存储在salary列中的值的范围是从-9999999.99到9999999.99。在ANSI/ISO SQL92中，句法DECIMAL(p)等价于DECIMAL(p,0)。同样，句法DECIMAL等价于DECIMAL(p,0)，这里实现被允许决定值p。MySQL当前不支持DECIMAL/NUMERIC数据类型的这些变种形式的任一种。这一般说来不是一个严重的问题，因为这些类型的主要益处得自于明显地控制精度和规模的能力。

DECIMAL和NUMERIC值作为字符串存储，而不是作为二进制浮点数，以便保存那些值的小数精度。一个字符用于值的每一位、小数点(如果scale>0)和“-”符号(对于负值)。如果scale是0，DECIMAL和NUMERIC值不包含小数点或小数部分。

DECIMAL和NUMERIC值得最大的范围与DOUBLE一样，但是对于一个给定的DECIMAL或NUMERIC列，实际的范围可由制由给定列的precision或scale限制。当这样的列赋给了小数点后面的位超过指定scale所允许的位的值，该值根据scale四舍五入。当一个DECIMAL或NUMERIC列被赋给了其大小超过指定(或缺省的）precision和scale隐含的范围的值，MySQL存储表示那个范围的相应的端点值。

作为对ANSI/ISO SQL92标准的扩展，MySQL也支持上表所列的整型类型TINYINT、MEDIUMINT和BIGINT。另一个扩展是MySQL支持可选地指定一个整型值显示的宽度，用括号跟在基本关键词之后(例如，INT(4))。这个可选的宽度指定被用于其宽度小于列指定宽度的值得左填补显示，但是不限制能在列中被存储的值的范围，也不限制值将被显示的位数，其宽度超过列指定的宽度。当与可选的扩展属性ZEROFILL一起使用时，缺省的空格填补用零代替。例如，对于声明为INT(5) ZEROFILL的列，一个为4的值作为00004被检索。注意，如果你在一个整型列存储超过显示宽度的更大值，当MySQL对于某些复杂的联结(join)生成临时表时，你可能会遇到问题，因为在这些情况下，MySQL相信数据确实适合原来的列宽度。

所有的整型类型可以有一个可选(非标准的)属性UNSIGNED。当你想要在列中仅允许正数并且你需要一个稍大一点的列范围，可以使用无符号值。

FLOAT类型被用来标示近似数字的数据类型。ANSI/ISO SQL92标准允许一个可选的精度说明(但不是指数的范围)，跟在关键词FLOAT后面的括号内位数。MySQL实现也支持这个可选的精度说明。当关键词FLOAT被用于一个列类型而没有精度说明时，MySQL使用4个字节存储值。一个变种的句法也被支持，在FLOAT关键词后面的括号给出2个数字。用这个选项，第一个数字继续表示在字节计算的值存储需求，而第二个数字指定要被存储的和显示跟随小数点后的位数(就象DECIMAL和NUMERIC)。当MySQL要求为这样一个列，一个小数点后的小数位超过列指定的值，存储值时，该值被四舍五入，去掉额外的位。

REAL和DOUBLE PRECISION类型不接受精度说明。作为对 ANSI/ISO SQL92 标准的扩展，MySQL识别出DOUBLE作为DOUBLE PRECISION类型的一个同义词。与REAL精度比用于DOUBLE PRECISION的更小的标准要求相反，MySQL实现了两种，作为8字节双精度浮点值(当运行不是“Ansi模式”时)。为了最大的移植性，近似数字的数据值的存储所需代码应该使用没有精度或小数位数说明的FLOAT或DOUBLE PRECISION。

当要求在数字的列存储超出该列类型允许的范围的值时，MySQL剪切该值到范围内的正确端点值并且存储剪切后的结果值。

例如，一个INT列的范围是-2147483648到2147483647。如果你试图插入-9999999999到一个INT列中，值被剪切到范围的低部端点，并存储-2147483648。同样，如果你试图插入9999999999，2147483647被存储。

如果INT列是UNSIGNED，列的范围的大小是相同的，但是它的端点移到了0和4294967295。如果你试图存储-9999999999和9999999999，在列被存储的值变为0和4294967296。

对于ALTER TABLE、LOAD DATA INFILE、UPDATE和多行INSERT语句，由于剪切所发生的变换作为“警告”被报告。

7.3.6 日期和时间类型

日期和时间类型是DATETIME、DATE、TIMESTAMP、TIME和YEAR。这些的每一个都有合法值的一个范围，而“零”当你指定确实不合法的值时被使用。注意，MySQL允许你存储某个“不严格地”合法的日期值，例如1999-11-31，原因我们认为它是应用程序的责任来处理日期检查，而不是SQL服务器。为了使日期检查更“快”，MySQL仅检查月份在0-12的范围，天在0-31的范围。上述范围这样被定义是因为MySQL允许你在一个DATE或DATETIME列中存储日期，这里的天或月是零。这对存储你不知道准确的日期的一个生日的应用程序来说是极其有用的，在这种情况下，你简单地存储日期象1999-00-00或1999-01-00。（当然你不能期望从函数如DATE_SUB()或DATE_ADD()得到类似以这些日期的正确值)。

当用日期和时间工作时，这里是的一些要记住的一般考虑：

  • MySQL对一个给定的日期或时间类型以标准的格式检索，但是它试图为你提供的值解释成许多格式(例如，当你指定一个值被赋给或与比较一个日期或时间类型时)，但是只支持有在下列小节描述的格式。期望你提供合法的值，并且如果你以其他格式使用这些值，可能造成无法预料的结果。
  • 尽管MySQL试图以多种格式解释值，但它总是期望日期值的年份部分在最左面，日期必须以年-月-日的顺序给出(例如，'98-09-04')，而不是以其他地方常用的月-日-年或日-月-年的次序(例如，'09-04-98'、'04-09-98')。
  • 如果一个值在数字的上下文环境中被使用，MySQL自动变换一个日期或时间类型值到一个数字，反过来也如此。
  • 当MySQL遇到一个日期或时间类型的值超出范围或对给类型不合法(见本节的开始)时，它将该类型的值变换到“零”值。（例外的是超出范围的TIME值被剪切为适当的TIME范围端点值。)下表显示对每种类型的“零”值的格式：
    列类型 | “零”值
    DATETIME | '0000-00-00 00:00:00'
    DATE | '0000-00-00'
    TIMESTAMP | 00000000000000（长度取决于显示尺寸）
    TIME | '00:00:00'
    YEAR | 0000
  • “零”值是特殊的，但是你能使用在表中显示的值来明显地存储或引用他们。你也可以使用值'0'或0做到, 这更容易写。
  • 在MyODBC 2.50.12和以上版本中，由MyODBC使用的“零”日期或时间值被自动变换到NULL，因为ODBC不能处理这样的值。

7.3.6.1 Y2K问题和日期类型

MySQL本身Y2K安全的(见1.6 2000年一致性)，但是呈交给MySQL的输入值可能不是。一个包含2位年份值的任何输入是由二义性的，因为世纪是未知的。这样的值必须被解释成4位形式，因为MySQL内部使用4位存储年份。

对于DATETIME, DATE, TIMESTAMP和YEAR类型，MySQL使用下列规则的解释二义性的年份值：

  • 在范围00-69的年值被变换到2000-2069。
  • 在范围70-99的年值被变换到1970-1999。

记得这些规则仅仅提供对于你数据的含义的合理猜测。如果MySQL使用的启发规则不产生正确的值，你应该提供无二义的包含4位年值的输入。

7.3.6.2 DATETIME, DATE和TIMESTAMP类型

DATETIME, DATE和TIMESTAMP类型是相关的。本节描述他们的特征，他们是如何类似的而又不同的。

DATETIME类型用在你需要同时包含日期和时间信息的值时。MySQL检索并且以'YYYY-MM-DD HH:MM:SS'格式显示DATETIME值，支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。（“支持”意味着尽管更早的值可能工作，但不能保证他们可以。）

DATE类型用在你仅需要日期值时，没有时间部分。MySQL检索并且以'YYYY-MM-DD'格式显示DATE值，支持的范围是'1000-01-01'到'9999-12-31'。

TIMESTAMP列类型提供一种类型，你可以使用它自动地用当前的日期和时间标记INSERT或UPDATE的操作。如果你有多个TIMESTAMP列，只有第一个自动更新。

自动更新第一个TIMESTAMP列在下列任何条件下发生：

  • 列没有明确地在一个INSERT或LOAD DATA INFILE语句中指定。
  • 列没有明确地在一个UPDATE语句中指定且一些另外的列改变值。（注意一个UPDATE设置一个列为它已经有的值，这将不引起TIMESTAMP列被更新，因为如果你设置一个列为它当前的值，MySQL为了效率而忽略更改。）
  • 你明确地设定TIMESTAMP列为NULL.

除第一个以外的TIMESTAMP列也可以设置到当前的日期和时间，只要将列设为NULL，或NOW()。

通过明确地设置希望的值，你可以设置任何TIMESTAMP列为不同于当前日期和时间的值，即使对第一个TIMESTAMP列也是这样。例如，如果，当你创建一个行时，你想要一个TIMESTAMP被设置到当前的日期和时间，但在以后无论何时行被更新时都不改变，你可以使用这个属性：

  • 让MySQL在行被创建时设置列，这将初始化它为当前的日期和时间。
  • 当你执行随后的对该行中其他列的更改时，明确设定TIMESTAMP列为它的当前值。

另一方面，你可能发现，当行被创建并且远离随后的更改时，很容易用一个你用NOW()初始化的DATETIME列。

TIMESTAMP值可以从1970的某时的开始一直到2037年，精度为一秒，其值作为数字显示。

在MySQL检索并且显示TIMESTAMP值取决于显示尺寸的格式如下表。“完整”TIMESTAMP格式是14位，但是TIMESTAMP列可以用更短的显示尺寸创造：

列类型 | 显示格式
TIMESTAMP(14) | YYYYMMDDHHMMSS
TIMESTAMP(12) | YYMMDDHHMMSS
TIMESTAMP(10) | YYMMDDHHMM
TIMESTAMP(8) | YYYYMMDD
TIMESTAMP(6) | YYMMDD
TIMESTAMP(4) | YYMM
TIMESTAMP(2) | YY

所有的TIMESTAMP列都有同样的存储大小，不考虑显示尺寸。最常见的显示尺寸是6、8、12、和14。你可以在表创建时间指定一个任意的显示尺寸，但是值0或比14大被强制到14。在从1～13范围的奇数值尺寸被强制为下一个更大的偶数。

使用一个常用的格式集的任何一个，你可以指定DATETIME、DATE和TIMESTAMP值：

  • 'YYYY-MM-DD HH:MM:SS'或'YY-MM-DD HH:MM:SS'格式的一个字符串。允许一种“宽松”的语法--任何标点可用作在日期部分和时间部分之间的分隔符。例如，'98-12-31 11:30:45'、'98.12.31 11+30+45'、'98/12/31 11*30*45'和'98@12@31 11^30^45'是等价的。
  • 'YYYY-MM-DD'或'YY-MM-DD'格式的一个字符串。允许一种“宽松”的语法。例如，'98-12-31', '98.12.31', '98/12/31'和'98@12@31'是等价的。
  • 'YYYYMMDDHHMMSS'或'YYMMDDHHMMSS'格式的没有任何分隔符的一个字符串，例如，'19970523091528'和'970523091528'被解释为'1997-05-23 09:15:28'，但是'971122459015'是不合法的(它有毫无意义的分钟部分)且变成'0000-00-00 00:00:00'。
  • 'YYYYMMDD'或'YYMMDD'格式的没有任何分隔符的一个字符串，如果字符串认为是一个日期。例如，'19970523'和'970523'被解释作为'1997-05-23'，但是'971332'是不合法的( 它有无意义的月和天部分)且变成'0000-00-00'。
  • YYYYMMDDHHMMSS或YYMMDDHHMMSS格式的一个数字，如果数字认为是一个日期。例如，19830905132800和830905132800被解释作为'1983-09-05 13:28:00'。
  • YYYYMMDD或YYMMDD格式的一个数字，如果数字认为是一个日期。例如，19830905和830905被解释作为'1983-09-05'。
  • 一个返回值可以在一个DATETIME, DATE或TIMESTAMP上下文环境中接受的函数，例如NOW()或CURRENT_DATE。

不合法DATETIME, DATE或TIMESTAMP值被变换到适当类型的“零”值('0000-00-00 00:00:00', '0000-00-00'或00000000000000)。

对于包括的日期部分分隔符的指定为字符串的值，不必要为小于10的月或天的值指定2位数字，'1979-6-9'与'1979-06-09'是一样的。同样, 对于包括的时间部分分隔符的指定为字符串的值，不必为小于10的小时、月或秒指定2位数字，'1979-10-30 1:2:3'与'1979-10-30 01:02:03'是一样的。

指定为数字应该是6、8、12或14位长。如果数字是8或14位长，它被假定以YYYYMMDD或YYYYMMDDHHMMSS格式并且年份由头4位数字给出。如果数字是6或12位长，它被假定是以YYMMDD或YYMMDDHHMMSS格式且年份由头2位数字给出。不是这些长度之一的数字通过填补前头的零到最接近的长度来解释。

指定为无分隔符的字符串用它们给定的长度来解释。如果字符串长度是8或14个字符，年份被假定头4个字符给出，否则年份被假定由头2个字符给出。对于字符串中呈现的多个部分，字符串从左到右边被解释，以找出年、月、日、小时、分钟和秒值，这意味着，你不应该使用少于 6 个字符的字符串。例如，如果你指定'9903'，认为将代表1999年3月，你会发现MySQL把一个“零”日期插入到你的表中，这是因为年份和月份值99和03，但是日期部分丢失(零)，因此该值不是一个合法的日期。

TIMESTAMP列使用被指定的值的完整精度的存储合法的值，不考虑显示大小。这有几个含意：

  • 总是指定年，月，和日，即使你的列类型是TIMESTAMP(4)或TIMESTAMP(2)。否则，值将不是一个合法的日期并且0将被存储。
  • 如果你使用ALTER TABLE拓宽一个狭窄的TIMESTAMP列，以前被“隐蔽”的信息将被显示。
  • 同样，缩小一个TIMESTAMP列不会导致信息失去，除了感觉上值在显示时，较少的信息被显示出。
  • 尽管TIMESTAMP值被存储为完整精度，直接操作存储值的唯一函数是UNIX_TIMESTAMP()，其他函数操作在格式化了的检索的值上，这意味着你不能使用函数例如HOUR()或SECOND()，除非TIMESTAMP值的相关部分被包含在格式化的值中。例如，一个TIMESTAMP列的HH部分部被显示，除非显示大小至少是10，因此在更短的TIMESTAMP值上试试使用HOUR()产生一个无意义的结果。

在某种程度上，你可以把一种日期类型的值赋给一个不同的日期类型的对象。然而，这可能值有一些改变或信息的损失：

  • 如果你将一个DATE值赋给一个DATETIME或TIMESTAMP对象，结果值的时间部分被设置为'00:00:00'，因为DATE值不包含时间信息。
  • 如果你将一个DATETIME或TIMESTAMP值赋给一个DATE对象，结果值的时间部分被删除，因为DATE类型不存储时间信息。
  • 记住，尽管DATETIME, DATE和TIMESTAMP值全都可以用同样的格式集来指定，但所有类型不都有同样的值范围。例如，TIMESTAMP值不能比1970早或比2037网晚，这意味着，一个日期例如'1968-01-01'，当作为一个DATETIME或DATE值合法时，它不是一个正确TIMESTAMP值，并且如果赋值给这样一个对象，它将被变换到0。

当指定日期值时，当心某些缺陷：

  • 允许作为字符串指定值的宽松格式能被欺骗。例如，值例如'10:11:12'可能看起来像时间值，因为“:”分隔符，但是如果在一个日期中使用，上下文将作为年份被解释成'2010-11-12'。值'10:45:15'将被变换到'0000-00-00'，因为'45'不是一个合法的月份。
  • 以2位数字指定的年值是模糊的，因为世纪是未知的。MySQL使用下列规则解释2位年值：
    • 在00-69范围的年值被变换到2000-2069。
    • 在范70-99围的年值被变换到1970-1999。

7.3.6.3 TIME类型

MySQL检索并以'HH:MM:SS'格式显示TIME值(或对大小时值，'HHH:MM:SS'格式)。TIME值的范围可以从'-838:59:59'到'838:59:59'。小时部分可能很大的的原因是TIME类型不仅可以被使用在表示一天的时间(它必须是不到24个小时)，而且用在表示在2个事件之间经过的时间或时间间隔(它可以是比24个小时大些，或甚至是负值)。

你能用多中格式指定TIME值：

  • 作为'HH:MM:SS'格式的一个字符串。“宽松”的语法被允许--任何标点符号可用作时间部分的分隔符，例如，'10:11:12'和'10.11.12'是等价的。
  • 作为没有分隔符的'HHMMSS'格式的一个字符串，如果它作为一个时间解释。例如，'101112'被理解为'10:11:12'，但是'109712'是不合法的(它有无意义的分钟部分)并变成'00:00:00'。
  • 作为HHMMSS格式的一个数字，如果它能解释为一个时间。例如，101112被理解为'10:11:12'。
  • 返回值可在一个TIME上下文接受的函数，例如CURRENT_TIME。

对于作为包括一个时间分隔符的字符串被指定的TIME值，不必为小于10的小时、分钟或秒值指定2位数字，'8:3:2'与'08:03:02'是一样的。

将“短的”TIME值赋值给一个TIME行列是要格外小心。MySQL使用最右位代表秒的假设来解释值。(MySQL将TIME值解释为经过的时间，而非作为一天的时间 )例如，你可能想到'11:12'、'1112'和1112意味着'11:12:00'（11点12分)，但是MySQL解释他们为'00:11:12'（11分12秒)。同样，'12'和12被解释为'00:00:12'。

但是超出TIME范围之外的值是样合法的，它被剪切到范围适当的端点值。例如，'-850:00:00'和'850:00:00'被变换到'-838:59:59'和'838:59:59'。

不合法的TIME值被变换到'00:00:00'。注意，既然'00:00:00'本身是一个合法的TIME值，没有其他方法区分表中存储的一个'00:00:00'值，原来的值是否被指定为'00:00:00'或它是否是不合法的。

7.3.6.4 YEAR类型

YEAR类型是一个 1 字节类型用于表示年份。

MySQL检索并且以YYYY格式显示YEAR值，其范围是1901到2155。

你能用多种格式指定YEAR值：

  • 作为在'1901'到'2155'范围的一个4位字符串。
  • 作为在1901到2155范围的一个4位数字。
  • 作为在'00'到'99'范围的一个2位字符串.在'00'到'69'和'70'到'99'范围的值被变换到在2000到2069范围和1970到1999的YEAR值。
  • 作为在1到99范围的一个2位数字。在范围1到69和70到99的值被变换到在范围2001到2069和1970到1999的YEAR的值。注意对于2位数字的范围略微不同于2位数字字符串的范围，因为你不能直接指定零作为一个数字并且把它解释为2000。你必须作为一个字符串'0'或'00'指定它，它将被解释为0000。
  • 其返回值可在一个YEAR上下文环境中接受的函数，例如NOW()。

不合法YEAR值被变换到0000。

7.3.7 字符串类型

字符串类型是CHAR、VARCHAR、BLOB、TEXT、ENUM和SET。

7.3.7.1 CHAR和VARCHAR类型

CHAR和VARCHAR类型是类似的，但是在他们被存储和检索的方式不同。

一个CHAR列的长度被修正为在你创造表时你所声明的长度。长度可以是1和255之间的任何值。（在MySQL 3.23中，CHAR长度可以是0～255。) 当CHAR值被存储时，他们被用空格在右边填补到指定的长度。当CHAR值被检索时，拖后的空格被删去。

在VARCHAR列中的值是变长字符串。你可以声明一个VARCHAR列是在1和255之间的任何长度，就像对CHAR列。然而，与CHAR相反，VARCHAR值只存储所需的字符，外加一个字节记录长度，值不被填补；相反，当值被存储时，拖后的空格被删去。（这个空格删除不同于ANSI SQL规范。）

如果你把一个超过列最大长度的值赋给一个CHAR或VARCHAR列，值被截断以适合它。

下表显示了两种类型的列的不同，通过演示存储变长字符串值到CHAR(4)和VARCHAR(4)列：

值 | CHAR(4) | 存储需求 | VARCHAR(4) | 存储需求
'' | ' ' | 4 个字节 | '' | 1 字节
'ab' | 'ab ' | 4 个字节 | 'ab' | 3 个字节
'abcd' | 'abcd' | 4 个字节 | 'abcd' | 5 个字节
'abcdefgh' | 'abcd' | 4 个字节 | 'abcd' | 5 个字节

从CHAR(4)和VARCHAR(4)列检索的值在每种情况下都是一样的，因为拖后的空格从检索的CHAR列上被删除。

在CHAR和VARCHAR列中存储和比较值是以大小写不区分的方式进行的，除非当桌子被创建时，BINARY属性被指定。BINARY属性意味着该列的值根据MySQL服务器正在运行的机器的ASCII顺序以大小写区分的方式存储和比较。

BINARY属性是“粘性”的。这意味着，如果标记了BINARY的列用于一个表达式中，整个的表达式作为一个BINARY值被比较。

MySQL在表创建时可以隐含地改变一个CHAR或VARCHAR列的类型。见7.7.1 隐含的的列说明改变。

7.3.7.2 BLOB和TEXT类型

一个BLOB是一个能保存可变数量的数据的二进制的大对象。4个BLOB类型TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB仅仅在他们能保存值的最大长度方面有所不同。见7.3.1 列类型存储需求。

4个TEXT类型TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT对应于4个BLOB类型，并且有同样的最大长度和存储需求。在BLOB和TEXT类型之间的唯一差别是对BLOB值的排序和比较以大小写敏感方式执行，而对TEXT值是大小写不敏感的。换句话说，一个TEXT是一个大小写不敏感的BLOB。

如果你把一个超过列类型最大长度的值赋给一个BLOB或TEXT列，值被截断以适合它。

在大多数方面，你可以认为一个TEXT行列是你所希望大的一个VARCHAR列。同样，你可以认为一个BLOB列是一个VARCHAR BINARY列。差别是：

  • 用MySQL版本3.23.2和更新，你能在BLOB和TEXT列上索引。更旧的MySQL版本不支持这个。
  • 当值被存储时，对BLOB和TEXT列没有拖后空格的删除，因为对VARCHAR列有删除。
  • BLOB和TEXT列不能有DEFAULT值。

MyODBC定义BLOB为LONGVARBINARY，TEXT值为LONGVARCHAR。

因为BLOB和TEXT值可以是非常长的，当使用他们时，你可能遇到一些限制：

  • 如果你想要在一个BLOB或TEXT列上使用GROUP BY或ORDER BY，你必须将列值变换成一个定长对象。这样做的标准方法是用SUBSTRING函数。例如：
    mysql> select comment from tbl_name,substring(comment,20) as substr ORDER BY substr;

    如果你不这样做，在排序时，只有列的首max_sort_length个字节被使用，缺省的max_sort_length是1024；这个值能在启动mysqld服务器时使用-O选择改变。你可以在包含BLOB或TEXT值得一个表达式上分组(group)，通过指定列的位置或使用一个别名：

    mysql> select id,substring(blob_col,1,100) from tbl_name
           GROUP BY 2;
mysql> select id,substring(blob_col,1,100) as b from tbl_name
           GROUP BY b;
  • 一个BLOB或TEXT对象的最大尺寸由其类型决定，但是你能在客户与服务器之间是实际传输的最大值由可用的内存数量和通讯缓冲区的大小来决定。你能改变消息缓冲区大小，但是你必须在服务器和客户两端做。见10.2.3 调节服务器参数。

注意，每个BLOB或TEXT值内部由一个独立分配的对象表示。这与所有的其他列类型相反，它们是在打开表时，按列被分配一次存储。

7.3.7.3 ENUM类型

一个ENUM是一个字符对象，其值通常从一个在表创建时明确被列举的允许值的一张表中选择。

在下列的某个情形下，值也可以空字符串("")或NULL：

  • 如果你把一个无效值插入到一个ENUM（即，一个不在允许的值列表中的字符串)，空字符串作为一个特殊错误的值被插入。
  • 如果一个ENUM被声明为NULL，NULL也是列的合法值，并且缺省值是NULL。如果一个ENUM被声明为NOT NULL，缺省值是允许值的列表的第一成员。

每枚举值有一个编号：

  • 在列说明中来自允许成员值列表值用从1开始编号。
  • 空字符串错误值的编号值是0。这意味着，你能使用下列SELECT语句找出被赋给无效ENUM值的行：
    mysql> SELECT * FROM tbl_name WHERE enum_col=0;
  • NULL值的编号是NULL。

例如，指定为ENUM("one", "two", "three")的列可以有显示在下面的值的任何一个。每个值的编号也被显示：

值 | 编号
NULL | NULL
"" | 0
"one" | 1
"two" | 2
"three" | 3

枚举可以有最大65535个成员。

当你把值赋给一个ENUM列时，字母的大小写是无关紧要的。然而，以后从列中检索的值大小写匹配在表创建时用来指定允许值的值的大小写。

如果你在一个数字的上下文环境中检索一个ENUM，列值的编号被返回。如果你存储一个数字到一个ENUM中，数字被当作一个标号，并且存储的值是该编号的枚举成员。

ENUM值根据列说明列举的枚举成员的次序被排序。（换句话说，ENUM值根据他们的编号数字被排序) 例如，对ENUM("a", "b")，"a"排在"b"前面，但是对ENUM("b", "a")，"b"排在"a"前面。空字符串排序非空字符串之前，并且NULL排在所有其他枚举值之前。

如果你想要得到一个ENUM列的所有可能的值，你应该使用：SHOW COLUMNS FROM table_name LIKE enum_column_name并且分析在第二列的ENUM定义。

7.3.7.4 SET类型

一个SET是可以有零或多个值的一个字符串对象，其每一个必须从表创建造被指定了的允许值的一张列表中被选择。由多个集合成员组成的SET列通过由由逗号分隔(“,”)的成员被指定，其推论是该SET成员值不能包含逗号本身。

例如, 一个指定为SET("one", "two") NOT NULL的列可以有这些值的任何一个：

""
"one"
"two"
"one,two"

一个SET能有最多64个不同的成员。

MySQL用数字值存储SET值，存储值的低阶位对应于第一个集合成员。如果你在数字上下文中检索一个SET值，检索的值把位设置位对应组成列值的集合成员。如果一个数字被存储进一个SET列，在数字的二进制表示中设置的位决定了在列中的集合成员。假定一个列被指定为SET("a","b","c","d")，那么成员有下列位值：

SET 成员 | 十进制的值 | 二进制的值
a | 1 | 0001
b | 2 | 0010
c | 4 | 0100
d | 8 | 1000

如果你给该列赋值9，即二进制的1001，这样第一个和第四个SET值成员"a"和"d"被选择并且结果值是"a,d"。

对于包含超过一个SET成员的值，当你插入值时，无所谓以什么顺序列举值，也无所谓给定的值列举了多少次。当以后检索值时，在值中的每个成员将出现一次，根据他们在表创建时被指定的顺序列出成员。例如，如果列指定为SET("a","b","c","d")，那么"a,d"、"d,a"和"d,a,a,d,d"在检索时将均作为"a,d"出现。

SET值以数字次序被排序。NULL指排在非NULL SET值之前。

通常，你使用LIKE操作符或FIND_IN_SET()函数执行在一个SET上的一个SELECT：

mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;

但是下列也会工作：

mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
mysql> SELECT * FROM tbl_name WHERE set_col & 1;

这些语句的第一个语句寻找一个精确的匹配。第二个寻找包含第一个集合成员的值。

如果你想要得到一个SET列的所有可能的值，你应该使用：SHOW COLUMNS FROM table_name LIKE set_column_name并且分析在第二列的SET定义。

7.3.8 为列选择正确的类型

为了最有效地使用存储空间，试着在所有的情况下使用最精确的类型。例如，如果一个整数列被用于在之间1和99999的值， MEDIUMINT UNSIGNED是最好的类型。

货币值的精确表示是一个常见的问题。在MySQL，你应该使用DECIMAL类型，它作为一个字符串被存储，不会发生精确性的损失。如果精确性不是太重要，DOUBLE类型也是足够好的。

对高精度，你总是能变换到以一个BIGINT存储的定点类型。这允许你用整数做所有的计算，并且仅在必要时将结果转换回浮点值。见10.6 选择一个表类型。

7.3.9 列索引

所有的MySQL列类型能被索引。在相关的列上的使用索引是改进SELECT操作性能的最好方法。

一个表最多可有16个索引。最大索引长度是256个字节，尽管这可以在编译MySQL时被改变。

对于CHAR和VARCHAR列，你可以索引列的前缀。这更快并且比索引整个列需要较少的磁盘空间。在CREATE TABLE语句中索引列前缀的语法看起来像这样：

KEY index_name (col_name(length))

下面的例子为name列的头10个字符创建一个索引：

mysql> CREATE TABLE test (
           name CHAR(200) NOT NULL,
           KEY index_name (name(10)));

对于BLOB和TEXT列，你必须索引列的前缀，你不能索引列的全部。

7.3.10 多列索引

MySQL能在多个列上创建索引。一个索引可以由最多15个列组成。（在CHAR和VARCHAR列上，你也可以使用列的前缀作为一个索引的部分)。

一个多重列索引可以认为是包含通过合并(concatenate)索引列值创建的值的一个排序数组。

当你为在一个WHERE子句索引的第一列指定已知的数量时，MySQL以这种方式使用多重列索引使得查询非常快速，即使你不为其他列指定值。

假定一张表使用下列说明创建：

mysql> CREATE TABLE test (
           id INT NOT NULL,
           last_name CHAR(30) NOT NULL,
           first_name CHAR(30) NOT NULL,
           PRIMARY KEY (id),
           INDEX name (last_name,first_name));

那么索引name是一个在last_name和first_name上的索引，这个索引将被用于在last_name或last_name和first_name的一个已知范围内指定值的查询，因此，name索引将使用在下列查询中：

mysql> SELECT * FROM test WHERE last_name="Widenius";

mysql> SELECT * FROM test WHERE last_name="Widenius"
                          AND first_name="Michael";

mysql> SELECT * FROM test WHERE last_name="Widenius"
                          AND (first_name="Michael" OR first_name="Monty");

mysql> SELECT * FROM test WHERE last_name="Widenius"
                          AND first_name >="M" AND first_name < "N";

然而，name索引将不用在下列询问中：

mysql> SELECT * FROM test WHERE first_name="Michael";

mysql> SELECT * FROM test WHERE last_name="Widenius"
                          OR first_name="Michael";

关于MySQL使用索引改进性能的方式的更多的信息，见10.4 使用MySQL索引。

7.3.11 使用来自其他数据库引擎的列类型

为了跟容易地使用为其他供应商的SQL实现编写的代码，下表显示了MySQL映射的列类型。这些映射使得从其他数据库引擎移动表定义到MySQL更容易：

其他供应商类型 | MySQL类型
BINARY(NUM) | CHAR(NUM) BINARY
CHAR VARYING(NUM) | VARCHAR(NUM)
FLOAT4 | FLOAT
FLOAT8 | DOUBLE
INT1 | TINYINT
INT2 | SMALLINT
INT3 | MEDIUMINT
INT4 | INT
INT8 | BIGINT
LONG VARBINARY | MEDIUMBLOB
LONG VARCHAR | MEDIUMTEXT
MIDDLEINT | MEDIUMINT
VARBINARY(NUM) | VARCHAR(NUM) BINARY

列类型映射发生在表创建时。如果你用其他供应商使用的类型创建表，那么发出一个DESCRIBE tbl_name语句，MySQL使用等价的MySQL类型报告表结构。

7.4 用在SELECT和WHERE子句中的函数

在一个SQL语句中的select_expression或where_definition可由使用下面描述的函数的任何表达式组成。

包含NULL的一个表达式总是产生一个NULL值，否则除非表达式所包含的操作符和函数在文档中说明。

注意：在一个函数名和跟随它的括号之间不许没有空格。这帮助MySQL分析器区分函数调用和具有相同名字的对表或列的引用，尽管允许在参数周围有空格。

为了简洁，例子以缩写形式显示从mysql程序输出。因此：

mysql> select MOD(29,9);
1 rows in set (0.00 sec)

+-----------+
| mod(29,9) |
+-----------+
|         2 |
+-----------+

被显示为这样：

mysql> select MOD(29,9);
        -> 2

7.4.1 分组函数

( ... )
括号。使用它们来强制在一个表达式的计算顺序。
mysql> select 1+2*3;
        -> 7
mysql> select (1+2)*3;
        -> 9

7.4.2 常用的算术操作

一般的算术操作符是可用的。注意在-、+和*情况下，如果两个参数是整数，结果用BIGINT（64位）精度计算！

+
加法
mysql> select 3+5;
        -> 8
-
减法
mysql> select 3-5;
        -> -2
*
乘法
mysql> select 3*5;
        -> 15
mysql> select 18014398509481984*18014398509481984.0;
        -> 324518553658426726783156020576256.0
mysql> select 18014398509481984*18014398509481984;
        -> 0

最后一个表达式的结果是不正确的，因为整数乘积的结果超过用BIGINT计算的64位范围。

/
除法
mysql> select 3/5;
        -> 0.60

被零除产生一个NULL结果：

mysql> select 102/(1-1);
        -> NULL

一个除法用BIGINT算术计算，只要在它的结果被转换到一个整数的上下文中执行！

7.4.3 位函数

MySQL为位操作使用BIGINT（64位)算法，因此这些操作符有最大64位的一个范围。

|
位或
mysql> select 29 | 15;
        -> 31
&
位与
mysql> select 29 & 15;
        -> 13
<<
左移位一个长(BIGINT)数字。
mysql> select 1 << 2
        -> 4
>>
右移位一个长(BIGINT)数字。
mysql> select 4 >> 2
        -> 1
~
颠倒所有的位。
mysql> select 5 & ~1
        -> 4
BIT_COUNT(N)
返回在参数N设定的位的数量。
mysql> select BIT_COUNT(29);
        -> 4

7.4.4 逻辑运算

所有的逻辑函数返回1（TRUE）或0（FALSE）。

NOT
!
逻辑非。如果参数是0，返回1，否则返回0。例外： NOT NULL返回NULL。
mysql> select NOT 1;
        -> 0
mysql> select NOT NULL;
        -> NULL
mysql> select ! (1+1);
        -> 0
mysql> select ! 1+1;
        -> 1

最后的例子返回1，因为表达式作为(!1)+1计算。
OR

||
逻辑或。如果任何一个参数不是0并且不NULL，返回1。
mysql> select 1 || 0;
        -> 1
mysql> select 0 || 0;
        -> 0
mysql> select 1 || NULL;
        -> 1
AND

&&
逻辑与。如果任何一个参数是0或NULL，返回0，否则返回1。
mysql> select 1 && NULL;
        -> 0
mysql> select 1 && 0;
        -> 0

7.4.5 比较运算符

比较操作得出值1（TRUE）、0（FALSE）或NULL等结果。这些函数工作运用在数字和字符串上。当需要时，字符串自动地被变换到数字且数字到字符串(如在Perl)。

MySQL使用下列规则执行比较：

  • 如果一个或两个参数是NULL，比较的结果是NULL，除了<=>操作符。
  • 如果在比较中操作的两个参数是字符串，他们作为字符串被比较。
  • 如果两个参数是整数，他们作为整数被比较。
  • 十六进制的值如果不与一个数字比较，则被当作二进制字符串。
  • 如果参数之一是一个TIMESTAMP或DATETIME列而其他参数是一个常数，在比较执行前，常数被转换为一个时间标记。这样做是为了对ODBC更友好。
  • 在所有其他的情况下，参数作为浮点(实数)数字被比较。

缺省地，字符串使用当前的字符集以大小写敏感的方式进行(缺省为ISO-8859-1 Latin1，它对英语运用得很出色)。

下面的例子演示了对于比较操作字符串到数字的转换：

mysql> SELECT 1 > '6x';
         -> 0
mysql> SELECT 7 > '6x';
         -> 1
mysql> SELECT 0 > 'x6';
         -> 0
mysql> SELECT 0 = 'x6';
         -> 1
=
等于
mysql> select 1 = 0;
        -> 0
mysql> select '0' = 0;
        -> 1
mysql> select '0.0' = 0;
        -> 1
mysql> select '0.01' = 0;
        -> 0
mysql> select '.01' = 0.01;
        -> 1
<>

!=
不等于
mysql> select '.01' <> '0.01';
        -> 1
mysql> select .01 <> '0.01';
        -> 0
mysql> select 'zapp' <> 'zappp';
        -> 1
<=
小于或等于
mysql> select 0.1 <= 2;
        -> 1
<
小于
mysql> select 2 <= 2;
        -> 1
>=
大于或等于
mysql> select 2 >= 2;
        -> 1
>
大于
mysql> select 2 > 2;
        -> 0
<=>
安全等于Null
mysql> select 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
        -> 1 1 0
IS NULL

IS NOT NULL
测试值是否是或不是NULL
mysql> select 1 IS NULL, 0 IS NULL, NULL IS NULL:
        -> 0 0 1
mysql> select 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;
expr BETWEEN min AND max
如果expr对大于或等于min且expr是小于或等于max，BETWEEN返回1，否则它返回0。如果所有的参数类型是一样得，这等价于表达式(min <= expr AND expr <= max)。第一个参数(expr)决定比较如何被执行。如果expr是一个大小写不敏感的字符串表达式，进行一个大小写不敏感的字符串比较。如果expr是一个大小写敏感的字符串表达式，进行一个大小写敏感的字符串比较。如果expr是一个整数表达式，进行整数比较。否则，进行一个浮点(实数)比较。
mysql> select 1 BETWEEN 2 AND 3;
        -> 0
mysql> select 'b' BETWEEN 'a' AND 'c';
        -> 1
mysql> select 2 BETWEEN 2 AND '3';
        -> 1
mysql> select 2 BETWEEN 2 AND 'x-3';
        -> 0
expr IN (value,...)
如果expr是在IN表中的任何值，返回1，否则返回0。如果所有的值是常数，那么所有的值根据expr类型被计算和排序，然后项目的搜索是用二进制的搜索完成。这意味着如果IN值表全部由常数组成，IN是很快的。如果expr是一个大小写敏感的字符串表达式，字符串比较以大小写敏感方式执行。
mysql> select 2 IN (0,3,5,'wefwf');
        -> 0
mysql> select 'wefwf' IN (0,3,5,'wefwf');
        -> 1
expr NOT IN (value,...)
与NOT (expr IN (value,...))相同。
ISNULL(expr)
如果expr是NULL，ISNULL()返回1，否则它返回0。
mysql> select ISNULL(1+1);
        -> 0
mysql> select ISNULL(1/0);
        -> 1

注意，使用=的NULL的值比较总为假！

COALESCE(list)
回来list中第一个非NULL的单元。
mysql> select COALESCE(NULL,1);
        -> 1
mysql> select COALESCE(NULL,NULL,NULL);
        -> NULL
INTERVAL(N,N1,N2,N3,...)
如果N< N1，返回0，如果N< N2，返回1等等。所有的参数被当作整数。为了函数能正确地工作，它要求N1<N2<N3< ...<Nn。这是因为使用二进制搜索(很快)。
mysql> select INTERVAL(23, 1, 15, 17, 30, 44, 200);
        -> 3
mysql> select INTERVAL(10, 1, 10, 100, 1000);
        -> 2
mysql> select INTERVAL(22, 23, 30, 44, 200);
        -> 0

7.4.6 字符串比较函数

通常，如果在字符串比较中的任何表达式是区分大小写的，比较以大小写敏感的方式执行。

expr LIKE pat [ESCAPE 'escape-char']
使用SQL的简单的正规表达式比较的模式匹配。返回1（TRUE）或0（FALSE）。用LIKE，你可以在模式中使用下列2个通配符字符：
% 匹配任何数目的字符，甚至零个字符
_ 精确匹配一个字符
mysql> select 'David!' LIKE 'David_';
        -> 1
mysql> select 'David!' LIKE '%D%v%';
        -> 1

为了测试一个通配符的文字实例，用转义字符的加在字符前面。如果你不指定ESCAPE字符，假定为“\”：

\% 匹配一%字符
\_ 匹配一_字符
mysql> select 'David!' LIKE 'David\_';
        -> 0
mysql> select 'David_' LIKE 'David\_';
        -> 1

为了指定一个不同的转义字符，使用ESCAPE子句：
mysql> select 'David_' LIKE 'David|_' ESCAPE '|';
        -> 1

LIKE允许用在数字的表达式上！（这是MySQL对ANSI SQL LIKE的一个扩充。)

mysql> select 10 LIKE '1%';
        -> 1

注意：因为MySQL在字符串中使用C转义语法(例如，“\n”)，你必须在你的LIKE字符串中重复任何“\”。例如，为了查找“\n”，指定它为“ \\n”，为了查找“\”，指定它为“\\\\”（反斜线被分析器剥去一次，另一次是在模式匹配完成时，留下一条单独的反斜线被匹配)。

expr NOT LIKE pat [ESCAPE 'escape-char']
与NOT (expr LIKE pat [ESCAPE 'escape-char'])相同。
expr REGEXP pat

expr RLIKE pat
执行一个字符串表达式expr对一个模式pat的模式匹配。模式可以是一个扩充的正则表达式。见MySQL 正则表达式句法的 H 描述.如果expr匹配pat，返回1，否则返回0。RLIKE是REGEXP的一个同义词，提供了与mSQL的兼容性。注意：因为MySQL在字符串中使用C转义语法(例如，“\n”), 你必须在你的REGEXP字符串重复任何“\”。在MySQL3.23.4中，REGEXP对于正常的(不是二进制)字符串是忽略大小写。
mysql> select 'Monty!' REGEXP 'm%y%%';
        -> 0
mysql> select 'Monty!' REGEXP '.*';
        -> 1
mysql> select 'new*\n*line' REGEXP 'new\\*.\\*line';
        -> 1
mysql> select "a" REGEXP "A", "a" REGEXP BINARY "A";
        -> 1  0
当决定一个字符的类型时，REGEXP和RLIKE使用当前的字符集(缺省为ISO-8859-1 Latin1)。
expr NOT REGEXP pat

expr NOT RLIKE pat
与NOT (expr REGEXP pat)相同。
STRCMP(expr1,expr2)
如果字符串相同，STRCMP()回来0，如果第一参数根据当前的排序次序小于第二个，返回-1，否则返回1。
mysql> select STRCMP('text', 'text2');
        -> -1
mysql> select STRCMP('text2', 'text');
        -> 1
mysql> select STRCMP('text', 'text');
        -> 0

7.4.7 类型转换运算符

BINARY
BINARY操作符强制跟随它后面的字符串为一个二进制字符串。即使列没被定义为BINARY或BLOB，这是一个强制列比较区分大小写的简易方法。
mysql> select "a" = "A";
        -> 1
mysql> select BINARY "a" = "A";
        -> 0

BINARY在MySQL 3.23.0中被引入。

7.4.8 控制流函数

IFNULL(expr1,expr2)
如果expr1不是NULL，IFNULL()返回expr1，否则它返回expr2。IFNULL()返回一个数字或字符串值，取决于它被使用的上下文环境。
mysql> select IFNULL(1,0);
        -> 1
mysql> select IFNULL(0,10);
        -> 0
mysql> select IFNULL(1/0,10);
        -> 10
mysql> select IFNULL(1/0,'yes');
        -> 'yes'
IF(expr1,expr2,expr3)
如果expr1是TRUE(expr1<>0且expr1<>NULL)，那么IF()返回expr2，否则它返回expr3。IF()返回一个数字或字符串值，取决于它被使用的上下文。
mysql> select IF(1>2,2,3);
        -> 3
mysql> select IF(1<2,'yes','no');
        -> 'yes'
mysql> select IF(strcmp('test','test1'),'yes','no');
        -> 'no'

expr1作为整数值被计算，它意味着如果你正在测试浮点或字符串值，你应该使用一个比较操作来做。

mysql> select IF(0.1,1,0);
        -> 0
mysql> select IF(0.1<>0,1,0);
        -> 1

在上面的第一种情况中，IF(0.1)返回0，因为0.1被变换到整数值, 导致测试IF(0)。这可能不是你期望的。在第二种情况中，比较测试原来的浮点值看它是否是非零，比较的结果被用作一个整数。

CASE value WHEN [compare-value] THEN result [WHEN [compare-value] THEN result ...] [ELSE result] END

CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END
第一个版本返回result，其中value=compare-value。第二个版本中如果第一个条件为真，返回result。如果没有匹配的result值，那么结果在ELSE后的result被返回。如果没有ELSE部分，那么NULL被返回。
mysql> SELECT CASE 1 WHEN 1 THEN "one" WHEN 2 THEN "two" ELSE "more" END;
       -> "one"
mysql> SELECT CASE WHEN 1>0 THEN "true" ELSE "false" END;
       -> "true"
mysql> SELECT CASE BINARY "B" when "a" then 1 when "b" then 2 END;
       -> NULL

7.4.9 数学函数

所有的数学函数在一个出错的情况下返回NULL。

-
单目减。改变参数的符号。
mysql> select - 2;

注意，如果这个操作符与一个BIGINT使用，返回值是一个BIGINT！这意味着你应该避免在整数上使用-，那可能有值-2^63！
ABS(X)
返回X的绝对值。
mysql> select ABS(2);
        -> 2
mysql> select ABS(-32);
        -> 32

该功能可安全用于BIGINT值。

SIGN(X)
返回参数的符号，为-1、0或1，取决于X是否是负数、零或正数。
mysql> select SIGN(-32);
        -> -1
mysql> select SIGN(0);
        -> 0
mysql> select SIGN(234);
        -> 1
MOD(N,M)

%
模 (类似C中的%操作符)。返回N被M除的余数。
mysql> select MOD(234, 10);
        -> 4
mysql> select 253 % 7;
        -> 1
mysql> select MOD(29,9);
        -> 2

这个函数可安全用于BIGINT值。
FLOOR(X)
返回不大于X的最大整数值。

mysql> select FLOOR(1.23);
        -> 1
mysql> select FLOOR(-1.23);
        -> -2

注意返回值被变换为一个BIGINT！

CEILING(X)

返回不小于X的最小整数值。
mysql> select CEILING(1.23);
        -> 2
mysql> select CEILING(-1.23);
        -> -1

注意返回值被变换为一个BIGINT！

ROUND(X)

返回参数X的四舍五入的一个整数。
mysql> select ROUND(-1.23);
        -> -1
mysql> select ROUND(-1.58);
        -> -2
mysql> select ROUND(1.58);
        -> 2

注意返回值被变换为一个BIGINT!

ROUND(X,D)

返回参数X的四舍五入的有D为小数的一个数字。如果D为0，结果将没有小数点或小数部分。

mysql> select ROUND(1.298, 1);
        -> 1.3
mysql> select ROUND(1.298, 0);
        -> 1

注意返回值被变换为一个BIGINT!

EXP(X)

返回值e（自然对数的底）的X次方。
mysql> select EXP(2);
        -> 7.389056
mysql> select EXP(-2);
        -> 0.135335

LOG(X)

返回X的自然对数。
mysql> select LOG(2);
        -> 0.693147
mysql> select LOG(-2);
        -> NULL

如果你想要一个数字X的任意底B的对数，使用公式LOG(X)/LOG(B)。

LOG10(X)

返回X的以10为底的对数。
mysql> select LOG10(2);
        -> 0.301030
mysql> select LOG10(100);
        -> 2.000000
mysql> select LOG10(-100);
        -> NULL

POW(X,Y)

POWER(X,Y)

返回值X的Y次幂。
mysql> select POW(2,2);
        -> 4.000000
mysql> select POW(2,-2);
        -> 0.250000

SQRT(X)

返回非负数X的平方根。
mysql> select SQRT(4);
        -> 2.000000
mysql> select SQRT(20);
        -> 4.472136

PI()

返回PI的值（圆周率）。
mysql> select PI();
        -> 3.141593

COS(X)

返回X的余弦, 在这里X以弧度给出。
mysql> select COS(PI());
        -> -1.000000

SIN(X)

返回X的正弦值，在此X以弧度给出。
mysql> select SIN(PI());
        -> 0.000000

TAN(X)

返回X的正切值，在此X以弧度给出。
mysql> select TAN(PI()+1);
        -> 1.557408

ACOS(X)

返回X反余弦，即其余弦值是X。如果X不在-1到1的范围，返回NULL。

mysql> select ACOS(1);
        -> 0.000000
mysql> select ACOS(1.0001);
        -> NULL
mysql> select ACOS(0);
        -> 1.570796

ASIN(X)

返回X反正弦值，即其正弦值是X。L如果X不在-1到1的范围，返回NULL。

mysql> select ASIN(0.2);
        -> 0.201358
mysql> select ASIN('foo');
        -> 0.000000

ATAN(X)

返回X的反正切值，即其正切值是X。
mysql> select ATAN(2);
        -> 1.107149
mysql> select ATAN(-2);
        -> -1.107149

ATAN2(X,Y)

返回2个变量X和Y的反正切。它类似于计算Y/X的反正切，除了两个参数的符号被用来决定结果的象限。

mysql> select ATAN(-2,2);
        -> -0.785398
mysql> select ATAN(PI(),0);
        -> 1.570796

COT(X)

返回X的余切。
mysql> select COT(12);
        -> -1.57267341
mysql> select COT(0);
        -> NULL

RAND()

RAND(N)

返回在范围0到1.0内的随机浮点值。如果一个整数参数N被指定，它被用作种子值。

mysql> select RAND();
        -> 0.5925
mysql> select RAND(20);
        -> 0.1811
mysql> select RAND(20);
        -> 0.1811
mysql> select RAND();
        -> 0.2079
mysql> select RAND();
        -> 0.7888

你不能在一个ORDER BY子句用RAND()值使用列，因为ORDER
    BY将重复计算列多次。然而在MySQL3.23中，你可以做：
    SELECT * FROM table_name ORDER BY RAND()，这是有利于得到一个来自SELECT
    * FROM table1,table2 WHERE a=b AND c<d ORDER BY RAND() LIMIT 1000的集合的随机样本。注意在一个WHERE子句里的一个RAND()将在每次WHERE被执行时重新评估。

LEAST(X,Y,...)

有2和2个以上的参数，返回最小(最小值)的参数。参数使用下列规则进行比较：

  • 如果返回值被使用在一个INTEGER上下文，或所有的参数都是整数值，他们作为整数比较。

    •

  • 如果返回值被使用在一个REAL上下文，或所有的参数是实数值，他们作为实数比较。

    •

  • 如果任何参数是一个大小敏感的字符串，参数作为大小写敏感的字符串被比较。

    •

  • 在其他的情况下，参数作为大小写无关的字符串被比较。
    •

mysql> select LEAST(2,0);
        -> 0
mysql> select LEAST(34.0,3.0,5.0,767.0);
        -> 3.0
mysql> select LEAST("B","A","C");
        -> "A"

在MySQL 3.22.5以前的版本，你可以使用MIN()而不是LEAST。

GREATEST(X,Y,...)

返回最大(最大值)的参数。参数使用与LEAST一样的规则进行比较。

mysql> select GREATEST(2,0);
        -> 2
mysql> select GREATEST(34.0,3.0,5.0,767.0);
        -> 767.0
mysql> select GREATEST("B","A","C");
        -> "C"

在MySQL在 3.22.5 以前的版本, 你能使用MAX()而不是GREATEST.

DEGREES(X)

返回参数X，从弧度变换为角度。
mysql> select DEGREES(PI());
        -> 180.000000

RADIANS(X)

返回参数X，从角度变换为弧度。
mysql> select RADIANS(90);
        -> 1.570796

TRUNCATE(X,D)

返回数字X，截断为D位小数。如果D为0，结果将没有小数点或小数部分。

mysql> select TRUNCATE(1.223,1);
        -> 1.2
mysql> select TRUNCATE(1.999,1);
        -> 1.9
mysql> select TRUNCATE(1.999,0);
        -> 1

7.4.10
字符串函数

如果结果的长度大于服务器参数max_allowed_packet，字符串值函数返回NULL。见10.2.3 调节服务器参数。

对于针对字符串位置的操作，第一个位置被标记为1。

ASCII(str)

返回字符串str的最左面字符的ASCII代码值。如果str是空字符串，返回0。如果str是NULL，返回NULL。

mysql> select ASCII('2');
        -> 50
mysql> select ASCII(2);
        -> 50
mysql> select ASCII('dx');
        -> 100

也可参见ORD()函数。

ORD(str)

如果字符串str最左面字符是一个多字节字符，通过以格式((first
    byte ASCII code)*256+(second byte ASCII code))[*256+third byte ASCII code...]返回字符的ASCII代码值来返回多字节字符代码。如果最左面的字符不是一个多字节字符。返回与ASCII()函数返回的相同值。
mysql> select ORD('2');
        -> 50

CONV(N,from_base,to_base)

在不同的数字基之间变换数字。返回数字N的字符串数字，从from_base基变换为to_base基，如果任何参数是NULL，返回NULL。参数N解释为一个整数，但是可以指定为一个整数或一个字符串。最小基是2且最大的基是36。如果to_base是一个负数，N被认为是一个有符号数，否则，N被当作无符号数。
    CONV以64位点精度工作。
mysql> select CONV("a",16,2);
        -> '1010'
mysql> select CONV("6E",18,8);
        -> '172'
mysql> select CONV(-17,10,-18);
        -> '-H'
mysql> select CONV(10+"10"+'10'+0xa,10,10);
        -> '40'

BIN(N)

返回二进制值N的一个字符串表示，在此N是一个长整数(BIGINT)数字，这等价于CONV(N,10,2)。如果N是NULL，返回NULL。

mysql> select BIN(12);
        -> '1100'

OCT(N)

返回八进制值N的一个字符串的表示，在此N是一个长整型数字，这等价于CONV(N,10,8)。如果N是NULL，返回NULL。

mysql> select OCT(12);
        -> '14'

HEX(N)

返回十六进制值N一个字符串的表示，在此N是一个长整型(BIGINT)数字，这等价于CONV(N,10,16)。如果N是NULL，返回NULL。

mysql> select HEX(255);
        -> 'FF'

CHAR(N,...)

CHAR()将参数解释为整数并且返回由这些整数的ASCII代码字符组成的一个字符串。NULL值被跳过。

mysql> select CHAR(77,121,83,81,'76');
        -> 'MySQL'
mysql> select CHAR(77,77.3,'77.3');
        -> 'MMM'

CONCAT(str1,str2,...)

返回来自于参数连结的字符串。如果任何参数是NULL，返回NULL。可以有超过2个的参数。一个数字参数被变换为等价的字符串形式。

mysql> select CONCAT('My', 'S', 'QL');
        -> 'MySQL'
mysql> select CONCAT('My', NULL, 'QL');
        -> NULL
mysql> select CONCAT(14.3);
        -> '14.3'

LENGTH(str)

OCTET_LENGTH(str)

CHAR_LENGTH(str)

CHARACTER_LENGTH(str)

返回字符串str的长度。
mysql> select LENGTH('text');
        -> 4
mysql> select OCTET_LENGTH('text');
        -> 4

注意，对于多字节字符，其CHAR_LENGTH()仅计算一次。

LOCATE(substr,str)

POSITION(substr IN str)

返回子串substr在字符串str第一个出现的位置，如果substr不是在str里面，返回0.

mysql> select LOCATE('bar', 'foobarbar');
        -> 4
mysql> select LOCATE('xbar', 'foobar');
        -> 0

该函数是多字节可靠的。

LOCATE(substr,str,pos)

返回子串substr在字符串str第一个出现的位置，从位置pos开始。如果substr不是在str里面，返回0。
mysql> select LOCATE('bar', 'foobarbar',5);
        -> 7

这函数是多字节可靠的。

INSTR(str,substr)

返回子串substr在字符串str中的第一个出现的位置。这与有2个参数形式的LOCATE()相同，除了参数被颠倒。

mysql> select INSTR('foobarbar', 'bar');
        -> 4
mysql> select INSTR('xbar', 'foobar');
        -> 0

这函数是多字节可靠的。

LPAD(str,len,padstr)

返回字符串str，左面用字符串padstr填补直到str是len个字符长。

mysql> select LPAD('hi',4,'??');
        -> '??hi'

RPAD(str,len,padstr)

返回字符串str，右面用字符串padstr填补直到str是len个字符长。

mysql> select RPAD('hi',5,'?');
        -> 'hi???'

LEFT(str,len)

返回字符串str的最左面len个字符。
mysql> select LEFT('foobarbar', 5);
        -> 'fooba'

该函数是多字节可靠的。

RIGHT(str,len)

返回字符串str的最右面len个字符。
mysql> select RIGHT('foobarbar', 4);
        -> 'rbar'

该函数是多字节可靠的。

SUBSTRING(str,pos,len)

SUBSTRING(str FROM pos FOR len)

MID(str,pos,len)

从字符串str返回一个len个字符的子串，从位置pos开始。使用FROM的变种形式是ANSI
    SQL92语法。
mysql> select SUBSTRING('Quadratically',5,6);
        -> 'ratica'

该函数是多字节可靠的。

SUBSTRING(str,pos)

SUBSTRING(str FROM pos)

从字符串str的起始位置pos返回一个子串。
mysql> select SUBSTRING('Quadratically',5);
        -> 'ratically'
mysql> select SUBSTRING('foobarbar' FROM 4);
        -> 'barbar'

该函数是多字节可靠的。

SUBSTRING_INDEX(str,delim,count)

返回从字符串str的第count个出现的分隔符delim之后的子串。如果count是正数，返回最后的分隔符到左边(从左边数)
    的所有字符。如果count是负数，返回最后的分隔符到右边的所有字符(从右边数)。

mysql> select SUBSTRING_INDEX('www.mysql.com', '.', 2);
        -> 'www.mysql'
mysql> select SUBSTRING_INDEX('www.mysql.com', '.', -2);
        -> 'mysql.com'

该函数对多字节是可靠的。

LTRIM(str)

返回删除了其前置空格字符的字符串str。
mysql> select LTRIM('  barbar');
        -> 'barbar'

RTRIM(str)

返回删除了其拖后空格字符的字符串str。
mysql> select RTRIM('barbar   ');
        -> 'barbar'

该函数对多字节是可靠的。

TRIM([[BOTH | LEADING | TRAILING] [remstr] FROM] str)

返回字符串str，其所有remstr前缀或后缀被删除了。如果没有修饰符BOTH、LEADING或TRAILING给出，BOTH被假定。如果remstr没被指定，空格被删除。

mysql> select TRIM('  bar   ');
        -> 'bar'
mysql> select TRIM(LEADING 'x' FROM 'xxxbarxxx');
        -> 'barxxx'
mysql> select TRIM(BOTH 'x' FROM 'xxxbarxxx');
        -> 'bar'
mysql> select TRIM(TRAILING 'xyz' FROM 'barxxyz');
        -> 'barx'

该函数对多字节是可靠的。

SOUNDEX(str)

返回str的一个同音字符串。听起来“大致相同”的2个字符串应该有相同的同音字符串。一个“标准”的同音字符串长是4个字符，但是SOUNDEX()函数返回一个任意长的字符串。你可以在结果上使用SUBSTRING()得到一个“标准”的
    同音串。所有非数字字母字符在给定的字符串中被忽略。所有在A-Z之外的字符国际字母被当作元音。

mysql> select SOUNDEX('Hello');
        -> 'H400'
mysql> select SOUNDEX('Quadratically');
        -> 'Q36324'

SPACE(N)

返回由N个空格字符组成的一个字符串。
mysql> select SPACE(6);
        -> '      '

REPLACE(str,from_str,to_str)

返回字符串str，其字符串from_str的所有出现由字符串to_str代替。

mysql> select REPLACE('www.mysql.com', 'w', 'Ww');
        -> 'WwWwWw.mysql.com'

该函数对多字节是可靠的。

REPEAT(str,count)

返回由重复countTimes次的字符串str组成的一个字符串。如果count
    <= 0，返回一个空字符串。如果str或count是NULL，返回NULL。

mysql> select REPEAT('MySQL', 3);
        -> 'MySQLMySQLMySQL'

REVERSE(str)

返回颠倒字符顺序的字符串str。
mysql> select REVERSE('abc');
        -> 'cba'

该函数对多字节可靠的。

INSERT(str,pos,len,newstr)

返回字符串str，在位置pos起始的子串且len个字符长得子串由字符串newstr代替。

mysql> select INSERT('Quadratic', 3, 4, 'What');
        -> 'QuWhattic'

该函数对多字节是可靠的。

ELT(N,str1,str2,str3,...)

如果N= 1，返回str1，如果N= 2，返回str2，等等。如果N小于1或大于参数个数，返回NULL。ELT()是FIELD()反运算。

mysql> select ELT(1, 'ej', 'Heja', 'hej', 'foo');
        -> 'ej'
mysql> select ELT(4, 'ej', 'Heja', 'hej', 'foo');
        -> 'foo'

FIELD(str,str1,str2,str3,...)

返回str在str1, str2, str3, ...清单的索引。如果str没找到，返回0。FIELD()是ELT()反运算。

mysql> select FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');
        -> 2
mysql> select FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo');
        -> 0

FIND_IN_SET(str,strlist)

如果字符串str在由N子串组成的表strlist之中，返回一个1到N的值。一个字符串表是被“,”分隔的子串组成的一个字符串。如果第一个参数是一个常数字符串并且第二个参数是一种类型为SET的列，FIND_IN_SET()函数被优化而使用位运算！如果str不是在strlist里面或如果strlist是空字符串，返回0。如果任何一个参数是NULL，返回NULL。如果第一个参数包含一个“,”，该函数将工作不正常。

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
        -> 2

MAKE_SET(bits,str1,str2,...)

返回一个集合 (包含由“,”字符分隔的子串组成的一个字符串)，由相应的位在bits集合中的的字符串组成。str1对应于位0，str2对应位1，等等。在str1,
    str2, ...中的NULL串不添加到结果中。
mysql> SELECT MAKE_SET(1,'a','b','c');
        -> 'a'
mysql> SELECT MAKE_SET(1 | 4,'hello','nice','world');
        -> 'hello,world'
mysql> SELECT MAKE_SET(0,'a','b','c');
        -> ''

EXPORT_SET(bits,on,off,[separator,[number_of_bits]])

返回一个字符串，在这里对于在“bits”中设定每一位，你得到一个“on”字符串，并且对于每个复位(reset)的位，你得到一个“off”字符串。每个字符串用“separator”分隔(缺省“,”)，并且只有“bits”的“number_of_bits”
    (缺省64)位被使用。
mysql> select EXPORT_SET(5,'Y','N',',',4)
        -> Y,N,Y,N

LCASE(str)

LOWER(str)

返回字符串str，根据当前字符集映射(缺省是ISO-8859-1
    Latin1)把所有的字符改变成小写。该函数对多字节是可靠的。
mysql> select LCASE('QUADRATICALLY');
        -> 'quadratically'

UCASE(str)

UPPER(str)

返回字符串str，根据当前字符集映射(缺省是ISO-8859-1
    Latin1)把所有的字符改变成大写。该函数对多字节是可靠的。
mysql> select UCASE('Hej');
        -> 'HEJ'

该函数对多字节是可靠的。

LOAD_FILE(file_name)

读入文件并且作为一个字符串返回文件内容。文件必须在服务器上，你必须指定到文件的完整路径名，而且你必须有file权限。文件必须所有内容都是可读的并且小于max_allowed_packet。如果文件不存在或由于上面原因之一不能被读出，函数返回NULL。

mysql> UPDATE table_name
           SET blob_column=LOAD_FILE("/tmp/picture")
           WHERE id=1;

MySQL必要时自动变换数字为字符串，并且反过来也如此：

mysql> SELECT 1+"1";
        -> 2
mysql> SELECT CONCAT(2,' test');
        -> '2 test'

如果你想要明确地变换一个数字到一个字符串，把它作为参数传递到CONCAT()。

如果字符串函数提供一个二进制字符串作为参数，结果字符串也是一个二进制字符串。被变换到一个字符串的数字被当作是一个二进制字符串。这仅影响比较。

7.4.11
日期和时间函数

对于每个类型拥有的值范围以及并且指定日期何时间值的有效格式的描述见7.3.6 日期和时间类型。

这里是一个使用日期函数的例子。下面的查询选择了所有记录，其date_col的值是在最后30天以内：

mysql> SELECT something FROM table
           WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) <= 30;

DAYOFWEEK(date)

返回日期date的星期索引(1=星期天，2=星期一,
    ……7=星期六)。这些索引值对应于ODBC标准。
mysql> select DAYOFWEEK('1998-02-03');
        -> 3

WEEKDAY(date)

返回date的星期索引(0=星期一，1=星期二,
    ……6= 星期天)。
mysql> select WEEKDAY('1997-10-04 22:23:00');
        -> 5
mysql> select WEEKDAY('1997-11-05');
        -> 2

DAYOFMONTH(date)

返回date的月份中日期，在1到31范围内。

mysql> select DAYOFMONTH('1998-02-03');
        -> 3

DAYOFYEAR(date)

返回date在一年中的日数, 在1到366范围内。

mysql> select DAYOFYEAR('1998-02-03');
        -> 34

MONTH(date)

返回date的月份，范围1到12。
mysql> select MONTH('1998-02-03');
        -> 2

DAYNAME(date)

返回date的星期名字。
mysql> select DAYNAME("1998-02-05");
        -> 'Thursday'

MONTHNAME(date)

返回date的月份名字。
mysql> select MONTHNAME("1998-02-05");
        -> 'February'

QUARTER(date)

返回date一年中的季度，范围1到4。
mysql> select QUARTER('98-04-01');
        -> 2

WEEK(date)

WEEK(date,first)

对于星期天是一周的第一天的地方，有一个单个参数，返回date的周数，范围在0到52。2个参数形式WEEK()允许你指定星期是否开始于星期天或星期一。如果第二个参数是0，星期从星期天开始，如果第二个参数是1，从星期一开始。

mysql> select WEEK('1998-02-20');
        -> 7
mysql> select WEEK('1998-02-20',0);
        -> 7
mysql> select WEEK('1998-02-20',1);
        -> 8

YEAR(date)

返回date的年份，范围在1000到9999。
mysql> select YEAR('98-02-03');
        -> 1998

HOUR(time)

返回time的小时，范围是0到23。
mysql> select HOUR('10:05:03');
        -> 10

MINUTE(time)

返回time的分钟，范围是0到59。
mysql> select MINUTE('98-02-03 10:05:03');
        -> 5

SECOND(time)

回来time的秒数，范围是0到59。
mysql> select SECOND('10:05:03');
        -> 3

PERIOD_ADD(P,N)

增加N个月到阶段P（以格式YYMM或YYYYMM)。以格式YYYYMM返回值。注意阶段参数P 不是日期值。

mysql> select PERIOD_ADD(9801,2);
        -> 199803

PERIOD_DIFF(P1,P2)

返回在时期P1和P2之间月数，P1和P2应该以格式YYMM或YYYYMM。注意，时期参数P1和P2 不是日期值。

mysql> select PERIOD_DIFF(9802,199703);
        -> 11

DATE_ADD(date,INTERVAL expr type)

DATE_SUB(date,INTERVAL expr type)

ADDDATE(date,INTERVAL expr type)

SUBDATE(date,INTERVAL expr type)

这些功能执行日期运算。对于MySQL 3.22，他们是新的。ADDDATE()和SUBDATE()是DATE_ADD()和DATE_SUB()的同义词。在MySQL
    3.23中，你可以使用+和-而不是DATE_ADD()和DATE_SUB()。（见例子）date是一个指定开始日期的DATETIME或DATE值，expr是指定加到开始日期或从开始日期减去的间隔值一个表达式，expr是一个字符串；它可以以一个“-”开始表示负间隔。type是一个关键词，指明表达式应该如何被解释。EXTRACT(type
    FROM date)函数从日期中返回“type”间隔。下表显示了type和expr参数怎样被关联：

        type 值
         | 含义
         | 期望的 expr 格式

        SECOND
         | 秒
         | SECONDS

        MINUTE
         | 分钟
         | MINUTES

        HOUR
         | 时间
         | HOURS

        DAY
         | 天
         | DAYS

        MONTH
         | 月
         | MONTHS

        YEAR
         | 年
         | YEARS

        MINUTE_SECOND
         | 分钟和秒
         | "MINUTES:SECONDS"

        HOUR_MINUTE
         | 小时和分钟
         | "HOURS:MINUTES"

        DAY_HOUR
         | 天和小时
         | "DAYS HOURS"

        YEAR_MONTH
         | 年和月
         | "YEARS-MONTHS"

        HOUR_SECOND
         | 小时, 分钟，
         | "HOURS:MINUTES:SECONDS"

        DAY_MINUTE
         | 天, 小时, 分钟
         | "DAYS HOURS:MINUTES"

        DAY_SECOND
         | 天, 小时, 分钟, 秒
         | "DAYS HOURS:MINUTES:SECONDS"

MySQL在expr格式中允许任何标点分隔符。表示显示的是建议的分隔符。如果date参数是一个DATE值并且你的计算仅仅包含YEAR、MONTH和DAY部分(即，没有时间部分)，结果是一个DATE值。否则结果是一个DATETIME值。

mysql> SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
        -> 1998-01-01 00:00:00
mysql> SELECT INTERVAL 1 DAY + "1997-12-31";
        -> 1998-01-01
mysql> SELECT "1998-01-01" - INTERVAL 1 SECOND;
       -> 1997-12-31 23:59:59
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
                       INTERVAL 1 SECOND);
        -> 1998-01-01 00:00:00
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
                       INTERVAL 1 DAY);
        -> 1998-01-01 23:59:59
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
                       INTERVAL "1:1" MINUTE_SECOND);
        -> 1998-01-01 00:01:00
mysql> SELECT DATE_SUB("1998-01-01 00:00:00",
                       INTERVAL "1 1:1:1" DAY_SECOND);
        -> 1997-12-30 22:58:59
mysql> SELECT DATE_ADD("1998-01-01 00:00:00",
                       INTERVAL "-1 10" DAY_HOUR);
        -> 1997-12-30 14:00:00
mysql> SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);
        -> 1997-12-02
mysql> SELECT EXTRACT(YEAR FROM "1999-07-02");
       -> 1999
mysql> SELECT EXTRACT(YEAR_MONTH FROM "1999-07-02 01:02:03");
       -> 199907
mysql> SELECT EXTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03");
       -> 20102

如果你指定太短的间隔值(不包括type关键词期望的间隔部分)，MySQL假设你省掉了间隔值的最左面部分。例如，如果你指定一个type是DAY_SECOND，值expr被希望有天、小时、分钟和秒部分。如果你象"1:10"这样指定值，MySQL假设日子和小时部分是丢失的并且值代表分钟和秒。换句话说，"1:10"
    DAY_SECOND以它等价于"1:10" MINUTE_SECOND的方式解释，这对那MySQL解释TIME值表示经过的时间而非作为一天的时间的方式有二义性。如果你使用确实不正确的日期，结果是NULL。如果你增加MONTH、YEAR_MONTH或YEAR并且结果日期大于新月份的最大值天数，日子在新月用最大的天调整。

mysql> select DATE_ADD('1998-01-30', Interval 1 month);
        -> 1998-02-28

注意，从前面的例子中词INTERVAL和type关键词不是区分大小写的。

TO_DAYS(date)

给出一个日期date，返回一个天数(从0年的天数)。
mysql> select TO_DAYS(950501);
        -> 728779
mysql> select TO_DAYS('1997-10-07');
        -> 729669

TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。

FROM_DAYS(N)

给出一个天数N，返回一个DATE值。
mysql> select FROM_DAYS(729669);
        -> '1997-10-07'

TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。

DATE_FORMAT(date,format)

根据format字符串格式化date值。下列修饰符可以被用在format字符串中：

        %M
         | 月名字(January……December)

        %W
         | 星期名字(Sunday……Saturday)

        %D
         | 有英语前缀的月份的日期(1st, 2nd, 3rd,
        等等。）

        %Y
         | 年, 数字, 4 位

        %y
         | 年, 数字, 2 位

        %a
         | 缩写的星期名字(Sun……Sat)

        %d
         | 月份中的天数, 数字(00……31)

        %e
         | 月份中的天数, 数字(0……31)

        %m
         | 月, 数字(01……12)

        %c
         | 月, 数字(1……12)

        %b
         | 缩写的月份名字(Jan……Dec)

        %j
         | 一年中的天数(001……366)

        %H
         | 小时(00……23)

        %k
         | 小时(0……23)

        %h
         | 小时(01……12)

        %I
         | 小时(01……12)

        %l
         | 小时(1……12)

        %i
         | 分钟, 数字(00……59)

        %r
         | 时间,12 小时(hh:mm:ss [AP]M)

        %T
         | 时间,24 小时(hh:mm:ss)

        %S
         | 秒(00……59)

        %s
         | 秒(00……59)

        %p
         | AM或PM

        %w
         | 一个星期中的天数(0=Sunday ……6=Saturday ）

        %U
         | 星期(0……52), 这里星期天是星期的第一天

        %u
         | 星期(0……52), 这里星期一是星期的第一天

        %%
        一个文字“%”。

所有的其他字符不做解释被复制到结果中。

mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
        -> 'Saturday October 1997'
mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
        -> '22:23:00'
mysql> select DATE_FORMAT('1997-10-04 22:23:00',
                          '%D %y %a %d %m %b %j');
        -> '4th 97 Sat 04 10 Oct 277'
mysql> select DATE_FORMAT('1997-10-04 22:23:00',
                          '%H %k %I %r %T %S %w');
        -> '22 22 10 10:23:00 PM 22:23:00 00 6'

MySQL3.23中，在格式修饰符字符前需要%。在MySQL更早的版本中，%是可选的。

TIME_FORMAT(time,format)

这象上面的DATE_FORMAT()函数一样使用，但是format字符串只能包含处理小时、分钟和秒的那些格式修饰符。其他修饰符产生一个NULL值或0。

CURDATE()

CURRENT_DATE

以'YYYY-MM-DD'或YYYYMMDD格式返回今天日期值，取决于函数是在一个字符串还是数字上下文被使用。

mysql> select CURDATE();
        -> '1997-12-15'
mysql> select CURDATE() + 0;
        -> 19971215

CURTIME()

CURRENT_TIME

以'HH:MM:SS'或HHMMSS格式返回当前时间值，取决于函数是在一个字符串还是在数字的上下文被使用。

mysql> select CURTIME();
        -> '23:50:26'
mysql> select CURTIME() + 0;
        -> 235026

NOW()

SYSDATE()

CURRENT_TIMESTAMP

以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回当前的日期和时间，取决于函数是在一个字符串还是在数字的上下文被使用。

mysql> select NOW();
        -> '1997-12-15 23:50:26'
mysql> select NOW() + 0;
        -> 19971215235026

UNIX_TIMESTAMP()

UNIX_TIMESTAMP(date)

如果没有参数调用，返回一个Unix时间戳记(从'1970-01-01 00:00:00'GMT开始的秒数)。如果UNIX_TIMESTAMP()用一个date参数被调用，它返回从'1970-01-01
    00:00:00' GMT开始的秒数值。date可以是一个DATE字符串、一个DATETIME字符串、一个TIMESTAMP或以YYMMDD或YYYYMMDD格式的本地时间的一个数字。

mysql> select UNIX_TIMESTAMP();
        -> 882226357
mysql> select UNIX_TIMESTAMP('1997-10-04 22:23:00');
        -> 875996580

当UNIX_TIMESTAMP被用于一个TIMESTAMP列，函数将直接接受值，没有隐含的“string-to-unix-timestamp”变换。

FROM_UNIXTIME(unix_timestamp)

以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回unix_timestamp参数所表示的值，取决于函数是在一个字符串还是或数字上下文中被使用。

mysql> select FROM_UNIXTIME(875996580);
        -> '1997-10-04 22:23:00'
mysql> select FROM_UNIXTIME(875996580) + 0;
        -> 19971004222300

FROM_UNIXTIME(unix_timestamp,format)

返回表示 Unix 时间标记的一个字符串，根据format字符串格式化。format可以包含与DATE_FORMAT()函数列出的条目同样的修饰符。

mysql> select FROM_UNIXTIME(UNIX_TIMESTAMP(),
                            '%Y %D %M %h:%i:%s %x');
        -> '1997 23rd December 03:43:30 x'

SEC_TO_TIME(seconds)

返回seconds参数，变换成小时、分钟和秒，值以'HH:MM:SS'或HHMMSS格式化，取决于函数是在一个字符串还是在数字上下文中被使用。

mysql> select SEC_TO_TIME(2378);
        -> '00:39:38'
mysql> select SEC_TO_TIME(2378) + 0;
        -> 3938

TIME_TO_SEC(time)

返回time参数，转换成秒。
mysql> select TIME_TO_SEC('22:23:00');
        -> 80580
mysql> select TIME_TO_SEC('00:39:38');
        -> 2378

7.4.12
其他函数

DATABASE()

返回当前的数据库名字。
mysql> select DATABASE();
        -> 'test'

如果没有当前的数据库，DATABASE()返回空字符串。

USER()

SYSTEM_USER()

SESSION_USER()

返回当前MySQL用户名。
mysql> select USER();
        -> 'davida@localhost'

在MySQL 3.22.11或以后版本中，这包括用户名和客户主机名。你可以象这样只提取用户名部分(值是否包括主机名部分均可工作)：

mysql> select substring_index(USER(),"@",1);
        -> 'davida'

PASSWORD(str)

从纯文本口令str计算一个口令字符串。该函数被用于为了在user授权表的Password列中存储口令而加密MySQL口令。

mysql> select PASSWORD('badpwd');
        -> '7f84554057dd964b'

PASSWORD()加密是非可逆的。PASSWORD()不以与Unix口令加密的相同的方法执行口令加密。你不应该假定如果你的Unix
    口令和你的MySQL口令是一样的，PASSWORD()将导致与在Unix口令文件存储的相同的加密值。见ENCRYPT()。

ENCRYPT(str[,salt])

使用Unix crypt()系统调用加密str。salt参数应该是一个有2个字符的字符串。（MySQL
    3.22.16中，salt可以长于2个字符。）
mysql> select ENCRYPT("hello");
        -> 'VxuFAJXVARROc'

如果crypt()在你的系统上不可用，ENCRYPT()总是返回NULL。ENCRYPT()只保留str起始8个字符而忽略所有其他，至少在某些系统上是这样。这将由底层的crypt()系统调用的行为决定。

ENCODE(str,pass_str)

使用pass_str作为口令加密str。为了解密结果，使用DECODE()。结果是一个二进制字符串，如果你想要在列中保存它，使用一个BLOB列类型。

DECODE(crypt_str,pass_str)

使用pass_str作为口令解密加密的字符串crypt_str。crypt_str应该是一个由ENCODE()返回的字符串。

MD5(string)

对字符串计算MD5校验和。值作为一个32长的十六进制数字被返回可以，例如用作哈希(hash)键。

mysql> select MD5("testing")
        -> 'ae2b1fca515949e5d54fb22b8ed95575'

这是一个“RSA数据安全公司的MD5消息摘要算法”。

LAST_INSERT_ID([expr])

返回被插入一个AUTO_INCREMENT列的最后一个自动产生的值。见20.4.29 mysql_insert_id()。
mysql> select LAST_INSERT_ID();
        -> 195

产生的最后ID以每个连接为基础在服务器被维护，它不会被其他客户改变。如果你更新另外一个有非魔术值(即，不是NULL和不是0的一个值)的AUTO_INCREMENT列，它甚至不会被改变。如果expr作为一个参数在一个UPDATE子句的LAST_INSERT_ID()里面给出，那么参数值作为一个LAST_INSERT_ID()值被返回。这可以用来模仿顺序：首先创建表：

mysql> create table sequence (id int not null);
mysql> insert into sequence values (0);

然后表能被用来产生顺序号，象这样：

mysql> update sequence set id=LAST_INSERT_ID(id+1);

你可以不调用LAST_INSERT_ID()而产生顺序，但是这样使用函数的实用程序在服务器上自动维护ID值作为最后自动产生的值。你可以检索新的ID值，就像你能读入正常MySQL中的任何正常的AUTO_INCREMENT值一样。例如，LAST_INSERT_ID()（没有一个参数
    )将返回新ID。C API函数mysql_insert_id()也可被用来得到值。

FORMAT(X,D)

格式化数字X为类似于格式'#,###,###.##'，四舍五入到D为小数。如果D为0，结果将没有小数点和小数部分。

mysql> select FORMAT(12332.123456, 4);
        -> '12,332.1235'
mysql> select FORMAT(12332.1,4);
        -> '12,332.1000'
mysql> select FORMAT(12332.2,0);
        -> '12,332'

VERSION()

返回表明MySQL服务器版本的一个字符串。
mysql> select VERSION();
        -> '3.22.19b-log'

GET_LOCK(str,timeout)

试图获得由字符串str给定的一个名字的锁定，第二个timeout为超时。如果锁定成功获得，返回1，如果尝试超时了，返回0，或如果发生一个错误，返回NULL(例如从存储器溢出或线程用mysqladmin
    kill被杀死)。当你执行RELEASE_LOCK()时、执行一个新的GET_LOCK()或线程终止时，一个锁定被释放。该函数可以用来实现应用锁或模拟记录锁，它阻止其他客户用同样名字的锁定请求；赞成一个给定的锁定字符串名字的客户可以使用字符串执行子协作建议的锁定。

mysql> select GET_LOCK("lock1",10);
        -> 1
mysql> select GET_LOCK("lock2",10);
        -> 1
mysql> select RELEASE_LOCK("lock2");
        -> 1
mysql> select RELEASE_LOCK("lock1");
        -> NULL

注意，第二个RELEASE_LOCK()调用返回NULL，因为锁"lock1"自动地被第二个GET_LOCK()调用释放。

RELEASE_LOCK(str)

释放字符串str命名的通过GET_LOCK()获得的锁。如果锁被释放，返回1，如果锁没被这个线程锁定(在此情况下锁没被释放)返回0，并且如果命名的锁不存在，返回NULL。如果锁从来没有通过调用GET_LOCK()获得或如果它已经被释放了，锁将不存在。

BENCHMARK(count,expr)

BENCHMARK()函数重复countTimes次执行表达式expr，它可以用于计时MySQL处理表达式有多快。结果值总是0。意欲用于mysql客户，它报告查询的执行时间。

mysql> select BENCHMARK(1000000,encode("hello","goodbye"));
+----------------------------------------------+
| BENCHMARK(1000000,encode("hello","goodbye")) |
+----------------------------------------------+
|                                            0 |
+----------------------------------------------+
1 row in set (4.74 sec)

报告的时间是客户端的经过时间，不是在服务器端的CPU时间。执行BENCHMARK()若干次可能是明智的，并且注意服务器机器的负载有多重来解释结果。

7.4.13 与GROUP
BY子句一起使用的函数

如果你在不包含GROUP BY子句的一个语句中使用聚合函数，它等价于聚合所有行。

COUNT(expr)

返回由一个SELECT语句检索出来的行的非NULL值的数目。

mysql> select student.student_name,COUNT(*)
           from student,course
           where student.student_id=course.student_id
           GROUP BY student_name;

COUNT(*)在它返回的检索出来的行数目上有些不同，不管他们是否包含NULL值。如果SELECT从一个表检索，或没有检索出其他列并且没有WHERE子句，COUNT(*)被优化以便快速地返回。例如：

mysql> select COUNT(*) from student;

COUNT(DISTINCT expr,[expr...])

返回一个不同值的数目。
mysql> select COUNT(DISTINCT results) from student;

在MySQL中，你可以通过给出一个表达式列表以得到不同的表达式组合的数目。在
    ANSI SQL中，你可能必须在CODE(DISTINCT ..)内进行所有表达式的连接。

AVG(expr)

返回expr的平均值。
mysql> select student_name, AVG(test_score)
           from student
           GROUP BY student_name;

MIN(expr)

MAX(expr)

返回expr的最小或最大值。MIN()和MAX()可以有一个字符串参数；在这种的情况下，他们返回最小或最大的字符串值。

mysql> select student_name, MIN(test_score), MAX(test_score)
           from student
           GROUP BY student_name;

SUM(expr)

返回expr的和。注意，如果返回的集合没有行，它返回NULL！

STD(expr)

STDDEV(expr)

返回expr标准差(deviation)。这是对 ANSI SQL
    的扩展。该函数的形式STDDEV()是提供与Oracle的兼容性。

BIT_OR(expr)

返回expr里所有位的位或。计算用 64 位(BIGINT)精度进行。

BIT_AND(expr)

返回expr里所有位的位与。计算用 64 位(BIGINT)精度进行。

MySQL扩展了GROUP BY的用法。你可以不出现在的GROUP
BY部分的SELECT表达式中使用列或计算，这表示这个组的任何可能值。你可以使用它是性能更好，避免在不必要的项目上排序和分组。例如，你在下列查询中不需要在customer.name上聚合：

mysql> select order.custid,customer.name,max(payments)
       from order,customer
       where order.custid = customer.custid
       GROUP BY order.custid;

在 ANSI SQL中，你将必须将customer.name加到GROUP BY子句。在MySQL中，名字是冗余的。

如果你从GROUP BY部分省略的列在组中不是唯一的，不要使用这个功能。

在某些情况下，你可以使用MIN()和MAX()获得一个特定的列值，即使它不是唯一的。下例给出从包含sort列中最小值的行的column值：

substr(MIN(concat(sort,space(6-length(sort)),column),7,length(column)))

注意，如果你正在使用MySQL
3.22(或更早)或如果你正在试图遵从ANSI SQL，你不能在GROUP BY或ORDER
BY子句中使用表达式。你可以通过使用表达式的一个别名解决此限制：

mysql> SELECT id,FLOOR(value/100) AS val FROM tbl_name
           GROUP BY id,val ORDER BY val;

在MySQL3.23中，你可以这样做：

mysql> SELECT id,FLOOR(value/100) FROM tbl_name ORDER BY RAND();

7.5 CREATE
DATABASE句法

CREATE DATABASE db_name

CREATE DATABASE用给定的名字创建一个数据库。允许的数据库名字规则在7.1.5
数据库、桌子、索引、列和别名命名中给出。如果数据库已经存在，发生一个错误。

在MySQL中的数据库实现成包含对应数据库中表的文件的目录。因为数据库在初始创建时没有任何表，CREATE
DATABASE语句只是在MySQL数据目录下面创建一个目录。

你也可以用mysqladmin创建数据库。见12.1 不同的MySQL程序的概述。

7.6 DROP DATABASE句法

DROP DATABASE [IF EXISTS] db_name

DROP DATABASE删除数据库中的所有表和数据库。要小心地使用这个命令！

DROP DATABASE返回从数据库目录被删除的文件的数目。通常，这3倍于表的数量，因为每张表对应于一个“.MYD”文件、一个“.MYI”文件和一个“.frm”文件。

在MySQL 3.22或以后版本中，你可以使用关键词IF
EXISTS阻止一个错误的发生，如果数据库不存在。

你也可以用mysqladmin丢弃数据库。见12.1 不同的 MySQL 程序的概述。

7.7 CREATE TABLE句法

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
[table_options] [select_statement]

create_definition:
  col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
            [PRIMARY KEY] [reference_definition]
  or    PRIMARY KEY (index_col_name,...)
  or    KEY [index_name] (index_col_name,...)
  or    INDEX [index_name] (index_col_name,...)
  or    UNIQUE [INDEX] [index_name] (index_col_name,...)
  or    [CONSTRAINT symbol] FOREIGN KEY index_name (index_col_name,...)
            [reference_definition]
  or    CHECK (expr)

type:
        TINYINT[(length)] [UNSIGNED] [ZEROFILL]
  or    SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
  or    MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
  or    INT[(length)] [UNSIGNED] [ZEROFILL]
  or    INTEGER[(length)] [UNSIGNED] [ZEROFILL]
  or    BIGINT[(length)] [UNSIGNED] [ZEROFILL]
  or    REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
  or    DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
  or    FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
  or    DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
  or    NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
  or    CHAR(length) [BINARY]
  or    VARCHAR(length) [BINARY]
  or    DATE
  or    TIME
  or    TIMESTAMP
  or    DATETIME
  or    TINYBLOB
  or    BLOB
  or    MEDIUMBLOB
  or    LONGBLOB
  or    TINYTEXT
  or    TEXT
  or    MEDIUMTEXT
  or    LONGTEXT
  or    ENUM(value1,value2,value3,...)
  or    SET(value1,value2,value3,...)

index_col_name:
        col_name [(length)]

reference_definition:
        REFERENCES tbl_name [(index_col_name,...)]
                   [MATCH FULL | MATCH PARTIAL]
                   [ON DELETE reference_option]
                   [ON UPDATE reference_option]

reference_option:
        RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT

table_options:
    TYPE = {ISAM | MYISAM | HEAP}
or	AUTO_INCREMENT = #
or	AVG_ROW_LENGTH = #
or	CHECKSUM = {0 | 1}
or	COMMENT = "string"
or	MAX_ROWS = #
or	MIN_ROWS = #
or	PACK_KEYS = {0 | 1}
or	PASSWORD = "string"
or	DELAY_KEY_WRITE = {0 | 1}
or      ROW_FORMAT= { default | dynamic | static | compressed }

select_statement:
    [IGNORE | REPLACE] SELECT ...  (Some legal select statement)

CREATE TABLE在当前数据库中用给出的名字创建一个数据库表。允许的表名的规则在7.1.5
数据库，桌子，索引，列和别名命名中给出。如果当前数据库不存在或如果表已经存在，出现一个错误。

在MySQL3.22或以后版本中，表名可以被指定为db_name.tbl_name，不管有没有当前的数据库都可以。

在MySQL3.23中，当你创建一张表时，你可以使用TEMPORARY关键词。如果一个连接死掉，临时表将自动被删除，并且其名字是按连接命名。这意味着，2个不同的连接能使用相同的暂时表的名字而不会彼此冲突或与相同名字的现有数据库表冲突。（现有的表被隐蔽直到临时表被删除）。

在MySQL3.23或以后版本中，你可以使用关键词IF NOT
EXISTS以便如果表已经存在不发生一个错误。注意，无法证实表结构是相同的。

每张表tbl_name由在数据库目录的一些文件表示。在MyISAM类型的表的情况下，你将得到：

文件 | 目的
tbl_name.frm | 表定义(表格)文件
tbl_name.MYD | 数据文件
tbl_name.MYI | 索引文件

对于各种列类型的性质的更多信息，见7.3 列类型。

  • 如果既不指定NULL也不指定NOT NULL，列被视为指定了NULL。

    •

  • 整型列可以有附加的属性AUTO_INCREMENT。当你插入NULL值（推荐)或0到一个AUTO_INCREMENT列中时，列被设置为value+1，在此value是当前表中的列的最大值。AUTO_INCREMENT顺序从1开始。见20.4.29 mysql_insert_id()。如果你删除了包含一个AUTO_INCREMENT列的最大值的行，值将被重新使用。如果你删除表中所有的行，顺序重新开始。注意：每个表只能有一个AUTO_INCREMENT列，并且它必须被索引。为了使做MySQL兼容一些
    ODBC 应用程序，用下列查询你可以找出最后插入的行：
    SELECT * FROM tbl_name WHERE auto_col IS NULL

    •

  • NULL值对于TIMESTAMP列的处理不同于其他列类型。你不能在一个TIMESTAMP列中存储一个文字NULL；设置列为NULL将把它设成当前的日期和时间。因为TIMESTAMP列表现就这样，NULL和NOT
    NULL属性不以一般方式运用并且如果你指定它们，将被忽略。在另一方面，为了使它MySQL客户更容易地使用TIMESTAMP列，服务器报告这样的列可以被赋值NULL(
    它是对的)，尽管TIMESTAMP实际上绝不包含一个NULL值。当你使用DESCRIBE
    tbl_name得到有关你的表的描述时，你就会明白。注意，设置一个TIMESTAMP列为0不同于将它设置为NULL，因为0是一个有效的TIMESTAMP值。

    •

  • 如果没有为列指定DEFAULT值，MySQL自动地分配一个。如果列可以取NULL作为值，缺省值是NULL。如果列被声明为NOT
    NULL，缺省值取决于列类型：

    • 对于没有声明AUTO_INCREMENT属性的数字类型，缺省值是0。对于一个AUTO_INCREMENT列，缺省值是在顺序中的下一个值。

      •

    • 对于除TIMESTAMP的日期和时间类型，缺省值是该类型适当的“零”值。对于表中第一个TIMESTAMP列，缺省值是当前的日期和时间。见7.3.6 日期和时间类型。
      •

    • 对于除ENUM的字符串类型，缺省是空字符串。对于ENUM，缺省值是第一个枚举值。

      •

    •

  • KEY是INDEX的一个同义词。
    •

  • 在MySQL中，一个UNIQUE键只能有不同的值。如果你试图用匹配现有行的键来增加新行，发生一个错误。

    •

  • A PRIMARY KEY是一个唯一KEY，它有额外的限制，即所有的关键列必须被定义为NOT
    NULL。在MySQL中，键被命名为PRIMARY。一张表只能有一个PRIMARY
    KEY。如果在表中你没有一个PRIMARY KEY并且一些应用程序要求PRIMARY
    KEY，MySQL将返回第一个UNIQUE键，它没有任何NULL列，作为PRIMARY
    KEY。
    •

  • 一个PRIMARY KEY可以是一个多列索引。然而，你不能在一个列说明中使用PRIMARY
    KEY的关键字属性创建一个多列索引。这样做将仅仅标记单个列作为主键。你必须使用PRIMARY
    KEY(index_col_name, ...)语法。
    •

  • 如果你不能给索引赋予一个名字，这个索引将赋予与第一个index_col_name相同的名字，用一个可选的suffix(_2,
    _3, ...)使它唯一。你能使用SHOW INDEX FROM
    tbl_name看到一张表的索引名字。见7.21
    SHOW句法(得到表、列等的信息）。
    •

  • 只有MyISAM表类型支持可以有NULL值的列上的索引。在其他情况下，你必须声明这样的列为NOT
    NULL，否则导致一个错。
    •

  • 用col_name(length)语法，你可以指定仅使用部分的CHAR或VARCHAR列的一个索引。这能使索引文件变得更小。见7.3.9 列索引。
    •

  • 只有MyISAM表类型支持BLOB和TEXT列的索引。当在一个BLOB或TEXT列上放置索引时，你必须总是指定索引的长度：

    CREATE TABLE test (blob_col BLOB, index(blob_col(10)));

    •

  • 当你与TEXT或BLOB列一起使用ORDER BY或GROUP
    BY时，只使用头max_sort_length个字节。见7.3.7.2 BLOB和TEXT类型。

    •

  • FOREIGN KEY、CHECK和REFERENCES子句实际上不做任何事情，其语法仅仅提供兼容性，使得它更容易从其他的SQL服务器移植代码并运行借助引用创建表的应用。见5.4 MySQL缺少的功能。
    •

  • 每个NULL列占据额外一位，取舍到最接近的字节。
    •

  • 最大记录长度以字节计可以如下计算：
    row length = 1
             + (sum of column lengths)
             + (number of NULL columns + 7)/8
             + (number of variable-length columns)

    •

  • table_options和SELECT选项只在MySQL 3.23和以后版本中被实现。不同的表类型是：

        ISAM
         | 原来的表处理器

        MyISAM
         | 全新二进制可移植的表处理器

        HEAP
         | 用于该表的数据仅仅存储在内存中

    见9.4 MySQL 表类型。其他表选项被用来优化表的行为。在大多数情况下，你不必指定他们任何一个。选项对所有表都适用，如果不是则说明。

        AUTO_INCREMENT
         | 你想要为你的表设定的下一个 auto_increment 值 ( MyISAM ）

        AVG_ROW_LENGTH
         | 你的表的平均行长度的近似值。你只需要为有变长记录的表设置它。

        CHECKSUM
         | 如果你想要MySQL对每行维持一个校验和(使表变得更慢以更新但是使它更容易找出损坏的表)设置它为1
        ( MyISAM )

        COMMENT
         | 对于你的表的一篇60个字符的注释

        MAX_ROWS
         | 你计划在表中存储的行的最大数目

        MIN_ROWS
         | 你计划在表中存储的行的最小数目

        PACK_KEYS
         | 如果你想要有更小的索引，将它设为1。这通常使的更新更慢并且读取更快(MyISAM，ISAM)。

        PASSWORD
         | 用一个口令加密.frm文件。该选项在标准MySQL版本中不做任何事情。

        DELAY_KEY_WRITE
         | 如果想要推迟关键表的更新直到表被关闭(MyISAM)，将它设置为1。

        ROW_FORMAT
         | 定义行应该如何被存储(为了将来)。

    当你使用一个MyISAM表时，MySQL使用max_rows
    * avg_row_length的乘积决定最终的表将有多大。如果你不指定上面的任何选项，对一个表的最大尺寸将是4G(或2G，如果你的操作系统仅支持2G的表)。

    •

  • 如果你在CREATE语句后指定一个SELECT，MySQL将为在SELECT中所有的单元创键新字段。例如：

    mysql> CREATE TABLE test (a int not null auto_increment,
           primary key (a), key(b))
           TYPE=HEAP SELECT b,c from test2;

    这将创建一个有3个列的HEAP表。注意如果在拷贝数据进表时发生任何错误，表将自动被删除。

    •

7.7.1
隐含的列说明改变

在某些情况下，MySQL隐含地改变在一个CREATE TABLE语句给出的一个列说明。（这也可能在ALTER
TABLE。）

  • 长度小于4的VARCHAR被改变为CHAR。
    •

  • 如果在一个表中的任何列有可变长度，结果是整个行是变长的。因此,
    如果一张表包含任何变长的列(VARCHAR、TEXT或BLOB)，所有大于3个字符的CHAR列被改变为VARCHAR列。这在任何方面都不影响你如何使用列；在MySQL中，VARCHAR只是存储字符的一个不同方法。MySQL实施这种改变，是因为它节省空间并且使表操作更快捷。见10.6 选择一种表格类型。
    •

  • TIMESTAMP的显示尺寸必须是偶数且在2 ～ 14的范围内。如果你指定0显示尺寸或比14大，尺寸被强制为14。从1～13范围内的奇数值尺寸被强制为下一个更大的偶数。

    •

  • 你不能在一个TIMESTAMP列里面存储一个文字NULL；将它设为NULL将设置为当前的日期和时间。因为TIMESTAMP列表现就是这样，NULL和NOT
    NULL属性不以一般的方式运用并且如果你指定他们，将被忽略。DESCRIBE
    tbl_name总是报告该TIMESTAMP列可能赋予了NULL值。

    •

  • MySQL将其他SQL数据库供应商使用的某个列类型映射到MySQL类型。见7.3.11
    只用其他数据库引擎的类型。
    •

如果你想要知道MySQL是否使用了除你指定的以外的一种列类型，在创建或改变你的表之后，发出一个DESCRIBE
tbl_name语句即可。

如果你使用myisampack压缩一个表，可能会发生改变某些其他的列类型。见10.6.3 压缩表的特征。

7.8 ALTER TABLE句法

ALTER [IGNORE] TABLE tbl_name alter_spec [, alter_spec ...]

alter_specification:
        ADD [COLUMN] create_definition [FIRST | AFTER column_name ]
  or    ADD INDEX [index_name] (index_col_name,...)
  or    ADD PRIMARY KEY (index_col_name,...)
  or    ADD UNIQUE [index_name] (index_col_name,...)
  or    ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
  or    CHANGE [COLUMN] old_col_name create_definition
  or    MODIFY [COLUMN] create_definition
  or    DROP [COLUMN] col_name
  or    DROP PRIMARY KEY
  or    DROP INDEX index_name
  or    RENAME [AS] new_tbl_name
  or    table_options

ALTER TABLE允许你修改一个现有表的结构。例如，你可以增加或删除列、创造或消去索引、改变现有列的类型、或重新命名列或表本身。你也能改变表的注释和表的类型。见7.7 CREATE TABLE句法。

如果你使用ALTER TABLE修改一个列说明但是DESCRIBE
tbl_name显示你的列并没有被修改，这可能是MySQL因为在7.7.1 隐含的列说明改变中描述的原因之一而忽略了你的修改。例如，如果你试图将一个VARCHAR改为CHAR，MySQL将仍然使用VARCHAR，如果表包含其他变长的列。

ALTER TABLE通过制作原来表的一个临时副本来工作。修改在副本上施行，然后原来的表被删除并且重新命名一个新的。这样做使得所有的修改自动地转向到新表，没有任何失败的修改。当ALTER
TABLE正在执行时，原来的桌可被其他客户读取。更新和写入表被延迟到新表准备好了为止。

  • 为了使用ALTER TABLE，你需要在表上的select、insert、delete、update、create和drop的权限。

    •

  • IGNORE是MySQL对ANSI SQL92
    的一个扩充，如果在新表中的唯一键上有重复，它控制ALTER TABLE如何工作。如果IGNORE没被指定，副本被放弃并且恢复原状。如果IGNORE被指定，那么对唯一键有重复的行，只有使用第一行；其余被删除。

    •

  • 你可以在单个ALTER TABLE语句中发出多个ADD、ALTER、DROP和CHANGE子句。这是MySQL对ANSI
    SQL92的一个扩充，SQL92在每个ALTER TABLE语句中只允许一个子句。

    •

  • CHANGE col_name、DROP col_name和DROP INDEX是MySQL对
    ANSI SQL92 的扩充。
    •

  • MODIFY是 Oracle 对ALTER TABLE的扩充。
    •

  • 可选的词COLUMN是一个纯粹的噪音且可以省略。
    •

  • 如果你使用ALTER TABLE tbl_name RENAME AS new_name而没有任何其他选项，MySQL简单地重命名对应于表tbl_name的文件。没有必要创建临时表。

    •

  • create_definition子句使用CREATE TABLE相同的ADD和CHANGE语法。注意语法包括列名字，不只列类型。见7.7 CREATE TABLE句法。
    •

  • 你可以使用CHANGE old_col_name create_definition子句重命名一个列。为了这样做，指定旧的和新的列名字和列当前有的类型。例如，重命名一个INTEGER列，从a到b，你可以这样做：

    mysql> ALTER TABLE t1 CHANGE a b INTEGER;

    如果你想要改变列的类型而非名字，就算他们是一样的，CHANGE语法仍然需要2个列名。例如：

    mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;

    然而，在MySQL3.22.16a，你也可以使用MODIFY来改变列的类型而不是重命名它：

    mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;

    •

  • 如果你使用CHANGE或MODIFY缩短一个列，一个索引存在于该列的部分(例如，如果你有一个VARCHAR列的头10个字符的索引)，你不能使列短于被索引的字符数目。

    •

  • 当你使用CHANGE或MODIFY改变一个列类型时，MySQL尽可能试图很好地变换数据到新类型。

    •

  • 在MySQL3.22或以后，你能使用FIRST或ADD ...
    AFTER col_name在一个表的行内在一个特定的位置增加列。缺省是增加到最后一列。

    •

  • ALTER COLUMN为列指定新的缺省值或删除老的缺省值。如果老的缺省值被删除且列可以是NULL，新缺省值是NULL。如果列不能是NULL，MySQL赋予一个缺省值。缺省值赋值在7.7 CREATE TABLE句法中描述。

    •

  • DROP INDEX删除一个索引。这是MySQL对 ANSI SQL92
    的一个扩充。
    •

  • 如果列从一张表中被丢弃，列也从他们是组成部分的任何索引中被删除。如果组成一个索引的所有列被丢弃，该索引也被丢弃。

    •

  • DROP PRIMARY KEY丢弃主索引。如果这样的索引不存在，它丢弃表中第一个UNIQUE索引。(如果没有明确地指定PRIMARY
    KEY，MySQL标记第一个UNIQUE键为PRIMARY
    KEY。）
    •

  • 用 C API 函数mysql_info()，你能找出多少记录被拷贝，
    和(当使用IGNORE时)由于唯一键值的重复多少记录被删除。
    •

  • FOREIGN KEY、CHECK和REFERENCES子句实际上不做任何事情，他们的句法仅仅提供兼容性，使得更容易地从其他SQL服务器移植代码并且运行借助引用来创建表的应用程序。见5.4 MySQL缺少的功能。
    •

这里是一个例子，显示了一些ALTER TABLE用法。我们以一个如下创建的表t1开始：

mysql> CREATE TABLE t1 (a INTEGER,b CHAR(10));

重命名表，从t1到t2:

mysql> ALTER TABLE t1 RENAME t2;

为了改变列a，从INTEGER改为TINYINT NOT NULL(名字一样)，并且改变列b，从CHAR(10)改为CHAR(20)，同时重命名它，从b改为c：

mysql> ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);

增加一个新TIMESTAMP列，名为d：

mysql> ALTER TABLE t2 ADD d TIMESTAMP;

在列d上增加一个索引，并且使列a为主键：

mysql> ALTER TABLE t2 ADD INDEX (d), ADD PRIMARY KEY (a);

删出列c：

mysql> ALTER TABLE t2 DROP COLUMN c;

增加一个新的AUTO_INCREMENT整数列，命名为c：

mysql> ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
           ADD INDEX (c);

注意，我们索引了c，因为AUTO_INCREMENT柱必须被索引，并且另外我们声明c为NOT
NULL，因为索引了的列不能是NULL。

当你增加一个AUTO_INCREMENT列时，自动地用顺序数字填入列值。

7.9 OPTIMIZE
TABLE句法

OPTIMIZE TABLE tbl_name

如果你删除了一个表的大部分或如果你用变长的行对一个表(有VARCHAR、BLOB或TEXT列的表)做了改变，应该使用OPTIMZE
TABLE。删除的记录以一个链接表维持并且随后的INSERT操作再次使用老记录的位置。你可以使用OPTIMIZE
TABLE回收闲置的空间。

OPTIMIZE TABLE通过制作原来的表的一个临时副本来工作。老的表子被拷贝到新表中(没有闲置的行)，然后原来的表被删除并且重命名一个新的。这样做使得所有更新自动转向新的表，没有任何失败的更新。当时OPTIMIZE
TABLE正在执行时，原来的表可被另外的客户读取。对表的更新和写入延迟到新表是准备好为止。

7.10 DROP TABLE句法

DROP TABLE [IF EXISTS] tbl_name [, tbl_name,...]

DROP TABLE删除一个或多个数据库表。所有表中的数据和表定义均被删除，故小心使用这个命令！

在MySQL 3.22或以后版本，你可以使用关键词IF EXISTS类避免不存在表的一个错误发生。

7.11 DELETE句法

DELETE [LOW_PRIORITY] FROM tbl_name
    [WHERE where_definition] [LIMIT rows]

DELETE从tbl_name表中删除满足由where_definition给出的条件的行，并且返回删除记录的个数。

如果你发出一个没有WHERE子句的DELETE，所有行都被删除。MySQL通过创建一个空表来完成，它比删除每行要快。在这种情况下，DELETE返回零作为受影响记录的数目。(MySQL不能返回实际上被删除的行数，因为进行再创建而不是打开数据文件。只要表定义文件“tbl_name.frm”是有效的，表才能这样被再创建，即使数据或索引文件破坏了)。

如果你确实想要知道在你正在删除所有行时究竟有对少记录被删除，并且愿意承受速度上的惩罚，你可以这种形式的一个ELETE语句：

mysql> DELETE FROM tbl_name WHERE 1>0;

注意这比没有WHERE子句的DELETE FROM tbl_name慢的多了，因为它一次删除一行。

如果你指定关键词LOW_PRIORITY，DELETE的执行被推迟到没有其他客户读取表后。

删除的记录以一个链接表维持并且随后的INSERT操作再次使用老的记录位置。为了回收闲置的空间并减小文件大小，使用OPTIMIZE
TABLE语句或myisamchk实用程序重新组织表。OPTIMIZE
TABLE较容易，但是myisamchk更快。见7.9 OPTIMIZE TABLE句法和13.4.3 表优化。

MySQL对DELETE特定的LIMIT rows选项告诉服务器在控制被返回到客户之前，将要删除的最大行数，这可以用来保证一个特定DELETE命令不会花太多的时间。你可以简单地重复DELETE命令直到受影响的行数小于LIMIT值。

7.12 SELECT句法

SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [HIGH_PRIORITY]
       [DISTINCT | DISTINCTROW | ALL]
    select_expression,...
    [INTO {OUTFILE | DUMPFILE} 'file_name' export_options]
    [FROM table_references
        [WHERE where_definition]
        [GROUP BY col_name,...]
        [HAVING where_definition]
        [ORDER BY {unsigned_integer | col_name | formula} [ASC | DESC] ,...]
        [LIMIT [offset,] rows]
        [PROCEDURE procedure_name] ]

SELECT被用来检索从一个或多个表中精选的行。select_expression指出你想要检索的列。SELECT也可以用来检索不引用任何表的计算行。例如：

mysql> SELECT 1 + 1;
         -> 2

所有使用的关键词必须精确地以上面的顺序给出。例如，一个HAVING子句必须跟在GROUP
BY子句之后和ORDER BY子句之前。

  • 一个SELECT表达式可以用一个AS给定一个别名，别名被用作表达式的列名并且能使用在ORDER
    BY或HAVING子句中。例如：
    mysql> select concat(last_name,', ',first_name) AS full_name
    from mytable ORDER BY full_name;

    •

  • FROM table_references子句指出从哪个表中检索行。如果你命名多个表，你正在执行一个联结(join)。对于联结的句法信息，见7.13 JOIN句法。
    •

  • 你可以引用一个列为col_name、tbl_name.col_name或db_name.tbl_name.col_name，你不必在一个SELECT语句中指定一个tbl_name或db_name.tbl_name是一个列引用的前缀，除非引用有二义性。见7.1.5
    数据库、表、索引、列和别名命名。对于二义性的例子要求更加显式的列引用格式。

    •

  • 一个表引用可以使用tbl_name [AS]
    alias_name起一个别名。
    mysql> select t1.name, t2.salary from employee AS t1, info AS t2
           where t1.name = t2.name;
mysql> select t1.name, t2.salary from employee t1, info t2
           where t1.name = t2.name;

    •

  • 精选输出的列可以用列名、列别名或列位置在ORDER BY和GROUP
    BY子句引用，列位置从1开始。
    mysql> select college, region, seed from tournament
           ORDER BY region, seed;
mysql> select college, region AS r, seed AS s from tournament
           ORDER BY r, s;
mysql> select college, region, seed from tournament
           ORDER BY 2, 3;

    为了以降序排列，把DESC（下降 )关键词加到ORDER BY子句中你要排序的列名前。缺省是升序；这也可以用ASC关键词明确指定。

    •

  • HAVING子句能引用任何列或在select_expression中命名的别名，它最后运用，就在项目被送到客户之前，没有优化。不要对因该在WHERE子句中的项目使用HAVING。例如，不能写成这样：

    mysql> select col_name from tbl_name HAVING col_name > 0;

    相反写成这样：

    mysql> select col_name from tbl_name WHERE col_name > 0;

    在MySQL 3.22.5或以后，你也能这样写查询：

    mysql> select user,max(salary) from users group by user HAVING max(salary)>10;

    在里面更老的MySQL版本中，你能这样写：

    mysql> select user,max(salary) AS sum from users
           group by user HAVING sum>10;

    •

  • SQL_SMALL_RESULT、SQL_BIG_RESULT、STRAIGHT_JOIN和HIGH_PRIORITY是MySQL对ANSI
    SQL92的扩展。
    •

  • STRAIGHT_JOIN强制优化器以其列在FROM子句的次序联结(join)桌子。如果优化器以非最佳次序联结表，你能使用它加速查询。见7.22 EXPLAIN句法(得到关于SELECT的信息)。

    •

  • SQL_SMALL_RESULT能与GROUP BY或DISTINCT一起使用告诉优化器结果集将很小。在这种情况下，MySQL将使用快速临时表存储最终的表而不是使用排序。
    SQL_SMALL_RESULT是一个MySQL扩展。
    •

  • SQL_BIG_RESULT能与GROUP BY或DISTINCT一起使用以告诉优化器结果集合将有很多行。在这种情况下，如果需要，MySQL将直接使用基于磁盘的临时表。
    MySQL在这种情况下将选择用GROUP BY单元上的键值进行排序而不是做一个临时表。

    •

  • HIGH_PRIORITY将赋予SELECT比一个更新表的语句更高的优先级，你应该仅对非常快的并且必须一次完成的查询使用它。
    如果表为读而锁定或甚至有一个等待表释放的更新语句，一个SELECT
    HIGH_PRIORITY将运行。
    •

  • LIMIT子句可以被用来限制SELECT语句返回的行数。LIMIT取1个或2个数字参数，如果给定2个参数，第一个指定要返回的第一行的偏移量，第二个指定返回行的最大数目。初始行的偏移量是0(不是1)。

    mysql> select * from table LIMIT 5,10;  # Retrieve rows 6-15

    如果给定一个参数，它指出返回行的最大数目。

    mysql> select * from table LIMIT 5;     # Retrieve first 5 rows

    换句话说，LIMIT n等价于LIMIT 0,n。

    •

  • SELECT ... INTO OUTFILE 'file_name'格式的SELECT语句将选择的行写入一个文件。文件在服务器主机上被创建，并且不能是已经存在的(不管别的，这可阻止数据库表和文件例如“/etc/passwd”被破坏)。在服务器主机上你必须有file权限以使用这种SELECT。SELECT
    ... INTO OUTFILE是LOAD DATA INFILE逆操作；语句的export_options部分的语法与用在LOAD
    DATA INFILE语句中的FIELDS和LINES子句的相同。见7.16 LOAD DATA INFILE句法。在最终的文本文件中，只有下列字符由ESCAPED
    BY字符转义：

    • ESCAPED BY字符
      •

    • 在FIELDS TERMINATED BY中的第一个字符
      •

    • 在LINES TERMINATED BY中的第一个字符
      •

    另外，ASCII 0被变换到ESCAPED BY后跟0(ASCII 48)。上述的原因是你必须转义任何FIELDS
    TERMINATED BY、ESCAPED BY或LINES TERMINATED BY字符以便能可靠地能读回文件。ASCII
    0被转义使它更容易用分页器观看。因为最终的文件不必须遵循SQL句法，没有别的东西需要转义。

    •

如果你使用INTO DUMPFILE而不是INTO
OUTFILE，MySQL将只写一行到文件中，没有任何列或行结束并且没有任何转义。如果你想要在一个文件存储一个blob，这是很有用的。

7.13 JOIN句法

MySQL支持下列用于SELECT语句的JOIN句法：

table_reference, table_reference
table_reference [CROSS] JOIN table_reference
table_reference INNER JOIN table_reference
table_reference STRAIGHT_JOIN table_reference
table_reference LEFT [OUTER] JOIN table_reference ON conditional_expr
table_reference LEFT [OUTER] JOIN table_reference USING (column_list)
table_reference NATURAL LEFT [OUTER] JOIN table_reference
{ oj table_reference LEFT OUTER JOIN table_reference ON conditional_expr }

上述最后的LEFT OUTER JOIN的句法只是为了与ODBC兼容而存在的。

  • 一个表可以是使用aliasedtbl_name AS alias_name或tbl_name
    alias_name的起的别名。
    mysql> select t1.name, t2.salary from employee AS t1, info AS t2
           where t1.name = t2.name;

    •

  • INNER JOIN和,（逗号)在语义上是等价的，都是进行一个在使用的表之间的全联结。通常，你指定表应该如何用WHERE条件联结起来。

    •

  • ON条件是可以用在一个WHERE子句形式的任何条件。

    •

  • 如果在一个LEFT JOIN中没有右表的匹配记录，一个所有列设置为NULL的行被用于右表。你可以使用这个事实指出表中在另一个表中没有对应记录的记录：

    mysql> select table1.* from table1
           LEFT JOIN table2 ON table1.id=table2.id
           where table2.id is NULL;

    这个例子找出在table1中所有的行，其id值在table2中不存在（即，所有table1中的在table2中没有对应行的行)。当然这假定table2.id被声明为NOT
    NULL。

    •

  • USING (column_list)子句命名一系列必须存在于两个表中的列。
    例如一个USING子句：
    A LEFT JOIN B USING (C1,C2,C3,...)

    被定义成在语义上等同一个这样的ON表达式：

    A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3,...

    •

  • 2个表的NATURAL LEFT JOIN被定义为在语义上等同于一个有USING子句命名在两表中存在的所有列的一个LEFT
    JOIN。
    •

  • STRAIGHT_JOIN等同于JOIN，除了左表在右表之前被读入，这能用于这些情况，联结优化器将表的顺序放错了。

    •

一些例子：

mysql> select * from table1,table2 where table1.id=table2.id;
mysql> select * from table1 LEFT JOIN table2 ON table1.id=table2.id;
mysql> select * from table1 LEFT JOIN table2 USING (id);
mysql> select * from table1 LEFT JOIN table2 ON table1.id=table2.id
           LEFT JOIN table3 ON table2.id=table3.id;

见10.5.4 MySQL怎样优化LEFT
JOIN。

7.14 INSERT句法

    INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        VALUES (expression,...),(...),...
或  INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...
或  INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name
        SET col_name=expression, col_name=expression, ...

INSERT把新行插入到一个存在的表中，INSERT ... VALUES形式的语句基于明确指定的值插入行，INSERT
... SELECT形式插入从其他表选择的行，有多个值表的INSERT ...
VALUES的形式在MySQL 3.22.5或以后版本中支持，col_name=expression语法在MySQL
3.22.10或以后版本中支持。

tbl_name是行应该被插入其中的表。列名表或SET子句指出语句为那一列指定值。

  • 如果你为INSERT ... VALUES或INSERT ... SELECT不指定列表，所有列的值必须在VALUES()表或由SELECT提供。如果你不知道表中列的顺序，使用DESCRIBE
    tbl_name来找出。
    •

  • 任何没有明确地给出值的列被设置为它的缺省值。例如，如果你指定一个列表并没命名表中所有列，未命名的列被设置为它们的缺省值。缺省值赋值在7.7 CREATE TABLE句法中描述。

    •

  • 一个expression可以引用在一个值表先前设置的任何列。例如，你能这样：

    mysql> INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);

    但不能这样：

    mysql> INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);

    •

  • 如果你指定关键词LOW_PRIORITY，INSERT的执行被推迟到没有其他客户正在读取表。在这种情况下，客户必须等到插入语句完成后，如果表频繁使用，它可能花很长时间。这与INSERT
    DELAYED让客马上继续正好相反。
    •

  • 如果你在一个有许多值行的INSERT中指定关键词IGNORE，表中任何复制一个现有PRIMARY或UNIQUE键的行被忽略并且不被插入。如果你不指定IGNORE，插入如果有任何复制现有关键值的行被放弃。你可用C
    API函数mysql_info()检查多少行被插入到表中。
    •

  • 如果MySQL用DONT_USE_DEFAULT_FIELDS选项配置，INSERT语句产生一个错误，除非你明确对需要一个非NULL值的所有列指定值。见4.7.3 典型configure选项。

    •

  • INSERT INTO ... SELECT语句满足下列条件：

    • 查询不能包含一个ORDER BY子句。
      •

    • INSERT语句的目的表不能出现在SELECT查询部分的FROM子句，因为这在ANSI
        SQL中被禁止让从你正在插入的表中SELECT。（问题是SELECT将可能发现在同一个运行期间内先前被插入的记录。当使用子选择子句时，情况能很容易混淆）
      •

    • AUTO_INCREMENT列象往常一样工作。
      •

    •

如果你使用INSERT ... SELECT或INSERT ...
VALUES语句有多个值列表，你可以使用C API函数mysql_info()得到查询的信息。信息字符串的格式如下：

Records: 100 Duplicates: 0 Warnings: 0

Duplicates指出不能被插入的行的数量，因为他们与现有的唯一的索引值重复。Warnings指出在出现某些问题时尝试插入列值的次数。在下列任何条件下都可能发生错误：

  • 插入NULL到被声明了NOT NULL的列，列被设置为它的缺省值。

    •

  • 将超出列范围的值设置给一个数字列，值被剪切为范围内适当的端点值。

    •

  • 将数字列设成例如'10.34 a'的值，拖尾的垃圾被剥去并仍然是数字部分被插入。如果值根本不是一个数字，列被设置到0。

    •

  • 把一个字符串插入到超过列的最大长度的一个CHAR、VARCHAR、TEXT或BLOB列中。值被截断为列的最大长度。

    •

  • 把一个对列类型不合法的值插入到一个日期或时间列。列被设置为该列类型适当的“零”值。

    •

对于INSERT语句的DELAYED选项是MySQL专属的选项-如果你客户有不能等到INSERT完成，它是很有用的。当你为日记登录使用MySQL时，而且你也周期性地运行花很长时间完成的SELECT语句，这是一个常见的问题。DELAYED在面MySQL
3.22.15中被引入，它是MySQL对 ANSI SQL92 的一个扩展。

当你使用INSERT DELAYED时，客户将马上准备好，并且当表不被任何其他的线程使用时，行将被插入。

另一个使用INSERT DELAYED的主要好处是从很多客户插入被捆绑在一起并且写进一个块。这比做很多单独的插入要来的快。

注意，当前排队的行只是存储在内存中，直到他们被插入到表中。这意味着，如果你硬要杀死mysqld(kill
-9)或如果mysqld出人意料地死掉，没被写进磁盘的任何排队的行被丢失！

下列详细描述当你为INSERT或REPLACE使用DELAYED选项时，发生什么。在这个描述中，“线程”是收到一个INSERT
DELAYED命令的线程并且“处理器”是处理所有对于一个特定表的INSERT
DELAYED语句。

  • 当一个线程对一个表执行一个DELAYED语句时，如果不存在这样的处理程序，一个处理器线程被创建以处理对于该表的所有DELAYED语句。

    •

  • 线程检查处理程序是否已经获得了一个DELAYED锁；如果没有，它告诉处理程序去获得。即使其他的线程有在表上的一个READ或WRITE锁，也能获得DELAYED锁。然而，处理程序将等待所有ALTER
    TABLE锁或FLUSH TABLES以保证表结构是最新的。
    •

  • 线程执行INSERT语句，但不是将行写入表，它把最后一行的副本放进被处理器线程管理的一个队列。任何语法错误都能被线程发觉并报告给客户程序。

    •

  • 顾客不能报告结果行的重复次数或AUTO_INCREMENT值；它不能从服务器获得它们，因为INSERT在插入操作完成前返回。如果你使用C
    API，同样原因，mysql_info()函数不返回任何有意义的东西。
    •

  • 当行被插入到表中时，更新日志有处理器线程更新。在多行插入的情况下，当第一行被插入时，更新日志被更新。

    •

  • 在每写入delayed_insert_limit行后，处理器检查是否任何SELECT语句仍然是未完成，如果这样，在继续之前允许执行这些语句。

    •

  • 当处理器在它的队列中没有更多行时，表被解锁。如果在delayed_insert_timeout秒内没有收到新的INSERT
    DELAYED命令，处理器终止。
    •

  • 如果已经有多于delayed_queue_size行在一个特定的处理器队列中未解决，线程等待直到队列有空间。这有助于保证mysqld服务器对延迟的内存队列不使用所有内存。

    •

  • 处理器线程将在Command列的MySQL进程表中显示delayed_insert。如果你执行一个FLUSH
    TABLES命令或以KILL thread_id杀死它，它将被杀死，然而，它在退出前首先将所有排队的行存进表中。在这期间，这次它将不从其他线程接受任何新的INSERT命令。如果你在它之后执行一个INSERT
    DELAYED，将创建一个新的处理器线程。
    •

  • 注意，上述意味着，如果有一个INSERT DELAYED处理器已经运行，INSERT
    DELAYED命令有比正常INSERT更高的优先级！其他更新命令将必须等到INSERT
    DELAY排队变空、杀死处理器线程(用KILL thread_id)或执行FLUSH
    TABLES。
    •

  • 下列状态变量提供了关于INSERT DELAYED命令的信息：

        Delayed_insert_threads
         | 处理器线程数量

        Delayed_writes
         | 用INSERT DELAYED被写入的行的数量

        Not_flushed_delayed_rows
         | 等待被写入的行数字

    你能通过发出一个SHOW STATUS语句或通过执行一个mysqladmin
    extended-status命令察看这些变量。

    •

注意如果桌子不在使用，INSERT DELAYED比一个正常的INSERT慢。对服务器也有额外开销来处理你对它使用INSERT
DELAYED的每个表的一个单独线程。这意味着，你应该只在你确实肯定需要它的时候才使用INSERT
DELAYED！

7.15 REPLACE句法

    REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name [(col_name,...)]
        VALUES (expression,...)
或  REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...
或  REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name
        SET col_name=expression, col_name=expression,...

REPLACE功能与INSERT完全一样，除了如果在表中的一个老记录具有在一个唯一索引上的新记录有相同的值，在新记录被插入之前，老记录被删除。见7.14 INSERT句法。

7.16 LOAD DATA INFILE句法

LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE]
    INTO TABLE tbl_name
    [FIELDS
        [TERMINATED BY '\t']
        [OPTIONALLY] ENCLOSED BY '']
        [ESCAPED BY '\\' ]]
    [LINES TERMINATED BY '\n']
    [IGNORE number LINES]
    [(col_name,...)]

LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中。如果指定LOCAL关键词，从客户主机读文件。如果LOCAL没指定，文件必须位于服务器上。(LOCAL在MySQL3.22.6或以后版本中可用。）

为了安全原因，当读取位于服务器上的文本文件时，文件必须处于数据库目录或可被所有人读取。另外，为了对服务器上文件使用LOAD
DATA INFILE，在服务器主机上你必须有file的权限。见6.5 由MySQL提供的权限。

如果你指定关键词LOW_PRIORITY，LOAD DATA语句的执行被推迟到没有其他客户读取表后。

使用LOCAL将比让服务器直接存取文件慢些，因为文件的内容必须从客户主机传送到服务器主机。在另一方面，你不需要file权限装载本地文件。

你也可以使用mysqlimport实用程序装载数据文件；它由发送一个LOAD
DATA INFILE命令到服务器来运作。 --local选项使得mysqlimport从客户主机上读取数据。如果客户和服务器支持压缩协议，你能指定--compress在较慢的网络上获得更好的性能。

当在服务器主机上寻找文件时，服务器使用下列规则：

  • 如果给出一个绝对路径名，服务器使用该路径名。
    •

  • 如果给出一个有一个或多个前置部件的相对路径名，服务器相对服务器的数据目录搜索文件。

    •

  • 如果给出一个没有前置部件的一个文件名，服务器在当前数据库的数据库目录寻找文件。

    •

注意这些规则意味着一个像“./myfile.txt”给出的文件是从服务器的数据目录读取，而作为“myfile.txt”给出的一个文件是从当前数据库的数据库目录下读取。也要注意，对于下列哪些语句，对db1文件从数据库目录读取，而不是db2：

mysql> USE db1;
mysql> LOAD DATA INFILE "./data.txt" INTO TABLE db2.my_table;

REPLACE和IGNORE关键词控制对现有的唯一键记录的重复的处理。如果你指定REPLACE，新行将代替有相同的唯一键值的现有行。如果你指定IGNORE，跳过有唯一键的现有行的重复行的输入。如果你不指定任何一个选项，当找到重复键键时，出现一个错误，并且文本文件的余下部分被忽略时。

如果你使用LOCAL关键词从一个本地文件装载数据，服务器没有办法在操作的当中停止文件的传输，因此缺省的行为好像IGNORE被指定一样。

LOAD DATA INFILE是SELECT ... INTO OUTFILE的逆操作，见7.12 SELECT句法。为了将一个数据库的数据写入一个文件，使用SELECT
... INTO OUTFILE，为了将文件读回数据库，使用LOAD DATA INFILE。两个命令的FIELDS和LINES子句的语法是相同的。两个子句是可选的，但是如果指定两个，FIELDS必须在LINES之前。

如果你指定一个FIELDS子句，它的每一个子句(TERMINATED
BY, [OPTIONALLY] ENCLOSED BY和ESCAPED BY)也是可选的，除了你必须至少指定他们之一。

如果你不指定一个FIELDS子句，缺省值与如果你这样写的相同：

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'

如果你不指定一个LINES子句，缺省值与如果你这样写的相同：

LINES TERMINATED BY '\n'

换句话说，缺省值导致读取输入时，LOAD DATA INFILE表现如下：

  • 在换行符处寻找行边界
    •

  • 在定位符处将行分进字段
    •

  • 不要期望字段由任何引号字符封装
    •

  • 将由“\”开头的定位符、换行符或“\”解释是字段值的部分字面字符
    •

相反，缺省值导致在写入输出时，SELECT ... INTO OUTFILE表现如下：

  • 在字段之间写定位符
    •

  • 不用任何引号字符封装字段
    •

  • 使用“\”转义出现在字段中的定位符、换行符或“\”字符
    •

  • 在行尾处写换行符
    •

注意，为了写入FIELDS ESCAPED BY '\\'，对作为一条单个的反斜线被读取的值，你必须指定2条反斜线值。

IGNORE number LINES选项可被用来忽略在文件开始的一个列名字的头：

mysql> LOAD DATA INFILE "/tmp/file_name" into table test IGNORE 1 LINES;

当你与LOAD DATA INFILE一起使用SELECT ... INTO OUTFILE将一个数据库的数据写进一个文件并且随后马上将文件读回数据库时，两个命令的字段和处理选项必须匹配，否则，LOAD
DATA INFILE将不能正确解释文件的内容。假定你使用SELECT ...
INTO OUTFILE将由逗号分隔的字段写入一个文件：

mysql> SELECT * FROM table1 INTO OUTFILE 'data.txt'
           FIELDS TERMINATED BY ','
           FROM ...

为了将由逗号分隔的文件读回来，正确的语句将是：

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
           FIELDS TERMINATED BY ',';

相反，如果你试图用下面显示的语句读取文件，它不会工作，因为它命令LOAD
DATA INFILE在字段之间寻找定位符：

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
           FIELDS TERMINATED BY '\t';

可能的结果是每个输入行将被解释为单个的字段。

LOAD DATA INFILE能被用来读取从外部来源获得的文件。例如，以dBASE格式的文件将有由逗号分隔并用双引号包围的字段。如果文件中的行由换行符终止，下面显示的命令说明你将用来装载文件的字段和行处理选项：

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
           FIELDS TERMINATED BY ',' ENCLOSED BY '"'
           LINES TERMINATED BY '\n';

任何字段或行处理选项可以指定一个空字符串('')。如果不是空，FIELDS
[OPTIONALLY] ENCLOSED BY和FIELDS ESCAPED BY值必须是一个单个字符。FIELDS
TERMINATED BY和LINES TERMINATED BY值可以是超过一个字符。例如，写入由回车换行符对（CR+LF）终止的行，或读取包含这样行的一个文件，指定一个LINES
TERMINATED BY '\r\n'子句。

FIELDS [OPTIONALLY] ENCLOSED BY控制字段的包围字符。对于输出(SELECT
... INTO OUTFILE)，如果你省略OPTIONALLY，所有的字段由ENCLOSED
BY字符包围。对于这样的输出的一个例子(使用一个逗号作为字段分隔符)显示在下面：

"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"

如果你指定OPTIONALLY，ENCLOSED BY字符仅被用于包围CHAR和VARCHAR字段：

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20

注意，一个字段值中的ENCLOSED BY字符的出现通过用ESCAPED
BY字符作为其前缀来转义。也要注意，如果你指定一个空ESCAPED
BY值，可能产生不能被LOAD DATA INFILE正确读出的输出。例如，如果转义字符为空，上面显示的输出显示如下。注意到在第四行的第二个字段包含跟随引号的一个逗号，它(错误地)好象要终止字段：

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20

对于输入，ENCLOSED BY字符如果存在，它从字段值的尾部被剥去。（不管是否指定OPTIONALLY都是这样；OPTIONALLY对于输入解释不起作用)由ENCLOSED
BY字符领先的ESCAPED BY字符出现被解释为当前字段值的一部分。另外，出现在字段中重复的ENCLOSED
BY被解释为单个ENCLOSED BY字符，如果字段本身以该字符开始。例如，如果ENCLOSED
BY '"'被指定，引号如下处理：

"The ""BIG"" boss"  -> The "BIG" boss
The "BIG" boss      -> The "BIG" boss
The ""BIG"" boss    -> The ""BIG"" boss

FIELDS ESCAPED BY控制如何写入或读出特殊字符。如果FIELDS
ESCAPED BY字符不是空的，它被用于前缀在输出上的下列字符：

  • FIELDS ESCAPED BY字符
    •

  • FIELDS [OPTIONALLY] ENCLOSED BY字符
    •

  • FIELDS TERMINATED BY和LINES TERMINATED BY值的第一个字符
    •

  • ASCII 0（实际上将后续转义字符写成 ASCII'0'，而不是一个零值字节）
    •

如果FIELDS ESCAPED BY字符是空的，没有字符被转义。指定一个空转义字符可能不是一个好主意，特别是如果在你数据中的字段值包含刚才给出的表中的任何字符。

对于输入，如果FIELDS ESCAPED BY字符不是空的，该字符的出现被剥去并且后续字符在字面上作为字段值的一个部分。例外是一个转义的“0”或“N”（即，\0或\N，如果转义字符是“\”)。这些序列被解释为ASCII
0（一个零值字节）和NULL。见下面关于NULL处理的规则。

对于更多关于“\”- 转义句法的信息，见7.1 文字：怎样写字符串和数字。

在某些情况下，字段和行处理选项相互作用：

  • 如果LINES TERMINATED BY是一个空字符串并且FIELDS TERMINATED
    BY是非空的，行也用FIELDS TERMINATED BY终止。
    •

  • 如果FIELDS TERMINATED BY和FIELDS ENCLOSED BY值都是空的('')，一个固定行(非限定的)格式被使用。用固定行格式，在字段之间不使用分隔符。相反，列值只用列的“显示”宽度被写入和读出。例如，如果列被声明为INT(7)，列的值使用7个字符的字段被写入。对于输入，列值通过读取7个字符获得。固定行格式也影响NULL值的处理；见下面。注意如果你正在使用一个多字节字符集，固定长度格式将不工作。

    •

NULL值的处理有多种，取决于你使用的FIELDS和LINES选项：

  • 对于缺省FIELDS和LINES值，对输出，NULL被写成\N，对输入，\N被作为NULL读入(假定ESCAPED
    BY字符是“\”)。
    •

  • 如果FIELDS ENCLOSED BY不是空的，包含以文字词的NULL作为它的值的字段作为一个NULL值被读入(这不同于包围在FIELDS
    ENCLOSED BY字符中的字NULL，它作为字符串'NULL'读入)。

    •

  • 如果FIELDS ESCAPED BY是空的，NULL作为字NULL被写入。

    •

  • 用固定行格式(它发生在FIELDS TERMINATED BY和FIELDS ENCLOSED
    BY都是空的时候)，NULL作为一个空字符串被写入。注意，在写入文件时，这导致NULL和空字符串在表中不能区分，因为他们都作为空字符串被写入。如果在读回文件时需要能区分这两者，你应该不使用固定行格式。

    •

一些不被LOAD DATA INFILE支持的情况：

  • 固定长度的行(FIELDS TERMINATED BY和FIELDS ENCLOSED BY都为空)和BLOB或TEXT列。

    •

  • 如果你指定一个分隔符与另一个相同，或是另一个的前缀，LOAD
    DATA INFILE不能正确地解释输入。例如，下列FIELDS子句将导致问题：

    FIELDS TERMINATED BY '"' ENCLOSED BY '"'

    •

  • 如果FIELDS ESCAPED BY是空的，一个包含跟随FIELDS
    TERMINATED BY值之后的FIELDS ENCLOSED BY或LINES TERMINATED
    BY的字段值将使得LOAD DATA INFILE过早地终止读取一个字段或行。这是因为LOAD
    DATA INFILE不能正确地决定字段或行值在哪儿结束。
    •

下列例子装载所有persondata表的行：

mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;

没有指定字段表，所以LOAD DATA INFILE期望输入行对每个表列包含一个字段。使用缺省FIELDS和LINES值。

如果你希望仅仅装载一张表的某些列，指定一个字段表：

mysql> LOAD DATA INFILE 'persondata.txt'
           INTO TABLE persondata (col1,col2,...);

如果在输入文件中的字段顺序不同于表中列的顺序，你也必须指定一个字段表。否则，MySQL不能知道如何匹配输入字段和表中的列。

如果一个行有很少的字段，对于不存在输入字段的列被设置为缺省值。缺省值赋值在7.7 CREATE TABLE句法中描述。

如果字段值缺省，空字段值有不同的解释：

  • 对于字符串类型，列被设置为空字符串。
    •

  • 对于数字类型，列被设置为0。
    •

  • 对于日期和时间类型，列被设置为该类型的适当“零”值。见7.3.6 日期和时间类型。
    •

如果列有一个NULL，或(只对第一个TIMESTAMP列)在指定一个字段表时，如果TIMESTAMP列从字段表省掉，TIMESTAMP列只被设置为当前的日期和时间。

如果输入行有太多的字段，多余的字段被忽略并且警告数字加1。

LOAD DATA INFILE认为所有的输入是字符串，因此你不能像你能用INSERT语句的ENUM或SET列的方式使用数字值。所有的ENUM和SET值必须作为字符串被指定！

如果你正在使用C API，当LOAD DATA INFILE查询完成时，你可通过调用API函数mysql_info()得到有关查询的信息。信息字符串的格式显示在下面：

Records: 1 Deleted: 0 Skipped: 0 Warnings: 0

当值通过INSERT语句插入时，在某些情况下出现警告(见7.14 INSERT句法)，除了在输入行中有太少或太多的字段时，LOAD
DATA INFILE也产生警告。警告没被存储在任何地方；警告数字仅能用于表明一切是否顺利。如果你得到警告并且想要确切知道你为什么得到他们，一个方法是使用SELECT
... INTO OUTFILE到另外一个文件并且把它与你的原版输入文件比较。

对于有关INSERT相对LOAD DATA INFILE的效率和加快LOAD
DATA INFILE的更多信息，见10.5.6
加速INSERT查询。

7.17 UPDATE句法

UPDATE [LOW_PRIORITY] tbl_name SET col_name1=expr1,col_name2=expr2,...
    [WHERE where_definition] [LIMIT #]

UPDATE用新值更新现存表中行的列，SET子句指出哪个列要修改和他们应该被给定的值，WHERE子句，如果给出，指定哪个行应该被更新，否则所有行被更新。

如果你指定关键词LOW_PRIORITY，执行UPDATE被推迟到没有其他客户正在读取表时。

如果你从一个表达式的tbl_name存取列，UPDATE使用列的当前值。例如，下列语句设置age为它的当前值加1：

mysql> UPDATE persondata SET age=age+1;

UPDATE赋值是从左到右计算。例如，下列语句两倍age列，然后加1：

mysql> UPDATE persondata SET age=age*2, age=age+1;

如果你设置列为其它当前有的值，MySQL注意到这点并且不更新它。

UPDATE返回实际上被改变的行的数量。在MySQL
3.22或以后版本中，C API函数mysql_info()返回被匹配并且更新的行数和在UPDATE期间发生警告的数量。

在MySQL3.23中，你可使用LIMIT #来保证只有一个给定数量的行被改变。

7.18 USE句法

USE db_name

USE db_name语句告诉MySQL使用db_name数据库作为随后的查询的缺省数据库。数据库保持到会话结束，或发出另外一个USE语句：

mysql> USE db1;
mysql> SELECT count(*) FROM mytable;      # selects from db1.mytable
mysql> USE db2;
mysql> SELECT count(*) FROM mytable;      # selects from db2.mytable

利用USE语句使得一个特定的数据库称为当前数据库并不阻止你访问在另外的数据库中的表。下面的例子访问db1数据库中的author表和db2数据库中的editor表：

mysql> USE db1;
mysql> SELECT author_name,editor_name FROM author,db2.editor
           WHERE author.editor_id = db2.editor.editor_id;

USE语句提供了Sybase的兼容性。

7.19 FLUSH句法(清除缓存）

FLUSH flush_option [,flush_option]

如果你想要清除一些MySQL使用内部缓存，你应该使用FLUSH命令。为了执行FLUSH，你必须有reload权限。

flush_option可以是下列任何东西：

HOSTS | 清空主机缓存表。如果你的某些主机改变IP数字，或如果你得到错误消息Host ... is blocked，你应该清空主机表。当在连接MySQL服务器时，对一台给定的主机有多于max_connect_errors个错误连续不断地发生，MySQL认定某些东西错了并且阻止主机进一步的连接请求。清空主机表允许主机再尝试连接。见18.2.3 Host '...' is blocked错误)。你可用-O max_connection_errors=999999999启动mysqld来避免这条错误消息。
LOGS | 关闭并且再打开标准和更新记录文件。如果你指定了一个没有扩展名的更新记录文件，新的更新记录文件的扩展数字将相对先前的文件加1。
PRIVILEGES | 从mysql数据库授权表中重新装载权限。
TABLES | 关闭所有打开的表。
STATUS | 重置大多数状态变量到0。

你也可以用mysqladmin实用程序，使用flush-hosts, flush-logs,
reload或flush-tables命令来访问上述的每一个命令。

7.20 KILL句法

KILL thread_id

每个对mysqld的连接以一个单独的线程运行。你可以用看SHOW
PROCESSLIST命令察看哪个线程正在运行，并且用KILL thread_id命令杀死一个线程。

如果你有process权限，你能看到并且杀死所有线程。否则，你只能看到并且杀死你自己的线程。

你也可以使用mysqladmin processlist和mysqladmin kill命令检查并杀死线程。

7.21 SHOW句法 (得到表，列等的信息）

   SHOW DATABASES [LIKE wild]
or SHOW TABLES [FROM db_name] [LIKE wild]
or SHOW COLUMNS FROM tbl_name [FROM db_name] [LIKE wild]
or SHOW INDEX FROM tbl_name [FROM db_name]
or SHOW STATUS
or SHOW VARIABLES [LIKE wild]
or SHOW [FULL] PROCESSLIST
or SHOW TABLE STATUS [FROM db_name] [LIKE wild]
or SHOW GRANTS FOR user

SHOW提供关于数据库、桌子、列或服务器的信息。如果使用LIKE
wild部分，wild字符串可以是一个使用SQL的“%”和“_”通配符的字符串。

你能使用db_name.tbl_name作为tbl_name FROM db_name句法的另一种选择。这两个语句是相等的：

mysql> SHOW INDEX FROM mytable FROM mydb;
mysql> SHOW INDEX FROM mydb.mytable;

SHOW DATABASES列出在MySQL服务器主机上的数据库。你也可以用mysqlshow命令得到这张表。

SHOW TABLES列出在一个给定的数据库中的表。你也可以用mysqlshow
db_name命令得到这张表。

注意：如果一个用户没有一个表的任何权限，表将不在SHOW
TABLES或mysqlshow db_name中的输出中显示。

SHOW COLUMNS列出在一个给定表中的列。如果列类型不同于你期望的是基于CREATE
TABLE语句的那样，注意，MySQL有时改变列类型。见7.7.1 隐含的列说明变化。

DESCRIBE语句提供了类似SHOW COLUMNS的信息。见7.23 DESCRIBE 句法 (得到列的信息）。

SHOW TABLE STATUS（在版本3.23引入)运行类似SHOW STATUS，但是提供每个表的更多信息。你也可以使用mysqlshow
--status db_name命令得到这张表。下面的列被返回：

列 | 含义
Name | 表名
Type | 表的类型 (ISAM，MyISAM或HEAP)
Row_format | 行存储格式 (固定, 动态, 或压缩）
Rows | 行数量
Avg_row_length | 平均行长度
Data_length | 数据文件的长度
Max_data_length | 数据文件的最大长度
Index_length | 索引文件的长度
Data_free | 已分配但未使用了字节数
Auto_increment | 下一个 autoincrement(自动加1）值
Create_time | 表被创造的时间
Update_time | 数据文件最后更新的时间
Check_time | 最后对表运行一个检查的时间
Create_options | 与CREATE TABLE一起使用的额外选项
Comment | 当创造表时，使用的注释 (或为什么MySQL不能存取表信息的一些信息)。

SHOW FIELDS是SHOW COLUMNS一个同义词，SHOW KEYS是SHOW
INDEX一个同义词。你也可以用mysqlshow db_name tbl_name或mysqlshow
-k db_name tbl_name 列出一张表的列或索引。

SHOW INDEX以非常相似于ODBC的SQLStatistics调用的格式返回索引信息。下面的列被返回：

列 | 含义
Table | 表名
Non_unique | 0，如果索引不能包含重复。
Key_name | 索引名
Seq_in_index | 索引中的列顺序号, 从 1 开始。
Column_name | 列名。
Collation | 列怎样在索引中被排序。在MySQL中，这可以有值A（升序) 或NULL（不排序)。
Cardinality | 索引中唯一值的数量。这可通过运行isamchk -a更改.
Sub_part | 如果列只是部分被索引，索引字符的数量。NULL，如果整个键被索引。

SHOW STATUS提供服务器的状态信息(象mysqladmin
extended-status一样)。输出类似于下面的显示，尽管格式和数字可以有点不同：

+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| Aborted_clients          | 0      |
| Aborted_connects         | 0      |
| Connections              | 17     |
| Created_tmp_tables       | 0      |
| Delayed_insert_threads   | 0      |
| Delayed_writes           | 0      |
| Delayed_errors           | 0      |
| Flush_commands           | 2      |
| Handler_delete           | 2      |
| Handler_read_first       | 0      |
| Handler_read_key         | 1      |
| Handler_read_next        | 0      |
| Handler_read_rnd         | 35     |
| Handler_update           | 0      |
| Handler_write            | 2      |
| Key_blocks_used          | 0      |
| Key_read_requests        | 0      |
| Key_reads                | 0      |
| Key_write_requests       | 0      |
| Key_writes               | 0      |
| Max_used_connections     | 1      |
| Not_flushed_key_blocks   | 0      |
| Not_flushed_delayed_rows | 0      |
| Open_tables              | 1      |
| Open_files               | 2      |
| Open_streams             | 0      |
| Opened_tables            | 11     |
| Questions                | 14     |
| Slow_queries             | 0      |
| Threads_connected        | 1      |
| Threads_running          | 1      |
| Uptime                   | 149111 |
+--------------------------+--------+

上面列出的状态变量有下列含义：

Aborted_clients | 由于客户没有正确关闭连接已经死掉，已经放弃的连接数量。
Aborted_connects | 尝试已经失败的MySQL服务器的连接的次数。
Connections | 试图连接MySQL服务器的次数。
Created_tmp_tables | 当执行语句时，已经被创造了的隐含临时表的数量。
Delayed_insert_threads | 正在使用的延迟插入处理器线程的数量。
Delayed_writes | 用INSERT DELAYED写入的行数。
Delayed_errors | 用INSERT DELAYED写入的发生某些错误(可能重复键值)的行数。
Flush_commands | 执行FLUSH命令的次数。
Handler_delete | 请求从一张表中删除行的次数。
Handler_read_first | 请求读入表中第一行的次数。
Handler_read_key | 请求数字基于键读行。
Handler_read_next | 请求读入基于一个键的一行的次数。
Handler_read_rnd | 请求读入基于一个固定位置的一行的次数。
Handler_update | 请求更新表中一行的次数。
Handler_write | 请求向表中插入一行的次数。
Key_blocks_used | 用于关键字缓存的块的数量。
Key_read_requests | 请求从缓存读入一个键值的次数。
Key_reads | 从磁盘物理读入一个键值的次数。
Key_write_requests | 请求将一个关键字块写入缓存次数。
Key_writes | 将一个键值块物理写入磁盘的次数。
Max_used_connections | 同时使用的连接的最大数目。
Not_flushed_key_blocks | 在键缓存中已经改变但是还没被清空到磁盘上的键块。
Not_flushed_delayed_rows | 在INSERT DELAY队列中等待写入的行的数量。
Open_tables | 打开表的数量。
Open_files | 打开文件的数量。
Open_streams | 打开流的数量(主要用于日志记载）
Opened_tables | 已经打开的表的数量。
Questions | 发往服务器的查询的数量。
Slow_queries | 要花超过long_query_time时间的查询数量。
Threads_connected | 当前打开的连接的数量。
Threads_running | 不在睡眠的线程数量。
Uptime | 服务器工作了多少秒。

关于上面的一些注释：

  • 如果Opened_tables太大，那么你的table_cache变量可能太小。

    •

  • 如果key_reads太大，那么你的key_cache可能太小。缓存命中率可以用key_reads/key_read_requests计算。

    •

  • 如果Handler_read_rnd太大，那么你很可能有大量的查询需要MySQL扫描整个表或你有没正确使用键值的联结(join)。

    •

SHOW VARIABLES显示出一些MySQL系统变量的值，你也能使用mysqladmin
variables命令得到这个信息。如果缺省值不合适，你能在mysqld启动时使用命令行选项来设置这些变量的大多数。输出类似于下面的显示，尽管格式和数字可以有点不同：

+------------------------+--------------------------+
| Variable_name          | Value                    |
+------------------------+--------------------------+
| back_log               | 5                        |
| connect_timeout        | 5                        |
| basedir                | /my/monty/               |
| datadir                | /my/monty/data/          |
| delayed_insert_limit   | 100                      |
| delayed_insert_timeout | 300                      |
| delayed_queue_size     | 1000                     |
| join_buffer_size       | 131072                   |
| flush_time             | 0                        |
| interactive_timeout    | 28800                    |
| key_buffer_size        | 1048540                  |
| language               | /my/monty/share/english/ |
| log                    | OFF                      |
| log_update             | OFF                      |
| long_query_time        | 10                       |
| low_priority_updates   | OFF                      |
| max_allowed_packet     | 1048576                  |
| max_connections        | 100                      |
| max_connect_errors     | 10                       |
| max_delayed_threads    | 20                       |
| max_heap_table_size    | 16777216                 |
| max_join_size          | 4294967295               |
| max_sort_length        | 1024                     |
| max_tmp_tables         | 32                       |
| net_buffer_length      | 16384                    |
| port                   | 3306                     |
| protocol-version       | 10                       |
| record_buffer          | 131072                   |
| skip_locking           | ON                       |
| socket                 | /tmp/mysql.sock          |
| sort_buffer            | 2097116                  |
| table_cache            | 64                       |
| thread_stack           | 131072                   |
| tmp_table_size         | 1048576                  |
| tmpdir                 | /machine/tmp/            |
| version                | 3.23.0-alpha-debug       |
| wait_timeout           | 28800                    |
+------------------------+--------------------------+

见10.2.3 调节服务器参数。

SHOW PROCESSLIST显示哪个线程正在运行，你也能使用mysqladmin
processlist命令得到这个信息。如果你有process权限，
你能看见所有的线程，否则，你仅能看见你自己的线程。见7.20 KILL句法。如果你不使用FULL选项，那么每个查询只有头100字符被显示出来。

SHOW GRANTS FOR user列出对一个用户必须发出以重复授权的授权命令。

mysql> SHOW GRANTS FOR root@localhost;
+---------------------------------------------------------------------+
| Grants for root@localhost                                           |
+---------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root''localhost' WITH GRANT OPTION  |
+---------------------------------------------------------------------+

7.22 EXPLAIN句法(得到关于SELECT的信息)

    EXPLAIN tbl_name
or  EXPLAIN SELECT select_options

EXPLAIN tbl_name是DESCRIBE tbl_name或SHOW COLUMNS
FROM tbl_name的一个同义词。

当你在一条SELECT语句前放上关键词EXPLAIN，MySQL解释它将如何处理SELECT，提供有关表如何联结和以什么次序联结的信息。

借助于EXPLAIN，你可以知道你什么时候必须为表加入索引以得到一个使用索引找到记录的更快的SELECT。你也能知道优化器是否以一个最佳次序联结表。为了强制优化器对一个SELECT语句使用一个特定联结次序，增加一个STRAIGHT_JOIN子句。

对于非简单的联结，EXPLAIN为用于SELECT语句中的每个表返回一行信息。表以他们将被读入的顺序被列出。MySQL用一边扫描多次联结的方式解决所有联结，这意味着MySQL从第一个表中读一行，然后找到在第二个表中的一个匹配行，然后在第3个表中等等。当所有的表被处理完，它输出选择的列并且回溯表列表直到找到一个表有更多的匹配行，从该表读入下一行并继续处理下一个表。

从EXPLAIN的输出包括下面列：

table

输出的行所引用的表。

type

联结类型。各种类型的信息在下面给出。

possible_keys

possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意，该列完全独立于表的次序。这意味着在possible_keys中的某些键实际上不能以生成的表次序使用。如果该列是空的，没有相关的索引。在这种情况下，你也许能通过检验WHERE子句看是否它引用某些列或列不是适合索引来提高你的查询性能。如果是这样，创造一个适当的索引并且在用EXPLAIN检查查询。见7.8 ALTER TABLE句法。为了看清一张表有什么索引，使用SHOW
    INDEX FROM tbl_name。

key

key列显示MySQL实际决定使用的键。如果没有索引被选择，键是NULL。

key_len

key_len列显示MySQL决定使用的键长度。如果键是NULL，长度是NULL。注意这告诉我们MySQL将实际使用一个多部键值的几个部分。

ref

ref列显示哪个列或常数与key一起用于从表中选择行。

rows

rows列显示MySQL相信它必须检验以执行查询的行数。

Extra

如果Extra列包括文字Only index，这意味着信息只用索引树中的信息检索出的。通常，这比扫描整个表要快。如果Extra列包括文字where
    used，它意味着一个WHERE子句将被用来限制哪些行与下一个表匹配或发向客户。

不同的联结类型列在下面，以最好到最差类型的次序：

system

桌子仅有一行(=系统表)。这是const联结类型的一个特例。

const

桌子有最多一个匹配行，它将在查询开始时被读取。因为仅有一行，在这行的列值可被剩下的优化器认为是常数。
    const表很快，因为它们只读取一次！

eq_ref

对于每个来自于先前的表的行组合，从该表中读取一行。这可能是最好的联结类型，除了const类型。它用在一个索引的所有部分被联结使用并且索引是UNIQUE或PRIMARY
    KEY。

ref

对于每个来自于先前的表的行组合，所有有匹配索引值的行将从这张表中读取。如果联结只使用键的最左面前缀，或如果键不是UNIQUE或PRIMARY
    KEY（换句话说，如果联结不能基于键值选择单个行的话)，使用ref。如果被使用的键仅仅匹配一些行，该联结类型是不错的。

range

只有在一个给定范围的行将被检索，使用一个索引选择行。ref列显示哪个索引被使用。

index

这与ALL相同，除了只有索引树被扫描。这通常比ALL快，因为索引文件通常比数据文件小。

ALL

对于每个来自于先前的表的行组合，将要做一个完整的表扫描。如果表格是第一个没标记const的表，这通常不好，并且通常在所有的其他情况下很差。你通常可以通过增加更多的索引来避免ALL，使得行能从早先的表中基于常数值或列值被检索出。

通过相乘EXPLAIN输出的rows行的所有值，你能得到一个关于一个联结要多好的提示。这应该粗略地告诉你MySQL必须检验多少行以执行查询。当你使用max_join_size变量限制查询时，也用这个数字。见10.2.3 调节服务器参数。

下列例子显示出一个JOIN如何能使用EXPLAIN提供的信息逐步被优化。

假定你有显示在下面的SELECT语句，你使用EXPLAIN检验：

EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
            tt.ProjectReference, tt.EstimatedShipDate,
            tt.ActualShipDate, tt.ClientID,
            tt.ServiceCodes, tt.RepetitiveID,
            tt.CurrentProcess, tt.CurrentDPPerson,
            tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
            et_1.COUNTRY, do.CUSTNAME
        FROM tt, et, et AS et_1, do
        WHERE tt.SubmitTime IS NULL
            AND tt.ActualPC = et.EMPLOYID
            AND tt.AssignedPC = et_1.EMPLOYID
            AND tt.ClientID = do.CUSTNMBR;

对于这个例子，假定：

  • 被比较的列被声明如下：

        表
         | 列
         | 列类型

        tt
         | ActualPC
         | CHAR(10)

        tt
         | AssignedPC
         | CHAR(10)

        tt
         | ClientID
         | CHAR(10)

        et
         | EMPLOYID
         | CHAR(15)

        do
         | CUSTNMBR
         | CHAR(15)

    •

  • 表有显示在下面的索引：

        表
         | 索引

        tt
         | ActualPC

        tt
         | AssignedPC

        tt
         | ClientID

        et
         | EMPLOYID（主键）

        do
         | CUSTNMBR（主键）

    •

  • tt.ActualPC值不是均匀分布的。
    •

开始，在任何优化被施行前，EXPLAIN语句产生下列信息：

table type possible_keys                key  key_len ref  rows  Extra
et    ALL  PRIMARY                      NULL NULL    NULL 74
do    ALL  PRIMARY                      NULL NULL    NULL 2135
et_1  ALL  PRIMARY                      NULL NULL    NULL 74
tt    ALL  AssignedPC,ClientID,ActualPC NULL NULL    NULL 3872
      range checked for each record (key map: 35)

因为type对每张表是ALL，这个输出显示MySQL正在对所有表进行一个完整联结！这将花相当长的时间，因为必须检验每张表的行数的乘积次数！对于一个实例，这是74
* 2135 * 74 * 3872 = 45,268,558,720行。如果表更大，你只能想象它将花多长时间……

如果列声明不同，这里的一个问题是MySQL(还)不能高效地在列上使用索引。在本文中，VARCHAR和CHAR是相同的，除非他们声明为不同的长度。因为tt.ActualPC被声明为CHAR(10)并且et.EMPLOYID被声明为CHAR(15)，有一个长度失配。

为了修正在列长度上的不同，使用ALTER TABLE将ActualPC的长度从10个字符变为15个字符：

mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);

现在tt.ActualPC和et.EMPLOYID都是VARCHAR(15)，再执行EXPLAIN语句产生这个结果：

table type   possible_keys   key     key_len ref         rows    Extra
tt    ALL    AssignedPC,ClientID,ActualPC NULL NULL NULL 3872    where used
do    ALL    PRIMARY         NULL    NULL    NULL        2135
      range checked for each record (key map: 1)
et_1  ALL    PRIMARY         NULL    NULL    NULL        74
      range checked for each record (key map: 1)
et    eq_ref PRIMARY         PRIMARY 15      tt.ActualPC 1

这不是完美的，但是是好一些了(rows值的乘积少了一个74一个因子)，这个版本在几秒内执行。

第2种改变能消除tt.AssignedPC = et_1.EMPLOYID和tt.ClientID =
do.CUSTNMBR比较的列的长度失配：

mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
                      MODIFY ClientID   VARCHAR(15);

现在EXPLAIN产生的输出显示在下面：

table type   possible_keys   key     key_len ref            rows     Extra
et    ALL    PRIMARY         NULL    NULL    NULL           74
tt    ref    AssignedPC,ClientID,ActualPC ActualPC 15 et.EMPLOYID 52 where used
et_1  eq_ref PRIMARY         PRIMARY 15      tt.AssignedPC  1
do    eq_ref PRIMARY         PRIMARY 15      tt.ClientID    1

这“几乎”象它能得到的一样好。

剩下的问题是，缺省地，MySQL假设在tt.ActualPC列的值是均匀分布的，并且对tt表不是这样。幸好，很容易告诉MySQL关于这些：

shell> myisamchk --analyze PATH_TO_MYSQL_DATABASE/tt
shell> mysqladmin refresh

现在联结是“完美”的了，而且EXPLAIN产生这个结果：

table type   possible_keys   key     key_len ref            rows    Extra
tt    ALL    AssignedPC,ClientID,ActualPC NULL NULL NULL    3872    where used
et    eq_ref PRIMARY         PRIMARY 15      tt.ActualPC    1
et_1  eq_ref PRIMARY         PRIMARY 15      tt.AssignedPC  1
do    eq_ref PRIMARY         PRIMARY 15      tt.ClientID    1

注意在从EXPLAIN输出的rows列是一个来自MySQL联结优化器的“教育猜测”；为了优化查询，你应该检查数字是否接近事实。如果不是，你可以通过在你的SELECT语句里面使用STRAIGHT_JOIN并且试着在在FROM子句以不同的次序列出表，可能得到更好的性能。

7.23 DESCRIBE句法 (得到列的信息）

{DESCRIBE | DESC} tbl_name {col_name | wild}

DESCRIBE提供关于一张表的列的信息。col_name可以是一个列名字或包含SQL的“%”和“_”通配符的一个字符串。

如果列类型不同于你期望的是基于一个CREATE TABLE语句，注意MySQL有时改变列类型。见7.7.1 隐含的列说明变化。

这个语句为了与 Oracle 兼容而提供的。

SHOW语句提供类似的信息。见7.21
SHOW句法(得到表，列的信息)。

7.24 LOCK TABLES/UNLOCK
TABLES句法

LOCK TABLES tbl_name [AS alias] {READ | [LOW_PRIORITY] WRITE}
            [, tbl_name {READ | [LOW_PRIORITY] WRITE} ...]
...
UNLOCK TABLES

LOCK TABLES为当前线程锁定表。UNLOCK TABLES释放被当前线程持有的任何锁。当线程发出另外一个LOCK
TABLES时，或当服务器的连接被关闭时，当前线程锁定的所有表自动被解锁。

如果一个线程获得在一个表上的一个READ锁，该线程(和所有其他线程)只能从表中读。如果一个线程获得一个表上的一个WRITE锁，那么只有持锁的线程READ或WRITE表，其他线程被阻止。

每个线程等待(没有超时)直到它获得它请求的所有锁。

WRITE锁通常比READ锁有更高的优先级，以确保更改尽快被处理。这意味着，如果一个线程获得READ锁，并且然后另外一个线程请求一个WRITE锁,
随后的READ锁请求将等待直到WRITE线程得到了锁并且释放了它。当线程正在等待WRITE锁时，你可以使用LOW_PRIORITY
WRITE允许其他线程获得READ锁。如果你肯定终于有个时刻没有线程将有一个READ锁，你应该只使用LOW_PRIORITY
WRITE。

当你使用LOCK TABLES时，你必须锁定你将使用的所有表！如果你正在一个查询中多次使用一张表(用别名)，你必须对每个别名得到一把锁！这条政策保证表锁定不会死锁。

注意你应该不锁定任何你正在用INSERT DELAYED使用的表，这是因为在这种情况下，INSERT被一个不同的线程执行。

通常，你不必锁定表，因为所有单个UPDATE语句是原语；没有其他线程能防碍任何其它正在执行SQL语句的线程。当你想锁定表，有一些情况：

  • 如果你将在一堆表上运行许多操作，锁定你将使用的表是较快的。当然缺点是，没有其他线程能更新一个READ锁定的表并且没有其他线程能读一个WRITE-锁定的表。

    •

  • MySQL不支持事务环境，所以如果你想要保证在一个SELECT和一个UPDATE之间没有其他线程到来，你必须使用LOCK
    TABLES。下面显示的例子要求LOCK TABLES以便安全地执行：

    mysql> LOCK TABLES trans READ, customer WRITE;
mysql> select sum(value) from trans where customer_id= some_id;
mysql> update customer set total_value=sum_from_previous_statement
           where customer_id=some_id;
mysql> UNLOCK TABLES;

    •

没有LOCK TABLES，另外一个线程可能有一个机会在执行SELECT和UPDATE语句之间往trans表中插入一个新行。

通过使用渐增更改(UPDATE customer SET value=value+new_value)或LAST_INSERT_ID()函数，在很多情况下你能使用LOCK
TABLES来避免。

你也可以使用用户级锁定函数GET_LOCK()和RELEASE_LOCK()解决一些情况，这些锁保存在服务器的一张哈希表中并且用pthread_mutex_lock()和pthread_mutex_unlock()实现以获得高速度。见7.4.12 其他函数。

有关锁定政策的更多信息，见10.2.8 MySQL 怎样锁定表。

7.25 SET OPTION句法

SET [OPTION] SQL_VALUE_OPTION= value, ...

SET OPTION设置影响服务器或你的客户操作的各种选项。你设置的任何选择保持有效直到当前会话结束，或直到你设置选项为不同的值。

CHARACTER SET character_set_name | DEFAULT

这用给定的映射表从/到客户映射所有字符串。对character_set_name当前唯一的选项是
    cp1251_koi8，但是你能容易通过编辑在MySQL源代码分发的“sql/convert.cc”文件增加新的映射。缺省映射能用character_set_name的DEFAULT值恢复。注意设置CHARACTER
    SET选项的语法不同于设置其他选项目的语法。

PASSWORD = PASSWORD('some password')

设置当前用户的口令。任何非匿名的用户能改变他自己的口令！

PASSWORD FOR user = PASSWORD('some password')

设置当前服务器主机上的一个特定用户的口令。只有具备存取mysql数据库的用户可以这样做。用户应该以user@hostname格式给出，这里user和hostname完全与他们列在mysql.user表条目的User和Host列一样。例如，如果你有一个条目其User和Host字段是'bob'和'%.loc.gov'，你将写成：

mysql> SET PASSWORD FOR bob@"%.loc.gov" = PASSWORD("newpass");

或

mysql> UPDATE mysql.user SET password=PASSWORD("newpass") where user="bob' and host="%.loc.gov";

SQL_AUTO_IS_NULL = 0 | 1

如果设置为1（缺省 )，那么对于一个具有一个自动加1的行的表，用下列构件能找出最后插入的行：WHERE
    auto_increment_column IS NULL。这被一些 ODBC 程序入Access使用。

SQL_BIG_TABLES = 0 | 1

如果设置为1，所有临时表存在在磁盘上而非内存中。这将更慢一些，但是对需要大的临时表的大SELECT操作，你将不会得到The
    table tbl_name is full的错误。对于一个新连接的缺省值是0（即，使用内存中的临时表)。

SQL_BIG_SELECTS = 0 | 1

如果设置为0，如果一个SELECT尝试可能花很长的时间，MySQL将放弃。这在一个不妥当的WHERE语句发出时是有用的。一个大的查询被定义为一个将可能必须检验多于max_join_size行的SELECT。对一个新连接的缺省值是1（它将允许所有SELECT语句)。

SQL_LOW_PRIORITY_UPDATES = 0 | 1

如果设置为1，所有INSERT、UPDATE、DELETE和LOCK
    TABLE WRITE语句等待，直到在受影响的表上没有未解决的SELECT或LOCK
    TABLE READ。

SQL_SELECT_LIMIT = value | DEFAULT

从SELECT语句返回的记录的最大数量。如果一个SELECT有一个LIMIT子句，LIMIT优先与SQL_SELECT_LIMIT值。对一个新连接的缺省值是“无限”的。如果你改变了限制，缺省值能用SQL_SELECT_LIMIT的一个DEFAULT值恢复。

SQL_LOG_OFF = 0 | 1

如果设置为1，如果客户有process权限，对该客户没有日志记载到标准的日志文件中。这不影响更新日志记录！

SQL_LOG_UPDATE = 0 | 1

如果设置为0, 如果客户有process权限，对该客户没有日志记载到更新日志中。这不影响标准日志文件！

TIMESTAMP = timestamp_value | DEFAULT

为该客户设置时间。如果你使用更新日志恢复行，这被用来得到原来的时间标记。

LAST_INSERT_ID = #

设置从LAST_INSERT_ID()返回的值。当你在更新一个表的命令中使用LAST_INSERT_ID()时，它存储在更新日志中。

INSERT_ID = #

设置当插入一个AUTO_INCREMENT值时，由INSERT命令使用的值。这主要与更新日志一起使用。

7.26 GRANT和REVOKE句法

GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...]
    ON {tbl_name | * | *.* | db_name.*}
    TO user_name [IDENTIFIED BY 'password']
        [, user_name [IDENTIFIED BY 'password'] ...]
    [WITH GRANT OPTION]

REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
    ON {tbl_name | * | *.* | db_name.*}
    FROM user_name [, user_name ...]

GRANT在MySQL 3.22.11或以后版本中实现。对于更早MySQL版本，GRANT语句不做任何事情。

GRANT和REVOKE命令允许系统主管在4个权限级别上授权和撤回赋予MySQL用户的权利：

全局级别

全局权限作用于一个给定服务器上的所有数据库。这些权限存储在mysql.user表中。

数据库级别

数据库权限作用于一个给定数据库的所有表。这些权限存储在mysql.db和mysql.host表中。

表级别

表权限作用于一个给定表的所有列。这些权限存储在mysql.tables_priv表中。

列级别

列权限作用于在一个给定表的单个列。这些权限存储在mysql.columns_priv表中。

对于GRANT如何工作的例子，见6.11 为MySQL增加新的用户权限。

对于GRANT和REVOKE语句，priv_type可以指定下列的任何一个：

ALL PRIVILEGES      FILE                RELOAD
ALTER               INDEX               SELECT
CREATE              INSERT              SHUTDOWN
DELETE              PROCESS             UPDATE
DROP                REFERENCES          USAGE

ALL是ALL PRIVILEGES的一个同义词，REFERENCES还没被实现，USAGE当前是“没有权限”的一个同义词。它能用在你想要创建一个没有权限用户的时候。

为了从一个用户撤回grant的权限，使用GRANT OPTION的一个priv_type值：

REVOKE GRANT OPTION ON ... FROM ...;

对于表，你能指定的唯一priv_type值是SELECT、INSERT、UPDATE、DELETE、CREATE、DROP、GRANT、INDEX和ALTER。

对于列，你能指定的唯一priv_type值是(即，当你使用一个column_list子句时)是SELECT、INSERT和UPDATE。

你能通过使用ON *.*语法设置全局权限，你能通过使用ON
db_name.*语法设置数据库权限。如果你指定ON *并且你有一个当前数据库，你将为该数据库设置权限。(警告：如果你指定ON
*而你没有一个当前数据库，你将影响全局权限！）

为了容纳对任意主机的用户授予的权利，MySQL支持以user@host格式指定user_name值。如果你想要指定一个特殊字符的一个user字符串(例如“-”)，或一个包含特殊字符或通配符的host字符串(例如“%”)，你可以用括号括起能用户或主机名字
(例如，'test-user'@'test-hostname')。

你能在主机名中指定通配符。例如，user@"%.loc.gov"适用于在loc.gov域中任何主机的user，并且user@"144.155.166.%"适用于在144.155.166类
C 子网中任何主机的user。

简单形式的user是user@"%"的一个同义词。注意：如果你允许匿名用户连接MySQL服务器(它是缺省的)，你也应该增加所有本地用户如user@localhost，因为否则，当用户试图从本地机器上登录到MySQL服务器时，对于mysql.user表中的本地主机的匿名用户条目将被使用！匿名用户通过插入有User=''的条目到mysql.user表中来定义。通过执行这个查询，你可以检验它是否作用于你：

mysql> SELECT Host,User FROM mysql.user WHERE User='';

目前，GRANT仅支持最长60个字符的主机、表、数据库和列名。一个用户名字能最多到16个字符。

对与一个表或列的权限是由4个权限级别的逻辑或形成的。例如，如果mysql.user表指定一个用户有一个全局select权限，它不能被数据库、表或列的一个条目否认。

对于一个列的权限能如下计算：

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges

在大多数情况下，你只授予用户一个权限级别上的权限，因此现实通常不象上面所说的那样复杂。:)
权限检查过程的细节在6
MySQL 存取权限系统中给出。

如果你为一个在mysql.user表中不存在的用户/主机名组合授权，一个条目被增加并且保留直到用一个DELETE命令删除。换句话说，GRANT可以创建user表的条目，但是REVOKE将不删除；你必须明确地使用DELETE删除.

在MySQL 3.22.12或以后，如果创建一个新用户或如果你有全局授予权限，用户的口令将被设置为由IDENTIFIED
BY子句指定的口令，如果给出一个。如果用户已经有了一个口令，它被一个新的代替。

警告：如果你创造一个新用户但是不指定一个IDENTIFIED
BY子句，用户没有口令。这是不安全的。

口令也能用SET PASSWORD命令设置。见7.25 SET OPTION句法。

如果你为一个数据库授权，如果需要在mysql.db表中创建一个条目。当所有为数据库的授权用REVOKE删除时，这个条目被删除。

如果一个用户没有在一个表上的任何权限，当用户请求一系列表时，表不被显示(例如，用一个SHOW
TABLES语句)。

WITH GRANT OPTION子句给与用户有授予其他用户在指定的权限水平上的任何权限的能力。你应该谨慎对待你授予他grant权限的用户，因为具有不同权限的两个用户也许能合并权限！

你不能授予其他用户你自己不具备的权限； agree权限允许你放弃你仅仅拥有的那些权限。

要知道，当你将一个特定权限级别上的grant授予其他用户，用户已经拥有(或在未来被授予！)的在该级别上的任何权限也可由该用户授权。假定你授权一个用户在一个数据库上的insert权限，那么如果你授权在数据库上select权限并且指定WITH
GRANT OPTION，用户能不仅放弃select权限，还有insert。如果你授权用户在数据库上的update权限，用户能放弃insert、select和update。

你不应该将alter权限授予一个一般用户。如果你这样做，用户可以通过重命名表试图颠覆权限系统！

注意，如果你正在使用即使一个用户的表或列的权限，服务器要检查所有用户的表和列权限并且这将使MySQL慢下来一点。

当mysqld启动时，所有的权限被读入存储器。数据库、表和列权限马上生效，而用户级权限在下一次用户连接时生效。你用GRANT或REVOKE对受权表执行的更改立即被服务器知晓。如果你手工修改授权表(使用INSERT、UPDATE等等)，你应该执行一个FLUSH
PRIVILEGES语句或运行mysqladmin flush-privileges告诉服务器再次装载授权表。见6.9 权限变化何时生效。

ANSI SQL版本的GRANT与MySQL版本之间的最大差别：

  • ANSI SQL 没有全局或数据库级别权限，并且 ANSI SQL 不支持所有MySQL支持的权限。

    •

  • 当你在 ANSI SQL 抛弃一张表时，表的所有权限均被撤消。如果你在
    ANSI SQL 撤销权限，所有基于该权限的授权也被也被撤消。在MySQL中，权限只能用明确的REVOKE命令或操作MySQL授权表抛弃。

    •

7.27　CREATE INDEX句法

CREATE [UNIQUE] INDEX index_name ON tbl_name (col_name[(length)],... )

CREATE INDEX语句在MySQL版本 3.22
以前不做任何事情。在 3.22 或以后版本中，CREATE INDEX被映射到一个ALTER
TABLE语句来创建索引。见7.8
ALTER TABLE句法。

通常，你在用CREATE TABLE创建表本身时创建表的所有索引。见7.7 CREATE TABLE句法。CREATE
INDEX允许你把索引加到现有表中。

一个(col1,col2,...)形式的列表创造一个多列索引。索引值有给定列的值串联而成。

对于CHAR和VARCHAR列，索引可以只用一个列的部分来创建，使用col_name(length)句法。（在BLOB和TEXT列上需要长度)。下面显示的语句使用name列的头10个字符创建一个索引：

mysql> CREATE INDEX part_of_name ON customer (name(10));

因为大多数名字通常在头10个字符不同，这个索引应该不比从整个name列的创建的索引慢多少。另外，在索引使用部分的列能使这个索引成为更小的文件大部分, 它能保存很多磁盘空格并且可能也加快INSERT操作！

注意，如果你正在使用MySQL版本 3.23.2
或更新并且正在使用MyISAM桌子类型，你只能在可以有NULL值的列或一个BLOB/TEXT列上增加一个索引，

关于MySQL如何使用索引的更多信息，见10.4 MySQL索引的使用。

7.28 DROP INDEX句法

DROP INDEX index_name ON tbl_name

DROP INDEX从tbl_name表抛弃名为index_name的索引。DROP
INDEX在MySQL 3.22 以前的版本中不做任何事情。在 3.22
或以后，DROP INDEX被映射到一个ALTER TABLE语句来抛弃索引。见7.8 ALTER TABLE句法。

7.29 注释句法

MySQL服务器支持# to end of line、-- to end of
line和/* in-line or multiple-line */注释风格：

mysql> select 1+1;     # This comment continues to the end of line
mysql> select 1+1;     -- This comment continues to the end of line
mysql> select 1 /* this is an in-line comment */ + 1;
mysql> select 1+
/*
this is a
multiple-line comment
*/
1;

注意--注释风格要求你在--以后至少有一个空格！

尽管服务者理解刚才描述的注释句法，mysql客户分析/*
... */注释的方式上有一些限制：

  • 单引号和双引号字符被用来标志一个括起来的字符串的开始，即使在一篇注释内。如果引号在主室内没被第2个引号匹配，分析器不知道注释已经结束。如果你正在交互式运行mysql，你能告知有些混乱，因为提示符从mysql>变为'>或">。

    •

  • 一个分号被用来指出当前的SQL语句结束并且跟随它的任何东西表示下一行的开始。

    •

当你交互式运行mysql时和当你把命令放在一个文件中并用mysql
< some-file告诉mysql从那个文件读它的输入时，这些限制都适用。

MySQL不支持‘--’的ANSI SQL注释风格。见5.4.7 ‘--’作为一篇注释的开始。

7.30 CREATE
FUNCTION/DROP FUNCTION句法

CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|REAL|INTEGER}
       SONAME shared_library_name

DROP FUNCTION function_name

一个用户可定义函数(UDF)是用一个像MySQL的原生（内置）函数如ABS()和CONCAT()的新函数来扩展MySQL的方法。

AGGREGATE是MySQL 3.23的一个新选项。一个AGGREGATE函数功能就像一个原生MySQL
GROUP函数如SUM或COUNT()。

CREATE FUNCTION在mysql.func系统表中保存函数名、类型和共享库名。你必须对mysql数据库有insert和delete权限以创建和抛弃函数。

所有活跃的函数在每次服务器启动时被重新装载，除非你使用--skip-grant-tables选项启动mysqld，在这种情况下，UDF初始化被跳过并且UDF是无法获得的。（一个活跃函数是一个已经用CREATE
FUNCTION装载并且没用DROP FUNCTION删除的函数。)

关于编写用户可定义函数的指令，见14 为MySQL增加新函数。对于UDF的工作机制，函数必须用
C 或 C++
编写，你的操作系统必须支持动态装载并且你必须动态编译了mysqld(不是静态)。

7.31 MySQL对保留词很挑剔吗？

一个常见的问题源自于试图使用MySQL内置的数据类型或函数名同名的列来创建数据库表，例如TIMESTAMP或GROUP。你允许这样做(例如，ABS是一个允许的列名)，但是当使用其名字也是列名的函数时，在一个函数名和“
( ”之间不允许白空。

下列词明确地在MySQL中被保留。他们的大多数被 ANSI
SQL92 禁止作为列或表名(例如，group)。一些被保留因为MySQL需要他们并且正在(当前)使用一个yacc分析器：

action | add | aggregate | all
alter | after | and | as
asc | avg | avg_row_length | auto_increment
between | bigint | bit | binary
blob | bool | both | by
cascade | case | char | character
change | check | checksum | column
columns | comment | constraint | create
cross | current_date | current_time | current_timestamp
data | database | databases | date
datetime | day | day_hour | day_minute
day_second | dayofmonth | dayofweek | dayofyear
dec | decimal | default | delayed
delay_key_write | delete | desc | describe
distinct | distinctrow | double | drop
end | else | escape | escaped
enclosed | enum | explain | exists
fields | file | first | float
float4 | float8 | flush | foreign
from | for | full | function
global | grant | grants | group
having | heap | high_priority | hour
hour_minute | hour_second | hosts | identified
ignore | in | index | infile
inner | insert | insert_id | int
integer | interval | int1 | int2
int3 | int4 | int8 | into
if | is | isam | join
key | keys | kill | last_insert_id
leading | left | length | like
lines | limit | load | local
lock | logs | long | longblob
longtext | low_priority | max | max_rows
match | mediumblob | mediumtext | mediumint
middleint | min_rows | minute | minute_second
modify | month | monthname | myisam
natural | numeric | no | not
null | on | optimize | option
optionally | or | order | outer
outfile | pack_keys | partial | password
precision | primary | procedure | process
processlist | privileges | read | real
references | reload | regexp | rename
replace | restrict | returns | revoke
rlike | row | rows | second
select | set | show | shutdown
smallint | soname | sql_big_tables | sql_big_selects
sql_low_priority_updates | sql_log_off | sql_log_update | sql_select_limit
sql_small_result | sql_big_result | sql_warnings | straight_join
starting | status | string | table
tables | temporary | terminated | text
then | time | timestamp | tinyblob
tinytext | tinyint | trailing | to
type | use | using | unique
unlock | unsigned | update | usage
values | varchar | variables | varying
varbinary | with | write | when
where | year | year_month | zerofill

下列符号(来自上表)被ANSI SQL禁止但是被MySQL允许作为列/表名。这是因为这些名字的一些是很自然的名字并且很多人已经使用了他们。

  • ACTION
    •

  • BIT
    •

  • DATE
    •

  • ENUM
    •

  • NO
    •

  • TEXT
    •

  • TIME
    •

  • TIMESTAMP
    •

去第一章, 前一章, 下一章,
最后一章，目录.


MySQL 中文参考手册- 8 MySQL 教程

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

8 MySQL教程

本章通过演示如何使用mysql客户程序创造和使用一个简单的数据库，提供一个MySQL的入门教程。mysql（有时称为“终端监视器”或只是“监视”)是一个交互式程序，允许你连接一个MySQL服务器，运行查询并察看结果。mysql可以用于批模式：你预先把查询放在一个文件中，然后告诉mysql执行文件的内容。使用mysql的两个方法都在这里涉及。

为了看清由mysql提供的一个选择项目表了，用--help选项调用它：

shell> mysql --help

本章假定mysql已经被安装在你的机器上，并且有一个MySQL服务器你可以连接。如果这不是真的，联络你的MySQL管理员。（如果你是管理员，你将需要请教这本手册的其他章节。）

本章描述建立和使用一个数据库的全过程。如果你仅仅对存取一个已经存在数据库感兴趣，你可能想要跳过描述怎样创建数据库及它所包含的表的章节。

既然本章本质上是一个教程，许多细节有必要被省略。对于这里所涉及的话题的更多信息，咨询本手册的相关章节。

8.1 连接与断开服务者

为了连接服务器，当你调用mysql时，你通常将需要提供一个MySQL用户名和很可能，一个口令。如果服务器运行在不是你登录的一台机器上，你也将需要指定主机名。联系你的管理员以找出你应该使用什么连接参数进行连接(即，那个主机，用户名字和使用的口令)。一旦你知道正确的参数，你应该能象这样连接：

shell> mysql -h host -u user -p
Enter password: ********

********代表你的口令；当mysql显示Enter password:提示时输入它。

如果能工作，你应该看见mysql>提示后的一些介绍信息：

shell> mysql -h host -u user -p
Enter password: ********
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 459 to server version: 3.22.20a-log

Type 'help' for help.

mysql>

提示符告诉你mysql准备为你输入命令。

一些MySQL安装允许用户以“anoymous”(匿名)用户连接在本地主机上运行的服务器。如果在你的机器是这种情况，你应该能通过没有任何选项地调用mysql与该服务器连接：

shell> mysql

在你成功地连接后，你可以在mysql>提示下打入QUIT随时断开：
mysql> QUIT
Bye

你也可以键入control-D断开。

在下列章节的大多数例子都假设你连接到服务器。由mysql>提示指明他们。

8.2 输入查询

确保你连接上了服务器，如在先前的章节讨论的。这样做本身将不选择任何数据库来工作，但是那很好。从这点讲，知道关于如何出询问的一点知识，比马上跳至创建表、给他们装载数据并且从他们检索数据要来的重要写。本节描述输入命令的基本原则，使用几个查询，你能尝试让自己mysql是如何工作的。

这是一个简单的命令，要求服务器告诉你它的版本号和当前日期。在mysql>提示打入如下命令并按回车键：

mysql> SELECT VERSION(), CURRENT_DATE;
+--------------+--------------+
| version()    | CURRENT_DATE |
+--------------+--------------+
| 3.22.20a-log | 1999-03-19   |
+--------------+--------------+
1 row in set (0.01 sec)
mysql>

这询问说明关于mysql几件事:

  • 一个命令通常由SQL语句组成，随后有一个分号。（有一些例外不需要一个分号。早先提到的QUIT是他们之一。我们将以后看到其它。）
  • 当你发出一个命令时，mysql发送它给服务器并显示结果，然后打出另外一个mysql>显示它准备好接受另外的命令。
  • mysql以一张表格(行和列)显示查询输出。第一行包含列的标签，随后的行是询问结果。通常， 列标签是你取自数据库表的列的名字。如果你正在检索一个表达式而非表列的值(如刚才的例子)，mysql用表达式本身标记列。
  • mysql显示多少行被返回，和查询花了多长执行，它给你提供服务器性能的一个大致概念。因为他们表示时钟时间(不是 CPU 或机器时间)，并且因为他们受到诸如服务器负载和网络延时的影响，因此这些值是不精确的。（为了简洁，在本章剩下的例子中不再显示“集合中的行”。）

关键词可以以任何大小写字符被输入。下列询问是等价的：

mysql> SELECT VERSION(), CURRENT_DATE;
mysql> select version(), current_date;
mysql> SeLeCt vErSiOn(), current_DATE;

这里有另外一个查询，它说明你能将mysql用作一个简单的计算器：
mysql> SELECT SIN(PI()/4), (4+1)*5;
+-------------+---------+
| SIN(PI()/4) | (4+1)*5 |
+-------------+---------+
|    0.707107 |      25 |
+-------------+---------+

至今显示的命令是相当短的，单行语句。你甚至能在单行上输入多条语句，只是以一个分号结束每一条：

mysql> SELECT VERSION(); SELECT NOW();
+--------------+
| version()    |
+--------------+
| 3.22.20a-log |
+--------------+

+---------------------+
| NOW()               |
+---------------------+
| 1999-03-19 00:15:33 |
+---------------------+

一个命令不必全在一个单独行给出，所以需要多行的较长命令不是一个问题。mysql通过寻找终止的分号而不是寻找输入行的结束来决定你的语句在哪儿结束。（换句话说，mysql接受自由格式输入：它收集输入行但执行他们直到它看见分号。）

这里是一个简单的多行语句的例子：

mysql> SELECT
    -> USER()
    -> ,
    -> CURRENT_DATE;
+--------------------+--------------+
| USER()             | CURRENT_DATE |
+--------------------+--------------+
| joesmith@localhost | 1999-03-18   |
+--------------------+--------------+

在这个例子中，在你输入一个多行查询的第一行后，要注意提示符如何从mysql>变为->，这正是mysql如何指出它没见到完整的语句并且正在等待剩余的部分。提示符是你的朋友，因为它提供有价值的反馈，如果你使用该反馈，你将总是知道mysql正在等待什么。

如果你决定，你不想要执行你在输入过程中输入的一个命令，打入\c取消它：

mysql> SELECT
    -> USER()
    -> \c
mysql>

这里也要注意提示符，在你打入\c以后，它切换回到mysql>，提供反馈以表明mysql准备接受一个新命令。

下表显示出你可以看见的各个提示符并总结他们意味着mysql在什么状态下：

提示符 | 意思
mysql> | 准备好接受新命令
-> | 等待多行命令的下一行
'> | 等待下一行，收集以单引号(“'”)开始的字符串
"> | 等待下一行，收集以双引号(“"”)开始的字符串

当你打算在一个单行上发出一个命令时，多行语句通常“偶然”出现，但是忘记终止的分号。在这种情况中，mysql等待进一步输入：

mysql> SELECT USER()
    ->

如果这发生在你身上(你认为你输完了语句但是唯一的反应是一个->提示符)，很可能mysql正在等待分号。如果你没有注意到提示符正在告诉你什么，在认识到你需要做什么之前，你可能花一会儿时间呆坐在那儿。进入一个分号完成语句，并且mysql将执行它：

mysql> SELECT USER()
    -> ;
+--------------------+
| USER()             |
+--------------------+
| joesmith@localhost |
+--------------------+

'>和">提示符出现在在字符串收集期间。在MySQL中，你可以写由“'”或“"”字符括起来的字符串 (例如，'hello'或"goodbye")，并且mysql让你进入跨越多行的字符串。当你看到一个'>或">提示符时，这意味着你已经输入了包含以“'”或“"”括号字符开始的字符串的一行，但是还没有输入终止字符串的匹配引号。如果你确实正在输入一个多行字符串，很好，但是果真如此吗？不尽然。更常见的，'>和">提示符显示你粗心地省掉了一个引号字符。例如：

mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
    ">

如果你输入该SELECT语句，然后按回车键并等待结果，什么都没有出现。不要惊讶，“为什么该查询这么长呢？”，注意">提示符提供的线索。它告诉你mysql期望见到一个未终止字符串的余下部分。（你在语句中看见错误吗？字符串"Smith正好丢失第二个引号。）

走到这一步，你该做什么？最简单的是取消命令。然而，在这种情况下，你不能只是打入\c，因为mysql作为它正在收集的字符串的一部分来解释它！相反，输入关闭的引号字符(这样mysql知道你完成了字符串)，然后打入\c：

mysql> SELECT * FROM my_table WHERE name = "Smith AND age < 30;
    "> "\c
mysql>

提示符回到mysql>，显示mysql准备好接受一个新命令了。

知道'>和">提示符意味着什么是很重要的，因为如果你错误地输入一个未终止的字符串，任何比你下一步输入的行好象将要被mysql忽略--包括包含QUIT的行！这可能相当含糊，特别是在你能取消当前命令前，如果你不知道你需要提出终止引号。

8.3 常用查询的例子

下面是一些学习如何用MySQL解决一些常见问题的例子。

一些例子使用数据库表“shop”，包含某个商人的每篇文章(物品号)的价格。假定每个商人的每篇文章有一个单独的固定价格，那么(物品，商人)是记录的主键。

你能这样创建例子数据库表：

CREATE TABLE shop (
 article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
 dealer  CHAR(20)                 DEFAULT ''     NOT NULL,
 price   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL,
 PRIMARY KEY(article, dealer));

INSERT INTO shop VALUES
(1,'A',3.45),(1,'B',3.99),(2,'A',10.99),(3,'B',1.45),(3,'C',1.69),
(3,'D',1.25),(4,'D',19.95);

好了，例子数据是这样的：

SELECT * FROM shop

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | A      |  3.45 |
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | B      |  1.45 |
|    0003 | C      |  1.69 |
|    0003 | D      |  1.25 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

8.3.1 列的最大值

“最大的物品号是什么？”

SELECT MAX(article) AS article FROM shop

+---------+
| article |
+---------+
|       4 |
+---------+

8.3.2 拥有某个列的最大值的行

“找出最贵的文章的编号、商人和价格”

在ANSI-SQL中这很容易用一个子查询做到：

SELECT article, dealer, price
FROM   shop
WHERE  price=(SELECT MAX(price) FROM shop)

在MySQL中（还没有子查询)就用2步做到：

  1. 用一个SELECT语句从表中得到最大值。
  2. 使用该值编出实际的查询：
    SELECT article, dealer, price
FROM   shop
WHERE  price=19.95

另一个解决方案是按价格降序排序所有行并用MySQL特定LIMIT子句只得到的第一行：

SELECT article, dealer, price
FROM   shop
ORDER BY price DESC
LIMIT 1

注意:如果有多个最贵的文章( 例如每个19.95)，LIMIT解决方案仅仅显示他们之一！

8.3.3 列的最大值：按组：只有值

“每篇文章的最高的价格是什么？”

SELECT article, MAX(price) AS price
FROM   shop
GROUP BY article

+---------+-------+
| article | price |
+---------+-------+
|    0001 |  3.99 |
|    0002 | 10.99 |
|    0003 |  1.69 |
|    0004 | 19.95 |
+---------+-------+

8.3.4 拥有某个字段的组间最大值的行

“对每篇文章，找出有最贵的价格的交易者。”

在ANSI SQL中，我可以用这样一个子查询做到：

SELECT article, dealer, price
FROM   shop s1
WHERE  price=(SELECT MAX(s2.price)
              FROM shop s2
              WHERE s1.article = s2.article)

在MySQL中，最好是分几步做到：

  1. 得到一个表(文章，maxprice)。见8.3.4 拥有某个域的组间最大值的行。
  2. 对每篇文章，得到对应于存储最大价格的行。

这可以很容易用一个临时表做到：

CREATE TEMPORARY TABLE tmp (
        article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
        price   DOUBLE(16,2)             DEFAULT '0.00' NOT NULL);

LOCK TABLES article read;

INSERT INTO tmp SELECT article, MAX(price) FROM shop GROUP BY article;

SELECT article, dealer, price FROM shop, tmp
WHERE shop.article=tmp.articel AND shop.price=tmp.price;

UNLOCK TABLES;

DROP TABLE tmp;

如果你不使用一个TEMPORARY表，你也必须锁定“tmp”表。

“它能一个单个查询做到吗？”

是的，但是只有使用我称之为“MAX-CONCAT诡计”的一个相当低效的诡计：

SELECT article,
       SUBSTRING( MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 7) AS dealer,
  0.00+LEFT(      MAX( CONCAT(LPAD(price,6,'0'),dealer) ), 6) AS price
FROM   shop
GROUP BY article;

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | C      |  1.69 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

最后例子当然能通过在客户程序中分割连结的列使它更有效一点。

8.3.5 使用外键

不需要外键联结2个表。

MySQL唯一不做的事情是CHECK以保证你使用的键确实在你正在引用表中存在，并且它不自动从有一个外键定义的表中删除行。如果你象平常那样使用你的键值，它将工作得很好！

CREATE TABLE persons (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR(60) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE shirts (
    id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
    style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
    color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
    owner SMALLINT UNSIGNED NOT NULL REFERENCES persons,
    PRIMARY KEY (id)
);

INSERT INTO persons VALUES (NULL, 'Antonio Paz');

INSERT INTO shirts VALUES
(NULL, 'polo', 'blue', LAST_INSERT_ID()),
(NULL, 'dress', 'white', LAST_INSERT_ID()),
(NULL, 't-shirt', 'blue', LAST_INSERT_ID());

INSERT INTO persons VALUES (NULL, 'Lilliana Angelovska');

INSERT INTO shirts VALUES
(NULL, 'dress', 'orange', LAST_INSERT_ID()),
(NULL, 'polo', 'red', LAST_INSERT_ID()),
(NULL, 'dress', 'blue', LAST_INSERT_ID()),
(NULL, 't-shirt', 'white', LAST_INSERT_ID());

SELECT * FROM persons;
+----+---------------------+
| id | name                |
+----+---------------------+
|  1 | Antonio Paz         |
|  2 | Lilliana Angelovska |
+----+---------------------+

SELECT * FROM shirts;
+----+---------+--------+-------+
| id | style   | color  | owner |
+----+---------+--------+-------+
|  1 | polo    | blue   |     1 |
|  2 | dress   | white  |     1 |
|  3 | t-shirt | blue   |     1 |
|  4 | dress   | orange |     2 |
|  5 | polo    | red    |     2 |
|  6 | dress   | blue   |     2 |
|  7 | t-shirt | white  |     2 |
+----+---------+--------+-------+

SELECT s.* FROM persons p, shirts s
 WHERE p.name LIKE 'Lilliana%'
   AND s.owner = p.id
   AND s.color &lt;&gt; 'white';

+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
|  4 | dress | orange |     2 |
|  5 | polo  | red    |     2 |
|  6 | dress | blue   |     2 |
+----+-------+--------+-------+

8.4 创造并使用一个数据库

既然你知道怎样输入命令，现在是存取一个数据库的时候了。

假定在你的家(你的“动物园”)中有很多宠物，并且你想追踪关于他们各种各样类型的信息。你可以通过创建表来保存你的数据并根据所需要的信息装载他们做到，然后你可以通过从表中检索数据来回答关于你的动物不同种类的问题。本节显示如何做到所有这些事情：

  • 怎样创建一个数据库
  • 怎样创建一个数据库表
  • 怎样装载数据到数据库表
  • 怎样以各种方法从表中检索数据
  • 怎样使用多个表

动物园数据库将会是简单的(故意的)，但是不难把它想象成可能用到相似类型数据库的真实世界情况。例如，这样的一个数据库能被一个农夫用来追踪家畜，或由一个兽医追踪病畜记录。

使用SHOW语句找出在服务器上当前存在什么数据库：

mysql> SHOW DATABASES;
+----------+
| Database |
+----------+
| mysql    |
| test     |
| tmp      |
+----------+

数据库列表可能在你的机器上是不同的，但是mysql和test数据库很可能的在其间。mysql是必需的，因为它描述用户存取权限，test数据库经常作为一个工作区提供给用户试试身手。

如果test数据库存在，尝试存取它：

mysql> USE test
Database changed

注意，USE，类似QUIT，不需要一个分号。（如果你喜欢，你可以用一个分号终止这样的语句；这无碍)USE语句在使用上也有另外一个特殊的地方：它必须在一个单行上给出。

你可列在后面的例子中使用test数据库(如果你能访问它)，但是你在该数据库创建的任何东西可以被与访问它的其他人删除，为了这个原因，你可能应该询问你的MySQL管理员许可你自己使用的一个数据库。假定你想要调用你的menagerie，管理员需要执行一个这样的命令：

mysql> GRANT ALL ON menagerie.* TO your_mysql_name;

这里your_mysql_name是分配给你的MySQL用户名。

8.4.1 创建并选用一个数据库

如果在设置你的权限时，管理员为你创建了数据库，你可以开始使用它。否则，你需要自己创建它：

mysql> CREATE DATABASE menagerie;

在Unix下，数据库名字是区分大小写的(不像SQL关键词)，因此你必须总是以menagerie引用你的数据库，不是Menagerie、MENAGERIE或一些其他变种。对表名也是这样的。（在Windows下，该限制不适用，尽管你必须在一个给定的查询中使用同样的大小写来引用数据库和表。）

创建了一个数据库并不选定以使用它，你必须明确地做这件事。为了使menagerie称为当前的数据库，使用这个命令：

mysql> USE menagerie
Database changed

你的数据库只需要创建一次，但是你必须在每次启动一个mysql会话时为使用而选择它。你可以由发出上面一个USE语句做到。另外，当你调用时mysql，你可在命令行上选择数据库，就在你可能需要提供的任何连接参数之后指定其名字。例如：

shell> mysql -h host -u user -p menagerie
Enter password: ********

注意，menagerie不是你在刚才所示命令的口令。如果你想要在命令行上在-p选项后提供你的口令，你必须做到没有多余的空格(例如，如-pmypassword，不是-p mypassword)。然而，不建议把你的口令放在命令行上，因为这样做把它暴露出来，能被在你的机器上登录的其他用户窥探到。

8.4.2 创建一个数据库表

创建数据库是容易的部分，但是在这时它是空的，正如SHOW TABLES将告诉你：

mysql> SHOW TABLES;
Empty set (0.00 sec)

较难的部分是决定你的数据库结构应该是什么：你将需要什么数据库表，和在他们中有什么样的列。

你将需要一个包含你每个宠物的记录的表。它可称为pet表，并且它应该包含，最少，每个动物的名字。因为名字本身不是很有趣，表应该包含另外的信息。例如，如果在你豢养宠物的家庭有超过一个人，你可能想要列出每个动物的主人。你可能也想要记录例如种类和性别的一些基本的描述信息。

年龄呢？那可能有趣，但是在一个数据库中存储不是一件好事情。年龄随着时间流逝而变化，这意味着你将要不断地更新你的记录。相反, 存储一个固定值例如生日比较好，那么，无论何时你需要年龄，你可以以当前日期和出生日期之间的差别来计算它。MySQL为日期运算提供了函数，因此这并不困难。存储出生日期而非年龄也有其他优点：

  • 你可以将数据库用于这样的任务例如生成即将到来的宠物生日的提示。（如果你认为这类查询是点蠢，注意，这与在一个商务数据库来标示你不久要给它发出生日祝贺的客户的环境中是同一个问题，因为计算机帮助私人联络。）
  • 你可以相对于日期而不止是当前日期来计算年龄。例如，如果你在数据库存储死亡日期，你能容易计算一只宠物是何时多大死的。

你可能想到pet表中其他有用的其他类型信息，但是到目前为止这些现在是足够了：名字、主人、种类，性别、出生和死亡日期。

使用一个CREATE TABLE语句指定你的数据库表的布局：

mysql> CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20),
    -> species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);

VARCHAR对name、owner和species列是个好的选择，因为列值将会是变长的。这些列的长度都不必是相同的，而且不必是20。你可以挑选从1到255的任何长度，无论哪个对你来说好象最合理。（如果你做了较差的选择，以后会变得你需要一个更长的字段，MySQL提供一个ALTER TABLE语句。）

动物性表可以用许多方法表示，例如，"m"和"f"，或也许"male"和"female"。使用单个字符"m"和"f"是最简单的。

为birth和death列使用DATE数据类型是相当明显的选择。

既然你创建了一个表，SHOW TABLES应该产生一些输出：

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| pet                 |
+---------------------+

为了验证你的表是按你期望的方式被创建，使用一个DESCRIBE语句：

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

你能随时DESCRIBE，例如，如果你忘记在你表中的列的名字或他们是什么类型。

8.4.3 将数据装入一个数据库表

在你创建表后，你需要充实它。LOAD DATA和INSERT语句用于此。

假定你的宠物纪录描述如下。（观察到MySQL期望日期时以YYYY-MM-DD格式；这可能与你习惯的不同。）

name | owner | species | sex | birth | death
Fluffy | Harold | cat | f | 1993-02-04 |
Claws | Gwen | cat | m | 1994-03-17 |
Buffy | Harold | dog | f | 1989-05-13 |
Fang | Benny | dog | m | 1990-08-27 |
Bowser | Diane | dog | m | 1998-08-31 | 1995-07-29
Chirpy | Gwen | bird | f | 1998-09-11 |
Whistler | Gwen | bird |  | 1997-12-09 |
Slim | Benny | snake | m | 1996-04-29 |

因为你是从一张空表开始的，充实它的一个容易方法是创建包含为你的动物各一行一个文本文件，然后用一个单个语句装载文件的内容到表中。

你可以创建一个文本文件“pet.txt”，每行包含一个记录，用定位符(tab)把值分开，并且以在CREATE TABLE语句中列出的列次序给出。对于丢失的值(例如未知的性别，或仍然活着的动物的死亡日期)，你可以使用NULL值。为了在你的文本文件表示这些，使用\N。例如，对Whistler鸟的记录看起来像这样的(这里在值之间的空白是一个单个的定位字符)：

Whistler Gwen bird \N 1997-12-09 \N

为了装载文本文件“pet.txt”到pet表中，使用这个命令：

mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;

如果你愿意，你能明确地在LOAD DATA语句中指出列值的分隔符和行尾标记，但是缺省是定位符和换行符。这些对争取读入文件“pet.txt”的语句是足够的。

当你想要一次增加一个新记录时，INSERT语句是有用的。在它最简单的形式，你为每一列提供值，以列在CREATE TABLE语句被列出的顺序。假定Diane把一只新仓鼠命名为Puffball，你可以使用一个这样INSERT语句增加一条新记录：

mysql> INSERT INTO pet
    -> VALUES ('Puffball','Diane','hamster','f','1999-03-30',NULL);

注意，这里字符串和日期值被指定为引号扩起来的字符串。另外，用INSERT，你能直接插入NULL代表不存在的值。你不能使用\N，就像你用LOAD DATA做的那样。

从这个例子，你应该能看到涉及很多的键入用多个INSERT语句而非单个LOAD DATA语句装载你的初始记录。

8.4.4 从一个数据库表检索信息

SELECT语句被用来从一张桌子拉出信息。语句的一般格式是：

SELECT what_to_select
FROM which_table
WHERE conditions_to_satisfy

what_to_select指出你想要看到的，这可以是列的一张表，或*表明“所有的列”。which_table指出你想要从其检索数据的表。WHERE子句是可选的，如果它在，conditions_to_satisfy指定行必须满足的检索条件。

8.4.4.1 选择所有数据

SELECT最简单的形式是从一张表中检索每样东西：

mysql> SELECT * FROM pet;
+----------+--------+---------+------+------------+------------+
| name     | owner  | species | sex  | birth      | death      |
+----------+--------+---------+------+------------+------------+
| Fluffy   | Harold | cat     | f    | 1993-02-04 | NULL       |
| Claws    | Gwen   | cat     | m    | 1994-03-17 | NULL       |
| Buffy    | Harold | dog     | f    | 1989-05-13 | NULL       |
| Fang     | Benny  | dog     | m    | 1990-08-27 | NULL       |
| Bowser   | Diane  | dog     | m    | 1998-08-31 | 1995-07-29 |
| Chirpy   | Gwen   | bird    | f    | 1998-09-11 | NULL       |
| Whistler | Gwen   | bird    | NULL | 1997-12-09 | NULL       |
| Slim     | Benny  | snake   | m    | 1996-04-29 | NULL       |
| Puffball | Diane  | hamster | f    | 1999-03-30 | NULL       |
+----------+--------+---------+------+------------+------------+

如果你想要考察整个表，这种形式的SELECT是很有用的。例如，在你刚刚给它装载了你的初始数据集装以后。当它发生时，刚才显示的输出揭示了在你的数据文件的一个错误：在Bowser死了以后，它好象要出生了！请教你原来的家谱，你发现正确的出生年是1989，而不是1998。

至少有一些修正它的方法：

  • 编辑文件“pet.txt”改正错误，然后使用DELETE和LOAD DATA弄空表并且再次装载它:
    mysql> DELETE FROM pet;
mysql> LOAD DATA LOCAL INFILE "pet.txt" INTO TABLE pet;

    然而, 如果你这样做，你必须重新输入Puffball记录。

  • 用一个UPDATE语句仅修正错误记录：
    mysql> UPDATE pet SET birth = "1989-08-31" WHERE name = "Bowser";

如上所示，检索整个表是容易的，但是一般你不想那样做，特别地当表变得很大时。相反，你通常对回答一个特别的问题更感兴趣，在这种情况下你在你想要的信息上指定一些限制。让我们看一些他们回答有关你宠物的问题的选择查询。

8.4.4.2 选择特定行

你能从你的表中只选择特定的行。例如，如果你想要验证你对Bowser的出生日期所做的改变，像这样精选Bowser的记录：

mysql> SELECT * FROM pet WHERE name = "Bowser";
+--------+-------+---------+------+------------+------------+
| name   | owner | species | sex  | birth      | death      |
+--------+-------+---------+------+------------+------------+
| Bowser | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+-------+---------+------+------------+------------+

输出证实年份现在正确记录为1989，而不是1998。

字符串比较通常是大小些无关的，因此你可以指定名字为"bowser"、"BOWSER"等等，查询结果将是相同的。

你能在任何列上指定条件，不只是name。例如，如果你想要知道哪个动物在1998以后出生的，测试birth列：

mysql> SELECT * FROM pet WHERE birth >= "1998-1-1";
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Puffball | Diane | hamster | f    | 1999-03-30 | NULL  |
+----------+-------+---------+------+------------+-------+

你能组合条件，例如，找出雌性的狗：

mysql> SELECT * FROM pet WHERE species = "dog" AND sex = "f";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

上面的查询使用AND逻辑操作符，也有一个OR操作符：

mysql> SELECT * FROM pet WHERE species = "snake" OR species = "bird";
+----------+-------+---------+------+------------+-------+
| name     | owner | species | sex  | birth      | death |
+----------+-------+---------+------+------------+-------+
| Chirpy   | Gwen  | bird    | f    | 1998-09-11 | NULL  |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL  |
| Slim     | Benny | snake   | m    | 1996-04-29 | NULL  |
+----------+-------+---------+------+------------+-------+

AND和OR可以混用。如果你这样做，使用括号指明条件应该如何被分组是一个好主意：

mysql> SELECT * FROM pet WHERE (species = "cat" AND sex = "m")
    -> OR (species = "dog" AND sex = "f");
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

8.4.4.3 选择特定列

如果你不想要看到你的表的整个行，就命名你感兴趣的列，用逗号分开。例如，如果你想要知道你的动物什么时候出生的，精选name和birth列：

mysql> SELECT name, birth FROM pet;
+----------+------------+
| name     | birth      |
+----------+------------+
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Buffy    | 1989-05-13 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Puffball | 1999-03-30 |
+----------+------------+

找出谁拥有宠物，使用这个查询：

mysql> SELECT owner FROM pet;
+--------+
| owner  |
+--------+
| Harold |
| Gwen   |
| Harold |
| Benny  |
| Diane  |
| Gwen   |
| Gwen   |
| Benny  |
| Diane  |
+--------+

然而，注意到查询简单地检索每个记录的owner字段，并且他们中的一些出现多次。为了使输出减到最少，通过增加关键词DISTINCT检索出每个唯一的输出记录：

mysql> SELECT DISTINCT owner FROM pet;
+--------+
| owner  |
+--------+
| Benny  |
| Diane  |
| Gwen   |
| Harold |
+--------+

你能使用一个WHERE子句把行选择与列选择相结合。例如，为了只得到狗和猫的出生日期，使用这个查询：

mysql> SELECT name, species, birth FROM pet
    -> WHERE species = "dog" OR species = "cat";
+--------+---------+------------+
| name   | species | birth      |
+--------+---------+------------+
| Fluffy | cat     | 1993-02-04 |
| Claws  | cat     | 1994-03-17 |
| Buffy  | dog     | 1989-05-13 |
| Fang   | dog     | 1990-08-27 |
| Bowser | dog     | 1989-08-31 |
+--------+---------+------------+

8.4.4.4 排序行

你可能已经注意到前面的例子中结果行没有以特定的次序被显示。然而，当行以某个有意义的方式排序，检验查询输出通常是更容易的。为了排序结果，使用一个ORDER BY子句。

这里是动物生日，按日期排序：

mysql> SELECT name, birth FROM pet ORDER BY birth;
+----------+------------+
| name     | birth      |
+----------+------------+
| Buffy    | 1989-05-13 |
| Bowser   | 1989-08-31 |
| Fang     | 1990-08-27 |
| Fluffy   | 1993-02-04 |
| Claws    | 1994-03-17 |
| Slim     | 1996-04-29 |
| Whistler | 1997-12-09 |
| Chirpy   | 1998-09-11 |
| Puffball | 1999-03-30 |
+----------+------------+

为了以逆序排序，增加DESC（下降 )关键字到你正在排序的列名上：

mysql> SELECT name, birth FROM pet ORDER BY birth DESC;
+----------+------------+
| name     | birth      |
+----------+------------+
| Puffball | 1999-03-30 |
| Chirpy   | 1998-09-11 |
| Whistler | 1997-12-09 |
| Slim     | 1996-04-29 |
| Claws    | 1994-03-17 |
| Fluffy   | 1993-02-04 |
| Fang     | 1990-08-27 |
| Bowser   | 1989-08-31 |
| Buffy    | 1989-05-13 |
+----------+------------+

你能在多个列上排序。例如，按动物的种类排序，然后按生日，首先是动物种类中最年轻的动物，使用下列查询：

mysql> SELECT name, species, birth FROM pet ORDER BY species, birth DESC;
+----------+---------+------------+
| name     | species | birth      |
+----------+---------+------------+
| Chirpy   | bird    | 1998-09-11 |
| Whistler | bird    | 1997-12-09 |
| Claws    | cat     | 1994-03-17 |
| Fluffy   | cat     | 1993-02-04 |
| Fang     | dog     | 1990-08-27 |
| Bowser   | dog     | 1989-08-31 |
| Buffy    | dog     | 1989-05-13 |
| Puffball | hamster | 1999-03-30 |
| Slim     | snake   | 1996-04-29 |
+----------+---------+------------+

注意DESC关键词仅适用于紧跟在它之前的列名字(birth)；species值仍然以升序被排序。

8.4.4.5 日期计算

MySQL提供几个函数，你能用来执行在日期上的计算，例如，计算年龄或提取日期的部分。

为了决定你的每个宠物有多大，用出生日期和当前日期之间的差别计算年龄。通过变换2个日期到天数，取差值，并且用365除(在一年里的天数)：

mysql> SELECT name, (TO_DAYS(NOW())-TO_DAYS(birth))/365 FROM pet;
+----------+-------------------------------------+
| name     | (TO_DAYS(NOW())-TO_DAYS(birth))/365 |
+----------+-------------------------------------+
| Fluffy   |                                6.15 |
| Claws    |                                5.04 |
| Buffy    |                                9.88 |
| Fang     |                                8.59 |
| Bowser   |                                9.58 |
| Chirpy   |                                0.55 |
| Whistler |                                1.30 |
| Slim     |                                2.92 |
| Puffball |                                0.00 |
+----------+-------------------------------------+

尽管查询可行，关于它还有能被改进的一些事情。首先，如果行以某个次序表示，其结果能更容易被扫描。第二，年龄列的标题不是很有意义的。

第一个问题通过增加一个ORDER BY name子句按名字排序输出来解决。为了处理列标题，为列提供一个名字以便一个不同的标签出现在输出中(这被称为一个列别名)：

mysql> SELECT name, (TO_DAYS(NOW())-TO_DAYS(birth))/365 AS age
    -> FROM pet ORDER BY name;
+----------+------+
| name     | age  |
+----------+------+
| Bowser   | 9.58 |
| Buffy    | 9.88 |
| Chirpy   | 0.55 |
| Claws    | 5.04 |
| Fang     | 8.59 |
| Fluffy   | 6.15 |
| Puffball | 0.00 |
| Slim     | 2.92 |
| Whistler | 1.30 |
+----------+------+

为了按age而非name排序输出，只要使用一个不同ORDER BY子句：

mysql>  SELECT name, (TO_DAYS(NOW())-TO_DAYS(birth))/365 AS age
    ->  FROM pet ORDER BY age;
+----------+------+
| name     | age  |
+----------+------+
| Puffball | 0.00 |
| Chirpy   | 0.55 |
| Whistler | 1.30 |
| Slim     | 2.92 |
| Claws    | 5.04 |
| Fluffy   | 6.15 |
| Fang     | 8.59 |
| Bowser   | 9.58 |
| Buffy    | 9.88 |
+----------+------+

一个类似的查询可以被用来确定已经死亡动物的死亡年龄。你通过检查death值是否是NULL来决定那些是哪些动物，然后，对于那些有非NULL值，计算在death和birth值之间的差别：

mysql>  SELECT name, birth, death, (TO_DAYS(death)-TO_DAYS(birth))/365 AS age
    ->  FROM pet WHERE death IS NOT NULL ORDER BY age;
+--------+------------+------------+------+
| name   | birth      | death      | age  |
+--------+------------+------------+------+
| Bowser | 1989-08-31 | 1995-07-29 | 5.91 |
+--------+------------+------------+------+

差询使用death IS NOT NULL而非death != NULL，因为NULL是特殊的值，这以后会解释。见8.4.4.6 用NULL值工作。

如果你想要知道哪个动物下个月过生日，怎么办？对于这类计算，年和天是无关的，你简单地想要提取birth列的月份部分。MySQL提供几个日期部分的提取函数，例如YEAR()、MONTH()和DAYOFMONTH()。在这里MONTH()是适合的函数。为了看它怎样工作，运行一个简单的查询，显示birth和MONTH(birth)的值：

mysql> SELECT name, birth, MONTH(birth) FROM pet;
+----------+------------+--------------+
| name     | birth      | MONTH(birth) |
+----------+------------+--------------+
| Fluffy   | 1993-02-04 |            2 |
| Claws    | 1994-03-17 |            3 |
| Buffy    | 1989-05-13 |            5 |
| Fang     | 1990-08-27 |            8 |
| Bowser   | 1989-08-31 |            8 |
| Chirpy   | 1998-09-11 |            9 |
| Whistler | 1997-12-09 |           12 |
| Slim     | 1996-04-29 |            4 |
| Puffball | 1999-03-30 |            3 |
+----------+------------+--------------+

用下个月的生日找出动物也是容易的。假定当前月是4月，那么月值是4并且你寻找在5月出生的动物 (5月)， 象这样：

mysql> SELECT name, birth FROM pet WHERE MONTH(birth) = 5;
+-------+------------+
| name  | birth      |
+-------+------------+
| Buffy | 1989-05-13 |
+-------+------------+

当然如果当前月份是12月，就有点复杂了。你不是只把加1到月份数(12)上并且寻找在13月出生的动物，因为没有这样的月份。相反，你寻找在1月出生的动物(1月) 。

你甚至可以编写查询以便不管当前月份是什么它都能工作。这种方法你不必在查询中使用一个特定的月份数字，DATE_ADD()允许你把时间间隔加到一个给定的日期。如果你把一个月加到NOW()值上，然后用MONTH()提取月份部分，结果产生寻找生日的月份：

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MONTH(DATE_ADD(NOW(), INTERVAL 1 MONTH));

完成同样任务的一个不同方法是加1以得出当前月份的下一个月(在使用取模函数(MOD)后，如果它当前是12，则“绕回”月份到值0)：

mysql> SELECT name, birth FROM pet
    -> WHERE MONTH(birth) = MOD(MONTH(NOW()), 12) + 1;

注意，MONTH返回在1和12之间的一个数字，且MOD(something,12)返回在0和11之间的一个数字，因此必须在MOD()以后加1，否则我们将从11月( 11 )跳到1月(1)。

8.4.4.6 NULL值操作

NULL值可能很奇怪直到你习惯于它。概念上，NULL意味着“没有值”或“未知值”，且它被看作有点与众不同的值。为了测试NULL，你不能使用算术比较运算符例如=、<或!=。为了说明它，试试下列查询：

mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 != NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
|     NULL |      NULL |     NULL |     NULL |
+----------+-----------+----------+----------+

很清楚你从这些比较中得到毫无意义的结果。相反使用IS NULL和IS NOT NULL操作符：

mysql> SELECT 1 IS NULL, 1 IS NOT NULL;
+-----------+---------------+
| 1 IS NULL | 1 IS NOT NULL |
+-----------+---------------+
|         0 |             1 |
+-----------+---------------+

在MySQL中，0意味着假而1意味着真。

NULL这样特殊的处理是为什么，在前面的章节中，为了决定哪个动物不再是活着的，使用death IS NOT NULL而不是death != NULL是必要的。

8.4.4.7 模式匹配

MySQL提供标准的SQL模式匹配，以及一种基于象Unix实用程序如vi、grep和sed的扩展正则表达式模式匹配的格式。

SQL的模式匹配允许你使用“_”匹配任何单个字符，而“%”匹配任意数目字符(包括零个字符)。在 MySQL中，SQL的模式缺省是忽略大小写的。下面显示一些例子。注意在你使用SQL模式时，你不能使用=或!=；而使用LIKE或NOT LIKE比较操作符。

为了找出以“b”开头的名字：

mysql> SELECT * FROM pet WHERE name LIKE "b%";
+--------+--------+---------+------+------------+------------+
| name   | owner  | species | sex  | birth      | death      |
+--------+--------+---------+------+------------+------------+
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL       |
| Bowser | Diane  | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+

为了找出以“fy”结尾的名字：

mysql> SELECT * FROM pet WHERE name LIKE "%fy";
+--------+--------+---------+------+------------+-------+
| name   | owner  | species | sex  | birth      | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat     | f    | 1993-02-04 | NULL  |
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL  |
+--------+--------+---------+------+------------+-------+

为了找出包含一个“w”的名字：

mysql> SELECT * FROM pet WHERE name LIKE "%w%";
+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Claws    | Gwen  | cat     | m    | 1994-03-17 | NULL       |
| Bowser   | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
+----------+-------+---------+------+------------+------------+

为了找出包含正好5个字符的名字，使用“_”模式字符：

mysql> SELECT * FROM pet WHERE name LIKE "_____";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

由MySQL提供的模式匹配的其他类型是使用扩展正则表达式。当你对这类模式进行匹配测试时，使用REGEXP和NOT REGEXP操作符(或RLIKE和NOT RLIKE，它们是同义词)。

扩展正则表达式的一些字符是：

  • “.”匹配任何单个的字符。
  • 一个字符类“[...]”匹配在方括号内的任何字符。例如，“[abc]”匹配“a”、“b”或“c”。为了命名字符的一个范围，使用一个“-”。“[a-z]”匹配任何小写字母，而“[0-9]”匹配任何数字。
  • “ * ”匹配零个或多个在它前面的东西。例如，“x*”匹配任何数量的“x”字符，“[0-9]*”匹配的任何数量的数字，而“.*”匹配任何数量的任何东西。
  • 正则表达式是区分大小写的，但是如果你希望，你能使用一个字符类匹配两种写法。例如，“[aA]”匹配小写或大写的“a”而“[a-zA-Z]”匹配两种写法的任何字母。
  • 如果它出现在被测试值的任何地方，模式就匹配(只要他们匹配整个值，SQL模式匹配)。
  • 为了定位一个模式以便它必须匹配被测试值的开始或结尾，在模式开始处使用“^”或在模式的结尾用“$”。

为了说明扩展正则表达式如何工作，上面所示的LIKE查询在下面使用REGEXP重写：

为了找出以“b”开头的名字，使用“^”匹配名字的开始并且“[bB]”匹配小写或大写的“b”：

mysql> SELECT * FROM pet WHERE name REGEXP "^[bB]";
+--------+--------+---------+------+------------+------------+
| name   | owner  | species | sex  | birth      | death      |
+--------+--------+---------+------+------------+------------+
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL       |
| Bowser | Diane  | dog     | m    | 1989-08-31 | 1995-07-29 |
+--------+--------+---------+------+------------+------------+

为了找出以“fy”结尾的名字，使用“$”匹配名字的结尾：

mysql> SELECT * FROM pet WHERE name REGEXP "fy$";
+--------+--------+---------+------+------------+-------+
| name   | owner  | species | sex  | birth      | death |
+--------+--------+---------+------+------------+-------+
| Fluffy | Harold | cat     | f    | 1993-02-04 | NULL  |
| Buffy  | Harold | dog     | f    | 1989-05-13 | NULL  |
+--------+--------+---------+------+------------+-------+

为了找出包含一个“w”的名字，使用“[wW]”匹配小写或大写的“w”：

mysql> SELECT * FROM pet WHERE name REGEXP "[wW]";
+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Claws    | Gwen  | cat     | m    | 1994-03-17 | NULL       |
| Bowser   | Diane | dog     | m    | 1989-08-31 | 1995-07-29 |
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
+----------+-------+---------+------+------------+------------+

既然如果一个正规表达式出现在值的任何地方，其模式匹配了，就不必再先前的查询中在模式的两方面放置一个通配符以使得它匹配整个值，就像如果你使用了一个SQL模式那样。

为了找出包含正好5个字符的名字，使用“^”和“$”匹配名字的开始和结尾，和5个“.”实例在两者之间：

mysql> SELECT * FROM pet WHERE name REGEXP "^.....$";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

你也可以使用“{n}”“重复n次”操作符重写先前的查询：

mysql> SELECT * FROM pet WHERE name REGEXP "^.{5}$";
+-------+--------+---------+------+------------+-------+
| name  | owner  | species | sex  | birth      | death |
+-------+--------+---------+------+------------+-------+
| Claws | Gwen   | cat     | m    | 1994-03-17 | NULL  |
| Buffy | Harold | dog     | f    | 1989-05-13 | NULL  |
+-------+--------+---------+------+------------+-------+

8.4.4.8 行计数

数据库经常用于回答这个问题，“某个类型的数据在一张表中出现的频度?”例如，你可能想要知道你有多少宠物，或每位主人有多少宠物，或你可能想要在你的动物上施行各种类型的普查。

计算你拥有动物的总数字与“在pet表中有多少行?”是同样的问题，因为每个宠物有一个记录。COUNT()函数计数非NULL结果的数目，所以数你的动物的查询看起来像这样：

mysql> SELECT COUNT(*) FROM pet;
+----------+
| COUNT(*) |
+----------+
|        9 |
+----------+

在前面，你检索了拥有宠物的人的名字。如果你想要知道每个主人有多少宠物，你可以使用COUNT()函数：

mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
+--------+----------+
| owner  | COUNT(*) |
+--------+----------+
| Benny  |        2 |
| Diane  |        2 |
| Gwen   |        3 |
| Harold |        2 |
+--------+----------+

注意，使用GROUP BY对每个owner分组所有记录，没有它，你得到的一切是一条错误消息：

mysql> SELECT owner, COUNT(owner) FROM pet;
ERROR 1140 at line 1: Mixing of GROUP columns (MIN(),MAX(),COUNT()...)
with no GROUP columns is illegal if there is no GROUP BY clause

COUNT()和GROUP BY对以各种方式分类你的数据很有用。下列例子显示出实施动物普查操作的不同方式。

每种动物数量：

mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| bird    |        2 |
| cat     |        2 |
| dog     |        3 |
| hamster |        1 |
| snake   |        1 |
+---------+----------+

每中性别的动物数量：

mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
+------+----------+
| sex  | COUNT(*) |
+------+----------+
| NULL |        1 |
| f    |        4 |
| m    |        4 |
+------+----------+

（在这个输出中，NULL表示“未知性别”。）

按种类和性别组合的动物数量：

mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | NULL |        1 |
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

当你使用COUNT()时，你不必检索整个一张表。例如, 先前的查询，当只在狗和猫上施行时，看起来像这样：

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE species = "dog" OR species = "cat"
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
+---------+------+----------+

或，如果你仅需要知道已知性别的按性别的动物数目：

mysql> SELECT species, sex, COUNT(*) FROM pet
    -> WHERE sex IS NOT NULL
    -> GROUP BY species, sex;
+---------+------+----------+
| species | sex  | COUNT(*) |
+---------+------+----------+
| bird    | f    |        1 |
| cat     | f    |        1 |
| cat     | m    |        1 |
| dog     | f    |        1 |
| dog     | m    |        2 |
| hamster | f    |        1 |
| snake   | m    |        1 |
+---------+------+----------+

8.4.5 使用多个数据库表

pet表追踪你有哪个宠物。如果你想要记录他们的其他信息，例如在他们一生中事件看兽医或何时后代出生，你需要另外的表。这张表应该像什么呢？

  • 它需要包含宠物名字因此你知道每个事件属于此动物。
  • 它需要一个日期因此你知道事件什么时候发生的。
  • 需要一个字段描述事件。
  • 如果你想要可分类事件，有一个事件类型字段将是有用的。

给出了这些考虑，为event表的CREATE TABLE语句可能看起来像这样：

mysql> CREATE TABLE event (name VARCHAR(20), date DATE,
    -> type VARCHAR(15), remark VARCHAR(255));

就象pet表，最容易的示通过创建包含信息的一个定位符分隔的文本文件装载初始记录：

Fluffy | 1995-05-15 | litter | 4 kittens, 3 female, 1 male
Buffy | 1993-06-23 | litter | 5 puppies, 2 female, 3 male
Buffy | 1994-06-19 | litter | 3 puppies, 3 female
Chirpy | 1999-03-21 | vet | needed beak straightened
Slim | 1997-08-03 | vet | broken rib
Bowser | 1991-10-12 | kennel
Fang | 1991-10-12 | kennel
Fang | 1998-08-28 | birthday | Gave him a new chew toy
Claws | 1998-03-17 | birthday | Gave him a new flea collar
Whistler | 1998-12-09 | birthday | First birthday

象这样装载记录：

mysql> LOAD DATA LOCAL INFILE "event.txt" INTO TABLE event;

基于你从已经运行在pet表上的查询中学到的，你应该能执行在event表中记录的检索；原则是一样的。但是什么时候是event表本身不足以回答你可能问的问题呢？

当他们有了一窝小动物时，假定你想要找出每只宠物的年龄。 event表指出何时发生，但是为了计算母亲的年龄，你需要她的出生日期。既然它被存储在pet表中，为了查询你需要两张表：

mysql> SELECT pet.name, (TO_DAYS(date) - TO_DAYS(birth))/365 AS age, remark
    -> FROM pet, event
    -> WHERE pet.name = event.name AND type = "litter";
+--------+------+-----------------------------+
| name   | age  | remark                      |
+--------+------+-----------------------------+
| Fluffy | 2.27 | 4 kittens, 3 female, 1 male |
| Buffy  | 4.12 | 5 puppies, 2 female, 3 male |
| Buffy  | 5.10 | 3 puppies, 3 female         |
+--------+------+-----------------------------+

关于该查询要注意的几件事情：

  • FROM子句列出两个表，因为查询需要从他们两个拉出信息。
  • 当组合(联结-join)来自多个表的信息时，你需要指定在一个表中的记录怎样能匹配其它表的记录。这很简单，因为它们都有一个name列。查询使用WHERE子句基于name值来匹配2个表中的记录。
  • 因为name列出现在两个表中，当引用列时，你一定要指定哪个表。这通过把表名附在列名前做到。

你不必有2个不同的表来执行一个联结。如果你想要将一个表的记录与同一个表的其他记录进行比较，联结一个表到自身有时是有用的。例如，为了在你的宠物之中繁殖配偶，你可以用pet联结自身来进行相似种类的雄雌配对：

mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species
    -> FROM pet AS p1, pet AS p2
    -> WHERE p1.species = p2.species AND p1.sex = "f" AND p2.sex = "m";
+--------+------+--------+------+---------+
| name   | sex  | name   | sex  | species |
+--------+------+--------+------+---------+
| Fluffy | f    | Claws  | m    | cat     |
| Buffy  | f    | Fang   | m    | dog     |
| Buffy  | f    | Bowser | m    | dog     |
+--------+------+--------+------+---------+

在这个查询中，我们为表名指定别名以便能引用列并且使得每一个列引用关联于哪个表实例更直观。

8.5 获得数据库和表的信息

如果你忘记一个数据库或表的名字，或一个给定的表的结构是什么(例如，它的列叫什么)，怎么办？ MySQL通过提供数据库及其支持的表的信息的几个语句解决这个问题。

你已经见到了SHOW DATABASES，它列出由服务器管理的数据库。为了找出当前选择了哪个数据库，使用DATABASE()函数：

mysql> SELECT DATABASE();
+------------+
| DATABASE() |
+------------+
| menagerie  |
+------------+

如果你还没选择任何数据库，结果是空的。

为了找出当前的数据库包含什么表(例如，当你不能确定一个表的名字)，使用这个命令：

mysql> SHOW TABLES;
+---------------------+
| Tables in menagerie |
+---------------------+
| event               |
| pet                 |
+---------------------+

如果你想要知道一个表的结构，DESCRIBE命令是有很用的；它显示有关一个表的每个列的信息：

mysql> DESCRIBE pet;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name    | varchar(20) | YES  |     | NULL    |       |
| owner   | varchar(20) | YES  |     | NULL    |       |
| species | varchar(20) | YES  |     | NULL    |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| birth   | date        | YES  |     | NULL    |       |
| death   | date        | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

Field显示列名字，Type是为列的数据类型，Null表示列是否能包含NULL值，Key显示列是否被索引而Default指定列的缺省值。

如果你在一个表上有索引，SHOW INDEX FROM tbl_name生成有关它们的信息。

8.6 以批处理模式使用mysql

在前面的章节中，你交互式地使用mysql输入查询并且查看结果。你也可以以批模式运行mysql。为了做到这些，把你想要运行的命令放在一个文件中，然后告诉mysql从文件读取它的输入：

shell> mysql < batch-file

如果你需要在命令行上指定连接参数，命令可能看起来像这样：

shell> mysql -h host -u user -p < batch-file
Enter password: ********

当你这样使用mysql时，你正在创建一个脚本文件，然后执行脚本。

为什么要使用一个脚本？有很多原因：

  • 如果你重复地运行查询(比如说，每天或每周)，把它做成一个脚本使得你在每次执行它时避免重新键入。
  • 你能通过拷贝并编辑脚本文件从类似的现有的查询生成一个新查询。
  • 当你正在开发查询时，批模式也是很有用的，特别对多行命令或多行语句序列。如果你犯了一个错误，你不必重新打入所有一切，只要编辑你的脚本来改正错误，然后告诉mysql再次执行它。
  • 如果你有一个产生很多输出的查询，你可以通过一个分页器而不是盯着它翻屏到你屏幕的顶端来运行输出：
    shell> mysql < batch-file | more
  • 你能捕捉输出到一个文件中进行更一步的处理：
    shell> mysql < batch-file > mysql.out
  • 你可以散发脚本给另外的人，因此他们也能运行命令。
  • 一些情况不允许交互地使用，例如, 当你从一个cron任务中运行查询时。在这种情况下，你必须使用批模式。

当你以批模式运行mysql时，比起你交互地使用它时，其缺省输出格式是不同的(更简明些)。例如，当交互式运行SELECT DISTINCT species FROM pet时，输出看起来像这样：

+---------+
| species |
+---------+
| bird    |
| cat     |
| dog     |
| hamster |
| snake   |
+---------+

但是当以批模式运行时，像这样：

species
bird
cat
dog
hamster
snake

如果你想要在批模式中得到交互的输出格式，使用mysql -t。为了回显以输出被执行的命令，使用mysql -vvv。

8.7 双胞胎项目的查询（实例）

在Analytikerna 和 Lentus，我们为一个大的研究项目工程一直在做系统和现场工作。这个项目是Institute of Environmental Medicine at Karolinska Institutet Stockholm 和 the Section on Clinical Research in Aging and Psychology at the University of Southern California的合作项目。

双胞胎研究的更多信息可在下列链接找到：

http://www.imm.ki.se/TWIN/TWINUKW.HTM

项目的后面部分是用一个用Perl和MySQL编写的web接口来管理。

每天晚上所有会谈的数据被移入一个MySQL数据库。

8.7.1 找出所有非独处的双胞胎

下列查询用来决定谁进入项目的第二部分：

select
        concat(p1.id, p1.tvab) + 0 as tvid,
        concat(p1.christian_name, " ", p1.surname) as Name,
        p1.postal_code as Code,
        p1.city as City,
        pg.abrev as Area,
        if(td.participation = "Aborted", "A", " ") as A,
        p1.dead as dead1,
        l.event as event1,
        td.suspect as tsuspect1,
        id.suspect as isuspect1,
        td.severe as tsevere1,
        id.severe as isevere1,
        p2.dead as dead2,
        l2.event as event2,
        h2.nurse as nurse2,
        h2.doctor as doctor2,
        td2.suspect as tsuspect2,
        id2.suspect as isuspect2,
        td2.severe as tsevere2,
        id2.severe as isevere2,
        l.finish_date
from
        twin_project as tp
        /* For Twin 1 */
        left join twin_data as td on tp.id = td.id and tp.tvab = td.tvab
        left join informant_data as id on tp.id = id.id and tp.tvab = id.tvab
        left join harmony as h on tp.id = h.id and tp.tvab = h.tvab
        left join lentus as l on tp.id = l.id and tp.tvab = l.tvab
        /* For Twin 2 */
        left join twin_data as td2 on p2.id = td2.id and p2.tvab = td2.tvab
        left join informant_data as id2 on p2.id = id2.id and p2.tvab = id2.tvab
        left join harmony as h2 on p2.id = h2.id and p2.tvab = h2.tvab
        left join lentus as l2 on p2.id = l2.id and p2.tvab = l2.tvab,
        person_data as p1,
        person_data as p2,
        postal_groups as pg
where
        /* p1 gets main twin and p2 gets his/her twin. */
        /* ptvab is a field inverted from tvab */
        p1.id = tp.id and p1.tvab = tp.tvab and
        p2.id = p1.id and p2.ptvab = p1.tvab and
        /* Just the sceening survey */
        tp.survey_no = 5 and
        /* Skip if partner died before 65 but allow emigration (dead=9) */
        (p2.dead = 0 or p2.dead = 9 or
         (p2.dead = 1 and
          (p2.death_date = 0 or
           (((to_days(p2.death_date) - to_days(p2.birthday)) / 365)
            >= 65))))
        and
        (
        /* Twin is suspect */
        (td.future_contact = 'Yes' and td.suspect = 2) or
        /* Twin is suspect - Informant is Blessed */
        (td.future_contact = 'Yes' and td.suspect = 1 and id.suspect = 1) or
        /* No twin - Informant is Blessed */
        (ISNULL(td.suspect) and id.suspect = 1 and id.future_contact = 'Yes') or
        /* Twin broken off - Informant is Blessed */
        (td.participation = 'Aborted'
         and id.suspect = 1 and id.future_contact = 'Yes') or
        /* Twin broken off - No inform - Have partner */
        (td.participation = 'Aborted' and ISNULL(id.suspect) and p2.dead = 0))
        and
        l.event = 'Finished'
        /* Get at area code */
        and substring(p1.postal_code, 1, 2) = pg.code
        /* Not already distributed */
        and (h.nurse is NULL or h.nurse=00 or h.doctor=00)
        /* Has not refused or been aborted */
        and not (h.status = 'Refused' or h.status = 'Aborted'
        or h.status = 'Died' or h.status = 'Other')
order by
        tvid;

一些解释：

concat(p1.id, p1.tvab) + 0 as tvid
我们想要在id和tvab的连接上以数字序排序。结果加0使得MySQL把结果当作一个数字。
列id
这标识一对双胞胎。它是所有表中的一个键。
列tvab
这标识双胞胎中的一个。它有值1或2。
列ptvab
这是tvab一个逆。当tvab是1，它是2，并且反过来也如此。它存在以保存键入并且使它更容易为MySQL优化查询。

这个查询表明，怎样用联结(p1和p2)从同一个表中查找表。在例子中，这被用来检查双胞胎的一个是否在65岁前死了。如果因此，行不返回。

上述所有双胞胎信息存在于所有表中。我们在id,tvab两者上的键值（所有表)和在id,ptvab上的键(person_data)以使查询更快。

在我们的生产机器上(一台200MHz UltraSPARC)，这个查询返回大约 150-200 行并且不超过一秒的时间。

上面所用的表的当前记录数是：

表 | 行数
person_data | 71074
lentus | 5291
twin_project | 5286
twin_data | 2012
informant_data | 663
harmony | 381
postal_groups | 100

8.7.2 显示关于双胞胎近况的表

每一次会面以一个称为event的状态码结束。下面显示的查询被用来显示按事件组合的所有双胞胎的表。这表明多少对双胞胎已经完成，多少对的其中之一已完成而另一个拒绝了，等等。

select
        t1.event,
        t2.event,
        count(*)
from
        lentus as t1,
        lentus as t2,
        twin_project as tp
where
        /* We are looking at one pair at a time */
        t1.id = tp.id
        and t1.tvab=tp.tvab
        and t1.id = t2.id
        /* Just the sceening survey */
        and tp.survey_no = 5
        /* This makes each pair only appear once */
        and t1.tvab='1' and t2.tvab='2'
group by
        t1.event, t2.event;

到第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册- 9 MySQL服务器功能

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

9 MySQL服务器功能

9.1 MySQL支持哪些语言？

mysqld可以用下列语言发出错误消息：捷克语、荷兰语、英语(缺省)、爱沙尼亚语、法语、德语、匈牙利、意大利语、挪威语。

启动mysqld使用一种特定的语言，使用一个--language=lang或-L lang选项。例如：

shell> mysqld --language=swedish

或：

shell> mysqld --language=/usr/local/share/swedish

注意，所有语言的名称用小写字母指定。

语言文件位于(缺省的)'mysql_base_dir/share/LANGUAGE/'。

为了更新错误消息文件，你应该编辑“errmsg.txt”文件并且执行下列命令生成“errmsg.sys”文件：

shell> comp_err errmsg.txt errmsg.sys

如果你升级到一个更新的MySQL版本，记得要再次用新的“errmsg.txt”文件进行更新。

9.1.1 用于数据和排序的字符集

缺省地，MySQL使用 ISO-8859-1 ( Latin1 ) 字符集。这是在美国和西欧使用的字符集。

字符集决定了在名字中允许什么字符和如何由SELECT语句的ORDER BY和GROUP BY子句排序。

通过给configure以--with-charset=charset选项，你可以在编译时改变字符集。见4.7.1 快速安装概述。

为了把其他字符集加入MySQL，使用下列过程：

9.1.2 增加一个新的字符集

  1. 为字符集选择一个名字，下面用MYSET表示。
  2. 在MySQL源代码分发中创造文件“strings/ctype-MYSET.c”。
  3. 研究一个现有的“ctype-*.c'文件，看需要定义什么。注意，你文件中的数组必须有类似于ctype_MYSET、to_lower_MYSET等等的名字。to_lower[]和to_upper[]是简单的数组，保存字符集每个成员相应的小写和大写字符。例如：
    to_lower['A'] should contain 'a'
to_upper['a'] should contain 'A'

    sort_order[]是一个映射，指出字符为了比较和排序目的应该如何定序。对于许多字符集，这与to_upper[]一样（意味着排序将忽略大小写)。MySQL将基于sort_order[character]值排序字符。ctype[]是一个位值的数组，一个元素对应一个字符。（注意，to_lower[]、to_upper[]和sort_order[]按字符定下标，但是ctype[]按字符值+1定下标。这是一个旧遗产以便能处理EOF) 你能在“m_ctype.h”找到下列bitmask定义：

    #define _U      01      /* Upper case */
#define _L      02      /* Lower case */
#define _N      04      /* Numeral (digit) */
#define _S      010     /* Spacing character */
#define _P      020     /* Punctuation */
#define _C      040     /* Control character */
#define _B      0100    /* Blank */
#define _X      0200    /* heXadecimal digit */

    每个字符的ctype[]的入口应该是描述字符的适用的位模(bitmask)值的联合（union）。例如，'A'是一个大写字符(_U) ，同时是十六进制位(_X)，这样ctype['A'+1]应该包含值：

    _U + _X = 01 + 0200 = 0201
  4. 为你的字符集增加一个唯一的编号到“include/m_ctype.h.in”。
  5. 把字符集名字加到在configure.in中的CHARSETS_AVAILABLE表。
  6. 重新配置，重新编译并且测试。

9.1.3 多字节字符支持

如果你正在创建一个多字节字符集，你可以使用_MB宏。在“include/m_ctype.h.in”，增加：

#define MY_CHARSET_MYSET  X
#if MY_CHARSET_CURRENT == MY_CHARSET_MYSET
#define USE_MB
#define USE_MB_IDENT
#define ismbchar(p, end)  (...)
#define ismbhead(c)       (...)
#define mbcharlen(c)      (...)
#define MBMAXLEN          N
#endif

这里：

MY_CHARSET_MYSET | 一个唯一的字符集值。
USE_MB | 这个字符集有多字节字符，由ismbhead()和mbcharlen()来处理。
USE_MB_IDENT | （可选 ) 如果定义，你能使用多字节字符的表和列名。
ismbchar(p, e) | 如果p不是一个多字节字符字符串，返回0，否则如果它是，返回字符的大小(字节数)。p和e指向字符串的开始和结束。检查是从(char*)p到(char*)e-1。
ismbhead(c) | 如果c是一个多字节字符字符串的第一个字符，返回真。
mbcharlen(c) | 如果c是一个多字节字符串的第一个字符，返回该字符串的大小。
MBMAXLEN | 在字符集中最大字符的字节大小。

9.2 更新日志

当以--log-update=file_name选项启动时，mysqld将所有更新数据的SQL命令写入记录文件中。文件被写入数据目录并且有一个名字file_name.#，这里#是一个数字，它在每次执行mysqladmin refresh或mysqladmin flush-logs、FLUSH LOGS语句、或重启服务器时加1。

如果你使用--log或-l选项，mysqld用一个文件名“hostname.log”写一个通用的记录文件，并且重启和更新不会引起一个新的记录文件生成(尽管它被关闭并且再打开)。缺省地，mysql.server脚本用-l选项启动MySQL服务器，如果当你在生产环境中开始使用MySQL时，你需要好一些的性能，你可以从mysql.server中删除-l选项。

更新记录很聪明，因为它仅仅记载真正更新数据的语句。因此一个用WHERE的UPDATE或DELETE找不到行，它就不被写入记录文件。它甚至跳过将设置一个列为它已经有的值的UPDATE语句。

如果你想要从更新记录文件更新一个数据库，你可以如下做到(假设你的更新记录有“file_name.#”形式的名字)：

shell> ls -1 -t -r file_name.[0-9]* | xargs cat | mysql

ls被用来以正确的次序得到所有的记录文件。

如果你必须在一个崩溃后恢复到备份文件并且你想要再做发生在备份和崩溃之间的更新，这可以很有用。

当你在其他主机上有一个镜像数据库并且你想要复制必须对主数据库进行的改变时，你也可以使用更新记录。

9.3 MySQL数据库表可以有多大?

MySQL 3.22 在表大小上有一个4G的限制。使用在MySQL 3.23中的新MyISAM 最大的表大小可达8百万 TB(2^63个字节)。

然而注意，操作系统有其自身文件大小的限制。在Linux上，当前的限制是2G；在Solaris 2.5.1上，限制是4G；在Solaris 2.6上，限制是1000G。这意味着MySQL表的大小通常由操作系统限制。

缺省地，MySQL表最大尺寸大约4G。你可用SHOW TABLE STATUS命令或myisamchk -dv table_name检查一个表的最大表大小。见7.21 SHOW句法(得到表、列等的信息）。

如果你需要大于 4G 的表(并且你的操作系统支持它)，你应该在你创建表时设定AVG_ROW_LENGTH和MAX_ROWS参数。见7.7 CREATE TABLE语法。你也能用ALTER TABLE在以后设置这些。见7.8 ALTER TABLE语法。

如果你的大表要变成只读，你可以使用myisampack合并并且把许多表压缩成一个。myisampack通常压缩一个表到至少50%，因此你可以有，实际上，更大的表。见12.5 MySQL压缩的只读的表生成器。

另一个的解决方案可以是内含包括MERGE库，它允许你将一个许多相同的表的集合作为一个来处理。（在这种情况下相同意味着所有的表由相同的列信息创建)目前MERGE只能用于扫描一个表集合，因为它不支持索引。我们在不久的将来将把索引加进去。

9.4 MySQL数据库表类型

用MySQL，目前(版本 3.23.6)你可以在三种基本数据库表格式间选择。当你创建一张表时，你可以告诉MySQL它应该对于表使用哪个表类型。MySQL将总是创建一个.frm文件保存表和列定义。视表类型而定，索引和数据将在其他文件中存储。

你能用ALTER TABLE语句在不同类型的表之间变换。见7.8 ALTER TABLE语法。

MyISAM
在MySQL 3.23中，MyISAM是缺省表格类型，它是基于ISAM代码并且有很多有用的扩展。索引存储在一个有.MYI（MYindex)扩展名的文件并且数据存储在有.MYD（MYData)扩展名的文件中。你能用myisamchk实用程序检查/修复MyISAM表。见13.4 对崩溃恢复使用myisamchk。下列几点在MyISAM中是全新的：
  • 不用删除行，可以在表中INSERT一个新行，在其他线程从表中正在读取的同时。
  • 在支持大文件的文件系统/操作系统上支持大文件(63位)。
  • 所有的数据首先存储低字节，这使数据独立于机器和OS，唯一的要求是机器使用补2有符号整数(就像最近20年时间内的每台机器)和IEEE浮点格式(也在主流机器上完全主导地位)。不能支持二进制兼容性的机器的唯一领域是嵌入式系统(因为他们有时有古怪的处理器)。
  • 所有的数字键先存储高字节以获得更高的索引压缩。
  • AUTO_INCREMENT列的内部处理。MyISAM将自动地在INSERT/UPDATE时更新它。 AUTO_INCREMENT值可以用myisamchk重新设置，这将使得AUTO_INCREMENT列更快速并且原来的数将不象老的ISAM那样被重新使用。注意，当一个AUTO_INCREMENT定义在一个多部键值(multi-part-key)的结尾时，老式的行为仍然是存在。
  • BLOB和TEXT列可以被索引。
  • 被索引的列允许NULL值。每个键占0-1个字节。
  • 现在最大的键长度缺省是500个字节。在键大于250个字节的情况下，一个大于缺省的1024个字节的关键字块大小被用于此键。
  • 每个表的键的最大数目放大到32作为缺省。这不必重新编译myisamchk就可以放大到64。
  • 在有一个标志MyISAM显示桌子是否正确被关上的文件。这将不久被用于自动的修理在MySQL服务器。
  • 现在myisamchk将标记表为“检查的”。myisamchk --fast将仅仅检查那些没有这个标记的表。
  • myisamchk -a存储键值组成部分的统计(不只是像ISAM对整个键)。
  • 现在在删除与更新和插入混用时，动态尺寸的行将有更少碎片，这通过自动合并相邻的删除块并且如果下一块被删除，通过扩大块来做到。
  • myisampack能紧缩BLOB和VARCHAR列。

MyISAM也支持下列东西，MySQL在不久的将来将能使用。

  • 支持一个真正的VARCHAR类型；一个VARCHAR列以2各字节存储的长度开始。
  • 用VARCHAR的表可以式固定或动态的记录长度。
  • VARCHAR和CHAR可以最大64K字节。所有的关键字片断有其自身的语言定义，这将使得MySQL每列有不同的语言定义。
  • 一个杂凑计算的索引可用于UNIQUE；这将允许你在一个表中的任何列组合上有UNIQUE属性。（然而，你不能搜索一个UNIQUE计算的索引。）

你也可以使用放弃的ISAM桌子类型。这将在不久消失，因为MyISAM是同一个东西的更好实现。ISAM使用一个B-tree索引，这个索引存储在一个有.ISM扩展名的文件中并且数据存储在有.ISD扩展名的文件中，你可用isamchk实用程序检查/修复ISAM表。见13.4 使用myisamchk恢复崩溃。ISAM表不是跨OS/平台二进制可移植的。ISAM有下列特征/属性：

  • 压缩的且定长键
  • 固定和动态记录长度
  • 有16个键，每个键有16键组成部分
  • 最大键长度256(缺省）
  • 数据以机器格式存储；快速但是依赖于机器/OS 。
HEAP
HEAP表格使用一个杂凑（hashed）索引并且存储在内存中。这使他们更快，但是如果MySQL崩溃，你将失去所有存储的数据。HEAP作为临时表很可用！
CREATE TABLE test TYPE=HEAP SELECT ip,SUM(downloads) as down
        FROM log_table GROUP BY ip;
SELECT COUNT(ip),AVG(down) FROM test;
DROP TABLE test;

当你使用HEAP表时，这里是你应该考虑的一些事情：

  • 你应该总是在CREATE语句中指定MAX_ROWS以保证你有意不使用所有的内存。
  • 索引将只能与与=和<=>一起使用（但是很快)。
  • HEAP表使用一个固定的记录长度格式。
  • HEAP不支持BLOB/TEXT列。
  • HEAP不支持AUTO_INCREMENT列。
  • HEAP不支持在一个NULL列上的索引。
  • 你可以在一个HEAP表中有非唯一键(杂凑表一般不这样)。
  • HEAP表格在所有的客户之间被共享(就象任何其他的表)。
  • HEAP表的数据以小块分配。表是100%动态的(在插入时)，无需溢出区和额外的键空间。删除的行放入一个链接表并且当你把新数据插入到表时，它将被再次使用。
  • 为了释放内存，你应该执行DELETE FROM heap_table或DROP TABLE heap_table。
  • 为了保证你不会偶然做些愚蠢的事情，你不能创建比max_heap_table_size大的HEAP表。

到第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册- 10 从MySQL得到最大的性能

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

10 从MySQL得到最大的性能

优化是一项复杂的任务，因为它最终需要对整个系统的理解。当用你的系统/应用的小知识做一些局部优化是可能的时候，你越想让你的系统更优化，你必须知道它也越多。

因此，本章将试图解释并给出优化MySQL的不同方法的一些例子。但是记住总是有某些(逐渐变难)是系统更快的方法留着去做。

10.1 优化概述

为了使一个系统更快的最重要部分当然是基本设计。你也需要知道你的系统将做这样的事情，那就是你的瓶颈。

最常见的瓶颈是：

  • 磁盘寻道。磁盘花时间找到一个数据，用在1999年的现代磁盘其平均时间通常小于10ms，因此理论上我们能大约一秒寻道 1000 次。这个时间用新磁盘提高很慢并且很难对一个表优化。优化它的方法是将数据散布在多个磁盘上。
  • 当磁盘在我们需要读数据的正确位置时，磁盘读/写。用1999年的现代，一个磁盘传输类似10-20Mb/s。这必寻道更容易优化，因为你能从多个磁盘并行地读。
  • CPU周期。当我们读数据进内存时，(或如果它已经在那里)我们需要处理它以达到我们的结果。当我们有相对内存较小的表时，这是最常见的限制因素，但是用小表速度通常不是问题。
  • 内存带宽。当CPU需要超出适合cpu缓存的数据时，缓存带宽就成为内存的一个瓶颈。这是对大多数系统的一个不常见的瓶颈但是你应该知道它。

10.2 系统/编译时和启动参数的调节

我们以系统级的东西开始，因为这些决策的某一些很早就做好了。在其他情况下，快速浏览这部分可能就够了，因为它对大收获并不重要，但是有一个关于在这个层次上收获有多大的感觉总是好的。

使用的缺省OS确实重要！为了最大程度地使用多CPU，应该使用Solaris(因为线程工作得确实不错)或Linux(因为2.2本的核心又确实不错的SMP支持)。而且在32位的机器上，Linux缺省有2G的文件大小限制。当新的文件系统被释出时( XFS )，希望这不久被修正。

因为我们没在很多平台上运行生产MySQL，我们忠告你在可能选择它前，测试你打算运行的平台。

其他建议：

  • 如果你有足够的RAM，你能删除所有交换设备。一些操作系统在某些情况下将使用一个SWAP设备，即使你有空闲的内存。
  • 使用--skip-locking的MySQL选项避免外部锁定。注意这将不影响MySQL功能，只要它仅运行在一个服务器上。只要在你运行myisamchk以前，记得要停掉服务器(或锁定相关部分)。在一些系统上这个开关是强制的，因为外部锁定不是在任何情况下都工作。当用MIT-pthreads编译时，--skip-locking选项缺省为打开(on)，因为flock()没在所有的平台上被MIT-pthreads充分支持。唯一的情况是如果你对同一数据运行MySQL服务器(不是客户)，你不能使用--skip-locking之时，否则对没有先清掉(flushing)或先锁定mysqld服务器的表上运行myisamchk。你仍然能使用LOCK TABLES/ UNLOCK TABLES，即使你正在使用--skip-locking。

10.2.1 编译和链接怎样影响MySQL的速度

大多数下列测试在Linux上并用MySQL基准进行的，但是它们应该对其他操作系统和工作负载给出一些指示。

当你用-static链接时，你得到最快的可执行文件。使用Unix套接字而非TCP/IP连接一个数据库也可给出好一些的性能。

在Linux上，当用pgcc和-O6编译时，你将得到最快的代码。为了用这些选项编译“sql_yacc.cc”，你需要大约200M内存，因为gcc/pgcc需要很多内存使所有函数嵌入（inline）。在配置MySQL时，你也应该设定CXX=gcc以避免包括libstdc++库(它不需要)。

只通过使用一个较好的编译器或较好的编译器选项，在应用中你能得到一个10-30%的加速。如果你自己编译SQL服务器，这特别重要！

在Intel上，你应该例如使用pgcc或Cygnus CodeFusion编译器得到最大速度。我们已经测试了新的 Fujitsu编译器，但是它是还没足够不出错来优化编译MySQL。

这里是我们做过的一些测量表：

  • 如果你以-O6使用pgcc并且编译任何东西，mysqld服务器是比用gcc快11%（用字符串99的版本)。
  • 如果你动态地链接(没有-static)，结果慢了13%。注意你仍能使用一个动态连接的MySQL库。只有服务器对性能是关键的。
  • 如果你使用TCP/IP而非Unix套接字，结果慢7.5%。
  • 在一个Sun SPARCstation 10上，gcc2.7.3是比Sun Pro C++ 4.2快13%。
  • 在Solaris 2.5.1上，在单个处理器上MIT-pthreads比带原生线程的Solaris慢8-12%。以更多的负载/cpus，差别应该变得更大。

由TcX提供的MySQL-Linux的分发用pgcc编译并静态链接。

10.2.2 磁盘问题

  • 正如前面所述，磁盘寻道是一个性能的大瓶颈。当数据开始增长以致缓存变得不可能时，这个问题变得越来越明显。对大数据库，在那你或多或少地要随机存取数据，你可以依靠你将至少需要一次磁盘寻道来读取并且几次磁盘寻道写入。为了使这个问题最小化，使用有低寻道时间的磁盘。
  • 为了增加可用磁盘轴的数量(并且从而减少寻道开销)，符号联接文件到不同磁盘或分割磁盘是可能的。
    使用符号连接
    这意味着你将索引/数据文件符号从正常的数据目录链接到其他磁盘(那也可以被分割的)。这使得寻道和读取时间更好(如果磁盘不用于其他事情)。见10.2.2.1 使用数据库和表的符号链接。
    分割
    分割意味着你有许多磁盘并把第一块放在第一个磁盘上，在第二块放在第二个磁盘上，并且第 n块在第(n mod number_of_disks)磁盘上，等等。这意味着，如果你的正常数据大小于分割大小(或完美地排列过)，你将得到较好一些的性能。注意，分割是否很依赖于OS和分割大小。因此用不同的分割大小测试你的应用程序。见10.8 使用你自己的基准。注意对分割的速度差异很依赖于参数，取决于你如何分割参数和磁盘数量，你可以得出以数量级的不同。注意你必须选择为随机或顺序存取优化。
  • 为了可靠，你可能想要使用袭击RAID 0+1(分割+镜像)，但是在这种情况下，你将需要2*N个驱动器来保存N个驱动器的数据。如果你有钱，这可能是最好的选择！然而你也可能必须投资一些卷管理软件投资以高效地处理它。
  • 一个好选择是让稍重要的数据(它能再生)上存在RAID 0磁盘上，而将确实重要的数据(像主机信息和日志文件)存在一个RAID 0+1或RAID N磁盘上。如果因为更新奇偶位你有许多写入，RAID N可能是一个问题。
  • 你也可以对数据库使用的文件系统设置参数。一个容易的改变是以noatime选项挂装文件系统。这是它跳过更新在inode中的最后访问时间，而且这将避免一些磁盘寻道。

10.2.2.1 为数据库和表使用符号链接

你可以从数据库目录移动表和数据库到别处，并且用链接到新地点的符号代替它们。你可能想要这样做，例如，转移一个数据库到有更多空闲空间的一个文件系统。

如果MySQL注意到一个表是一个符号链接，它将解析符号链接并且使用其实际指向的表，它可工作在支持realpath()调用的所有系统上(至少Linux和Solaris支持realpath())！在不支持realpath()的系统上，你应该不同时通过真实路径和符号链接访问表！如果你这样做，表在任何更新后将不一致。

MySQL缺省不支持数据库链接。只要你不在数据库之间做一个符号链接，一切将工作正常。假定你在MySQL数据目录下有一个数据库db1，并且做了一个符号链接db2指向db1：

shell> cd /path/to/datadir
shell> ln -s db1 db2

现在，对在db1中的任一表tbl_a，在db2种也好象有一个表tbl_a。如果一个线程更新db1.tbl_a并且另一个线程更新db2.tbl_a，将有问题。

如果你确实需要这样，你必须改变下列在“mysys/mf_format.c”中的代码：

if (!lstat(to,&stat_buff))  /* Check if it's a symbolic link */
    if (S_ISLNK(stat_buff.st_mode) && realpath(to,buff))

把代码改变为这样：

if (realpath(to,buff))

10.2.3 调节服务器参数

你能用这个命令得到mysqld服务器缺省缓冲区大小：

shell> mysqld --help

这个命令生成一张所有mysqld选项和可配置变量的表。输出包括缺省值并且看上去象这样一些东西：

Possible variables for option --set-variable (-O) are:
back_log              current value: 5
connect_timeout       current value: 5
delayed_insert_timeout  current value: 300
delayed_insert_limit  current value: 100
delayed_queue_size    current value: 1000
flush_time            current value: 0
interactive_timeout   current value: 28800
join_buffer_size      current value: 131072
key_buffer_size       current value: 1048540
lower_case_table_names  current value: 0
long_query_time       current value: 10
max_allowed_packet    current value: 1048576
max_connections       current value: 100
max_connect_errors    current value: 10
max_delayed_threads   current value: 20
max_heap_table_size   current value: 16777216
max_join_size         current value: 4294967295
max_sort_length       current value: 1024
max_tmp_tables        current value: 32
max_write_lock_count  current value: 4294967295
net_buffer_length     current value: 16384
query_buffer_size     current value: 0
record_buffer         current value: 131072
sort_buffer           current value: 2097116
table_cache           current value: 64
thread_concurrency    current value: 10
tmp_table_size        current value: 1048576
thread_stack          current value: 131072
wait_timeout          current value: 28800

如果有一个mysqld服务器正在运行，通过执行这个命令，你可以看到它实际上使用的变量的值：

shell> mysqladmin variables

每个选项在下面描述。对于缓冲区大小、长度和栈大小的值以字节给出，你能用于个后缀“K”或“M” 指出以K字节或兆字节显示值。例如，16M指出16兆字节。后缀字母的大小写没有关系；16M和16m是相同的。

你也可以用命令SHOW STATUS自一个运行的服务器看见一些统计。见7.21 SHOW语法(得到表、列的信息)。

back_log
要求MySQL能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求，这就起作用，然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接，你需要增加它，换句话说，这值对到来的TCP/IP连接的侦听队列的大小。你的操作系统在这个队列大小上有它自己的限制。 Unix listen(2)系统调用的手册页应该有更多的细节。检查你的OS文档找出这个变量的最大值。试图设定back_log高于你的操作系统的限制将是无效的。
connect_timeout
mysqld服务器在用Bad handshake（糟糕的握手）应答前正在等待一个连接报文的秒数。
delayed_insert_timeout
一个INSERT DELAYED线程应该在终止之前等待INSERT语句的时间。
delayed_insert_limit
在插入delayed_insert_limit行后，INSERT DELAYED处理器将检查是否有任何SELECT语句未执行。如果这样，在继续前执行允许这些语句。
delayed_queue_size
应该为处理INSERT DELAYED分配多大一个队列(以行数)。如果排队满了，任何进行INSERT DELAYED的客户将等待直到队列又有空间了。
flush_time
如果这被设置为非零值，那么每flush_time秒所有表将被关闭(以释放资源和sync到磁盘)。
interactive_timeout
服务器在关上它前在一个交互连接上等待行动的秒数。一个交互的客户被定义为对mysql_real_connect()使用CLIENT_INTERACTIVE选项的客户。也可见wait_timeout。
join_buffer_size
用于全部联结(join)的缓冲区大小(不是用索引的联结)。缓冲区对2个表间的每个全部联结分配一次缓冲区，当增加索引不可能时，增加该值可得到一个更快的全部联结。（通常得到快速联结的最佳方法是增加索引。）
key_buffer_size
索引块是缓冲的并且被所有的线程共享。key_buffer_size是用于索引块的缓冲区大小，增加它可得到更好处理的索引(对所有读和多重写)，到你能负担得起那样多。如果你使它太大，系统将开始换页并且真的变慢了。记住既然MySQL不缓存读取的数据，你将必须为OS文件系统缓存留下一些空间。为了在写入多个行时得到更多的速度，使用LOCK TABLES。见7.24LOCK TABLES/UNLOCK TABLES语法。
long_query_time
如果一个查询所用时间超过它(以秒计)，Slow_queries记数器将被增加。
max_allowed_packet
一个包的最大尺寸。消息缓冲区被初始化为net_buffer_length字节，但是可在需要时增加到max_allowed_packet个字节。缺省地，该值太小必能捕捉大的(可能错误)包。如果你正在使用大的BLOB列，你必须增加该值。它应该象你想要使用的最大BLOB的那么大。
max_connections
允许的同时客户的数量。增加该值增加mysqld要求的文件描述符的数量。见下面对文件描述符限制的注释。见18.2.4 Too many connections错误。
max_connect_errors
如果有多于该数量的从一台主机中断的连接，这台主机阻止进一步的连接。你可用FLUSH HOSTS命令疏通一台主机。
max_delayed_threads
不要启动多于的这个数字的线程来处理INSERT DELAYED语句。如果你试图在所有INSERT DELAYED线程在用后向一张新表插入数据，行将被插入，就像DELAYED属性没被指定那样。
max_join_size
可能将要读入多于max_join_size个记录的联结将返回一个错误。如果你的用户想要执行没有一个WHERE子句、花很长时间并且返回百万行的联结，设置它。
max_sort_length
在排序BLOB或TEXT值时使用的字节数(每个值仅头max_sort_length个字节被使用；其余的被忽略)。
max_tmp_tables
（该选择目前还不做任何事情)。一个客户能同时保持打开的临时表的最大数量。
net_buffer_length
通信缓冲区在查询之间被重置到该大小。通常这不应该被改变，但是如果你有很少的内存，你能将它设置为查询期望的大小。（即，客户发出的SQL语句期望的长度。如果语句超过这个长度，缓冲区自动地被扩大，直到max_allowed_packet个字节。）
record_buffer
每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描，你可能想要增加该值。
sort_buffer
每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速ORDER BY或GROUP BY操作。见18.5 MySQL在哪儿存储临时文件。
table_cache
为所有线程打开表的数量。增加该值能增加mysqld要求的文件描述符的数量。MySQL对每个唯一打开的表需要2个文件描述符，见下面对文件描述符限制的注释。对于表缓存如何工作的信息，见10.2.4 MySQL怎样打开和关闭表。
tmp_table_size
如果一张临时表超出该大小，MySQL产生一个The table tbl_name is full形式的错误，如果你做很多高级GROUP BY查询，增加tmp_table_size值。
thread_stack
每个线程的栈大小。由crash-me测试检测到的许多限制依赖于该值。缺省队一般的操作是足够大了。见10.8 使用你自己的基准。
wait_timeout
服务器在关闭它之前在一个连接上等待行动的秒数。也可见interactive_timeout。

MySQL使用是很具伸缩性的算法，因此你通常能用很少的内存运行或给MySQL更多的被存以得到更好的性能。

如果你有很多内存和很多表并且有一个中等数量的客户，想要最大的性能，你应该一些象这样的东西：

shell> safe_mysqld -O key_buffer=16M -O table_cache=128 \
           -O sort_buffer=4M -O record_buffer=1M &

如果你有较少的内存和大量的连接，使用这样一些东西：
shell> safe_mysqld -O key_buffer=512k -O sort_buffer=100k \
           -O record_buffer=100k &

或甚至：
shell> safe_mysqld -O key_buffer=512k -O sort_buffer=16k \
           -O table_cache=32 -O record_buffer=8k -O net_buffer=1K &

如果有很多连接，“交换问题”可能发生，除非mysqld已经被配置每个连接使用很少的内存。当然如果你对所有连接有足够的内存，mysqld执行得更好。

注意，如果你改变mysqld的一个选项，它实际上只对服务器的那个例子保持。

为了明白一个参数变化的效果，这样做：

shell> mysqld -O key_buffer=32m --help

保证--help选项是最后一个；否则，命令行上在它之后列出的任何选项的效果将不在反映在输出中。

10.2.4 MySQL怎样打开和关闭数据库表

table_cache, max_connections和max_tmp_tables影响服务器保持打开的文件的最大数量。如果你增加这些值的一个或两个，你可以遇到你的操作系统每个进程打开文件描述符的数量上强加的限制。然而，你可以能在许多系统上增加该限制。请教你的OS文档找出如何做这些，因为改变限制的方法各系统有很大的不同。

table_cache与max_connections有关。例如，对于200个打开的连接，你应该让一张表的缓冲至少有200 * n，这里n是一个联结(join)中表的最大数量。

打开表的缓存可以增加到一个table_cache的最大值（缺省为64；这可以用mysqld的-O table_cache=#选项来改变）。一个表绝对不被关闭，除非当缓存满了并且另外一个线程试图打开一个表时或如果你使用mysqladmin refresh或mysqladmin flush-tables。

当表缓存满时，服务器使用下列过程找到一个缓存入口来使用：

  • 不是当前使用的表被释放，以最近最少使用（LRU）顺序。
  • 如果缓存满了并且没有表可以释放，但是一个新表需要打开，缓存必须临时被扩大。
  • 如果缓存处于一个临时扩大状态并且一个表从在用变为不在用状态，它被关闭并从缓存中释放。

对每个并发存取打开一个表。这意味着，如果你让2个线程存取同一个表或在同一个查询中存取表两次(用AS)，表需要被打开两次。任何表的第一次打开占2个文件描述符；表的每一次额外使用仅占一个文件描述符。对于第一次打开的额外描述符用于索引文件；这个描述符在所有线程之间共享。

10.2.5 在同一个数据库中创建大量数据库表的缺点

如果你在一个目录中有许多文件，打开、关闭和创建操作将会很慢。如果你执行在许多不同表上的SELECT语句，当表缓存满时，将有一点开销，因为对每个必须打开的表，另外一个必须被关闭。你可以通过使表缓冲更大些来减少这个开销。

10.2.6 为什么有这么多打开的表？

当你运行mysqladmin status时，你将看见象这样的一些东西：

Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12

如果你仅有6个表，这可能有点令人困惑。

MySQL是多线程的，因此它可以同时在同一个表上有许多询问。为了是2个线程在同一个文件上有不同状态的问题减到最小，表由每个并发进程独立地打开。这为数据文件消耗一些内存和一个额外的文件描述符。索引文件描述符在所有线程之间共享。

10.2.7 MySQL怎样使用内存

下表指出mysqld服务器使用存储器的一些方式。在应用的地方，给出与存储器使用相关的服务器变量的名字。

  • 关键字缓冲区(变量key_buffer_size)由所有线程分享；当需要时，分配服务器使用的其他缓冲区。见10.2.3 调节服务器参数。
  • 每个连接使用一些线程特定的空间；一个栈(缺省64K，变量thread_stack)、一个连接缓冲区(变量net_buffer_length)和一个结果缓冲区(变量net_buffer_length)。当需要时，连接缓冲区和结果缓冲区动态地被扩大到max_allowed_packet。当一个查询正在运行当前查询的一个拷贝时，也分配字符串。
  • 所有线程共享同一基存储器。
  • 目前还没有什么是内存映射的(除了压缩表，但是那是另外一个的故事)。这是因为4GB的32位存储器空间对最大的数据库来所不是足够大的。当一个64位寻址空间的系统变得更普遍时，我们可以为内存映射增加全面的支持。
  • 每个做顺序扫描的请求分配一个读缓冲区(变量record_buffer)。
  • 所有联结均用一遍完成并且大多数联结可以甚至不用一张临时表来完成。最临时的表是基于内存的(HEAP)表。有较大记录长度(以所有列的长度之和计算)的临时表或包含BLOB列的表在磁盘上存储。在MySQL版本3.23.2前一个问题是如果一张HEAP表超过tmp_table_size的大小，你得到错误The table tbl_name is full。在更新的版本中，这通过必要时自动将在内存的(HEAP)表转变为一个基于磁盘(MyISAM)的表来处理。为了解决这个问题，你可以通过设置mysqld的tmp_table_size选项，或通过在客户程序中设置SQL的SQL_BIG_TABLES选项增加临时表的大小。见7.25 SET OPTION句法。在MySQL 3.20中，临时表的最大尺寸是record_buffer*16，因此如果你正在使用这个版本，你必须增加record_buffer值。你也可以使用--big-tables选项启动mysqld以总将临时表存储在磁盘上，然而，这将影响许多复杂查询的速度。
  • 大多数做排序的请求分配一个排序缓冲区和一个或二个临时文件。见18.5 MySQL在哪儿存储临时文件。
  • 几乎所有的语法分析和计算都在一家本地存储器中完成。对小项目没有内存开销并且一般的较慢存储器分配和释放被避免。内存仅为出乎意料的大字符串分配(这用malloc()和free()完成)。
  • 每个索引文件只被打开一次，并且数据文件为每个并发运行的线程打开一次。对每个并发线程，分配一个表结构、对每列的列结构和大小为3 * n的一个缓冲区(这里n是最大的行长度，不算BLOB列)。一个BLOB使用5 ～ 8个字节加上BLOB数据。
  • 对每个有BLOB列的表，一个缓冲区动态地被扩大以便读入更大的BLOB值。如果你扫描一个表，分配与最大BLOB值一样大的一个缓冲区。
  • 对所有在用的表的表处理器被保存在一个缓存中并且作为一个FIFO管理。通常缓存有64个入口。如果一个表同时被2个运行的线程使用，缓存为此包含2个入口。见10.2.4 MySQL如何打开和关闭数据库表。
  • 一个mysqladmin flush-tables命令关闭所有不在用的表并在当前执行的线程结束时，标记所有在用的表准备被关闭。这将有效地释放大多数在用的内存。

ps和其他系统状态程序可以报导mysqld使用很多内存。这可以是在不同的内存地址上的线程栈造成的。例如，Solaris版本的ps将栈间未用的内存算作已用的内存。你可以通过用swap -s检查可用交换区来验证它。我们用商业内存漏洞探查器测试了mysqld，因此应该有没有内存漏洞。

10.2.8 MySQL怎样锁定数据库表

MySQL中所有锁定不会是死锁的。这通过总是在一个查询前立即请求所有必要的锁定并且总是以同样的顺序锁定表来管理。

对WRITE，MySQL使用的锁定方法原理如下：

  • 如果在表上没有锁，放一个锁在它上面。
  • 否则，把锁定请求放在写锁定队列中。

对READ，MySQL使用的锁定方法原理如下：

  • 如果在表上没有写锁定，把一个读锁定放在它上面。
  • 否则，把锁请求放在读锁定队列中。

当一个锁定被释放时，锁定可被写锁定队列中的线程得到，然后是读锁定队列中的线程。

这意味着，如果你在一个表上有许多更改，SELECT语句将等待直到有没有更多的更改。

为了解决在一个表中进行很多INSERT和SELECT操作的情况，你可在一张临时表中插入行并且偶尔用来自临时表的记录更新真正的表。

这可用下列代码做到：

mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
mysql> insert into real_table select * from insert_table;
mysql> delete from insert_table;
mysql> UNLOCK TABLES;

如果你在一些特定的情况字下区分检索的优先次序，你可以使用LOW_PRIORITY选项的INSERT。见7.14 INSERT句法。

你也能改变在“mysys/thr_lock.c”中的锁代码以使用一个单个队列。在这种情况下，写锁定和读锁定将有同样优先级，它可能帮助一些应用程序。

10.2.9 数据库表级锁定的问题

MySQL的表锁定代码是不会死锁的。

MySQL使用表级锁定(而不是行级锁定或列级锁定)以达到很高的锁定速度。对于大表，表级锁定对大多数应用程序来说比行级锁定好一些，但是当然有一些缺陷。

在MySQL3.23.7和更高版本中，一个人能把行插入到MyISAM表同时其他线程正在读该表。注意，目前只有在表中内有删除的行时才工作。

表级锁定使很多线程能够同时读一个表，但是如果一个线程想要写一个表，它必须首先得到独占存取权。在更改期间，所有其他想要存取该特定表的线程将等到更改就绪。

因为数据库的更改通常被视为比SELECT更重要，更新一个表的所有语句比从一个表中检索信息的语句有更高的优先级。这应该保证更改不被“饿死”，因为一个人针对一个特定表会发出很多繁重的查询。

从MySQL 3.23.7开始，一个人可以能使用max_write_lock_count变量强制MySQL在一个表上一个特定数量的插入后发出一个SELECT。

对此一个主要的问题如下：

  • 一个客户发出一个花很长时间运行的SELECT。
  • 然后其他客户在一个使用的表上发出一个UPDATE；这个客户将等待直到SELECT完成。
  • 另一个客户在同一个表上发出另一个SELECT语句；因为UPDATE比SELECT有更高的优先级，该SELECT将等待UPDATE的完成。它也将等待第一个SELECT完成！

对这个问题的一些可能的解决方案是：

  • 试着使SELECT语句运行得更快；你可能必须创建一些摘要(summary)表做到这点。
  • 用--low-priority-updates启动mysqld。这将给所有更新(修改)一个表的语句以比SELECT语句低的优先级。在这种情况下，在先前情形的最后的SELECT语句将在INSERT语句前执行。
  • 你可以用LOW_PRIORITY属性给与一个特定的INSERT、UPDATE或DELETE语句较低优先级。
  • 为max_write_lock_count指定一个低值来启动mysqld使得在一定数量的WRITE锁定后给出READ锁定。
  • 通过使用SQL命令：SET SQL_LOW_PRIORITY_UPDATES=1，你可从一个特定线程指定所有的更改应该由用低优先级完成。见7.25 SET OPTION句法。
  • 你可以用HIGH_PRIORITY属性指明一个特定SELECT是很重要的。见7.12 SELECT句法。
  • 如果你有关于INSERT结合SELECT的问题，切换到使用新的MyISAM表，因为它们支持并发的SELECT和INSERT。
  • 如果你主要混合INSERT和SELECT语句，DELAYED属性的INSERT将可能解决你的问题。见7.14 INSERT句法。
  • 如果你有关于SELECT和DELETE的问题，LIMIT选项的DELETE可以帮助你。见7.11 DELETE句法。

10.3 使你的数据尽可能小

最基本的优化之一是使你的数据(和索引)在磁盘上(并且在内存中)占据的空间尽可能小。这能给出巨大的改进，因为磁盘读入较快并且通常也用较少的主存储器。如果在更小的列上做索引，索引也占据较少的资源。

你能用下面的技术使表的性能更好并且使存储空间最小：

  • 尽可能地使用最有效(最小)的类型。MySQL有很多节省磁盘空间和内存的专业化类型。
  • 如果可能使表更小，使用较小的整数类型。例如，MEDIUMINT经常比INT好一些。
  • 如果可能，声明列为NOT NULL。它使任何事情更快而且你为每列节省一位。注意如果在你的应用程序中你确实需要NULL，你应该毫无疑问使用它，只是避免缺省地在所有列上有它。
  • 如果你没有任何变长列(VARCHAR、TEXT或BLOB列)，使用固定尺寸的记录格式。这比较快但是不幸地可能会浪费一些空间。见10.6 选择一种表类型。
  • 每张桌子应该有尽可能短的主索引。这使一行的辨认容易而有效。
  • 对每个表，你必须决定使用哪种存储/索引方法。见9.4 MySQL表类型。也可参见10.6 选择一种表类型。
  • 只创建你确实需要的索引。索引对检索有好处但是当你需要快速存储东西时就变得糟糕。如果你主要通过搜索列的组合来存取一个表，以它们做一个索引。第一个索引部分应该是最常用的列。如果你总是使用许多列，你应该首先以更多的副本使用列以获得更好的列索引压缩。
  • 如果很可能一个索引在头几个字符上有唯一的前缀，仅仅索引该前缀比较好。MySQL支持在一个字符列的一部分上的索引。更短的索引更快，不仅因为他们占较少的磁盘空间而且因为他们将在索引缓存中给你更多的命中率并且因此有更少磁盘寻道。见10.2.3 调节服务器参数。
  • 在一些情形下，分割一个经常被扫描进2个表的表是有益的。特别是如果它是一个动态格式的表并且它可能使一个能用来扫描后找出相关行的较小静态格式的表。

10.4 MySQL索引的使用

索引被用来快速找出在一个列上用一特定值的行。没有索引，MySQL不得不首先以第一条记录开始并然后读完整个表直到它找出相关的行。表越大，花费时间越多。如果表对于查询的列有一个索引，MySQL能快速到达一个位置去搜寻到数据文件的中间，没有必要考虑所有数据。如果一个表有1000行，这比顺序读取至少快100倍。注意你需要存取几乎所有1000行，它较快的顺序读取，因为此时我们避免磁盘寻道。

所有的MySQL索引(PRIMARY、UNIQUE和INDEX)在B树中存储。字符串是自动地压缩前缀和结尾空间。见7.27 CREATE INDEX句法。

索引用于：

  • 快速找出匹配一个WHERE子句的行。
  • 当执行联结时，从其他表检索行。
  • 对特定的索引列找出MAX()或MIN()值。
  • 如果排序或分组在一个可用键的最左面前缀上进行(例如，ORDER BY key_part_1,key_part_2)，排序或分组一个表。如果所有键值部分跟随DESC，键以倒序被读取。
  • 在一些情况中，一个查询能被优化来检索值，不用咨询数据文件。如果对某些表的所有使用的列是数字型的并且构成某些键的最左面前缀，为了更快，值可以从索引树被检索出来。

假定你发出下列SELECT语句：

mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;

如果一个多列索引存在于col1和col2上，适当的行可以直接被取出。如果分开的单行列索引存在于col1和col2上，优化器试图通过决定哪个索引将找到更少的行并来找出更具限制性的索引并且使用该索引取行。

如果表有一个多列索引，任何最左面的索引前缀能被优化器使用以找出行。例如，如果你有一个3行列索引(col1,col2,col3)，你已经索引了在(col1)、(col1,col2)和(col1,col2,col3)上的搜索能力。

如果列不构成索引的最左面前缀，MySQL不能使用一个部分的索引。假定你下面显示的SELECT语句：

mysql> SELECT * FROM tbl_name WHERE col1=val1;
mysql> SELECT * FROM tbl_name WHERE col2=val2;
mysql> SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;

如果一个索引存在于(col1、col2、col3)上，只有上面显示的第一个查询使用索引。第二个和第三个查询确实包含索引的列，但是(col2)和(col2、col3)不是(col1、col2、col3)的最左面前缀。

如果LIKE参数是一个不以一个通配符字符起始的一个常数字符串，MySQL也为LIKE比较使用索引。例如，下列SELECT语句使用索引：

mysql> select * from tbl_name where key_col LIKE "Patrick%";
mysql> select * from tbl_name where key_col LIKE "Pat%_ck%";

在第一条语句中，只考虑有"Patrick" <= key_col < "Patricl"的行。在第二条语句中，只考虑有"Pat" <= key_col < "Pau"的行。

下列SELECT语句将不使用索引：

mysql> select * from tbl_name where key_col LIKE "%Patrick%";
mysql> select * from tbl_name where key_col LIKE other_col;

在第一条语句中，LIKE值以一个通配符字符开始。在第二条语句中，LIKE值不是一个常数。

如果 column_name 是一个索引，使用column_name IS NULL的搜索将使用索引。

MySQL通常使用找出最少数量的行的索引。一个索引被用于你与下列操作符作比较的列：=、>、>=、<、<=、BETWEEN和一个有一个非通配符前缀象'something%'的LIKE的列。

任何不跨越的在WHERE子句的所有AND层次的索引不用来优化询问。

下列WHERE子句使用索引：

... WHERE index_part1=1 AND index_part2=2
... WHERE index=1 OR A=10 AND index=2      /* index = 1 OR index = 2 */
... WHERE index_part1='hello' AND index_part_3=5
          /* optimized like "index_part1='hello'" */

这些WHERE子句不使用索引：

... WHERE index_part2=1 AND index_part3=2  /* index_part_1 is not used */
... WHERE index=1 OR A=10                  /* No index */
... WHERE index_part1=1 OR index_part2=10  /* No index spans all rows */

10.5 存取或更新数据的查询速度

首先，一件事情影响所有的询问。你有的许可系统设置越复杂，你得到更多的开销。

如果你不让任何GRANT语句执行，MySQL将稍微优化许可检查。因此如果你有很大量，值得花时间来避免授权，否则更多的许可检查有更大的开销。

如果你的问题是与一些明显的MySQL函数有关，你总能在MySQL客户中计算其时间：

mysql> select benchmark(1000000,1+1);
+------------------------+
| benchmark(1000000,1+1) |
+------------------------+
|                      0 |
+------------------------+
1 row in set (0.32 sec)

上面显示MySQL能在PentiumII 400MHz上以0.32秒执行1,000,000个+表达式。

所有MySQL函数应该被高度优化，但是以可能有一些例外并且benchmark(loop_count,expression)是找出是否你的查询有问题的一个极好工具。

10.5.1 估计查询性能

在大多数情况下，你能通过计算磁盘寻道估计性能。对小的表，你通常能在1次磁盘寻道中找到行(因为这个索引可能被缓冲)。对更大的表，你能估计它(使用 B++ 树索引)，你将需要：log(row_count)/log(index_block_length/3*2/(index_length + data_pointer_length))+1次寻道找到行。

在MySQL中，索引块通常是1024个字节且数据指针通常是4个字节，这对一个有一个索引长度为3(中等整数)的 500,000 行的表给你：log(500,000)/log(1024/3*2/(3+4)) + 1= 4 次寻道。

象上面的索引将要求大约 500,000 * 7 * 3/2 = 5.2M，(假设索引缓冲区被充满到2/3(它是典型的))，你将可能在内存中有索引的大部分并且你将可能仅需要1-2调用从OS读数据来找出行。

然而对于写，你将需要 4 次寻道请求(如上)来找到在哪儿存放新索引并且通常需2次寻道更新这个索引并且写入行。

注意，上述不意味着你的应用程序将缓慢地以 N log N 退化！当表格变得更大时，只要一切被OS或SQL服务器缓冲，事情将仅仅或多或少地更慢。在数据变得太大不能被缓冲后，事情将开始变得更慢直到你的应用程序仅仅受磁盘寻道限制(它以N log N增加)。为了避免这个增加，索引缓冲随数据增加而增加。见10.2.3 调节服务器参数。

10.5.2 SELECT查询的速度

总的来说，当你想要使一个较慢的SELECT ... WHERE更快，检查的第一件事情是你是否能增加一个索引。见10.4 MySQL 索引的使用。在不同表之间的所有引用通常应该用索引完成。你可以使用EXPLAIN来确定哪个索引用于一条SELECT语句。见7.22 EXPLAIN句法(得到关于一条SELECT的信息)。

一些一般的建议：

  • 为了帮助MySQL更好地优化查询，在它已经装载了相关数据后，在一个表上运行myisamchk --analyze。这为每一个更新一个值，指出有相同值地平均行数（当然，对唯一索引，这总是1。）
  • 为了根据一个索引排序一个索引和数据，使用myisamchk --sort-index --sort-records=1（如果你想要在索引1上排序)。如果你有一个唯一索引，你想要根据该索引地次序读取所有的记录，这是使它更快的一个好方法。然而注意，这个排序没有被最佳地编写，并且对一个大表将花很长时间！

10.5.3 MySQL怎样优化WHERE子句

where优化被放在SELECT中，因为他们最主要在那里使用里，但是同样的优化被用于DELETE和UPDATE语句。

也要注意，本节是不完全的。MySQL确实作了许多优化而我们没有时间全部记录他们。

由MySQL实施的一些优化列在下面：

  • 删除不必要的括号：
       ((a AND b) AND c OR (((a AND b) AND (c AND d))))
-> (a AND b AND c) OR (a AND b AND c AND d)
  • 常数调入：
       (a<b AND b=c) AND a=5
-> b>5 AND b=c AND a=5
  • 删除常数条件(因常数调入所需)：
       (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
-> B=5 OR B=6
  • 索引使用的常数表达式仅计算一次。
  • 在一个单个表上的没有一个WHERE的COUNT(*)直接从表中检索信息。当仅使用一个表时，对任何NOT NULL表达式也这样做。
  • 无效常数表达式的早期检测。MySQL快速检测某些SELECT语句是不可能的并且不返回行。
  • 如果你不使用GROUP BY或分组函数(COUNT()、MIN()……)，HAVING与WHERE合并。
  • 为每个子联结(sub join)，构造一个更简单的WHERE以得到一个更快的WHERE计算并且也尽快跳过记录。
  • 所有常数的表在查询中的任何其他表前被首先读出。一个常数的表是：
    • 一个空表或一个有1行的表。
    • 与在一个UNIQUE索引、或一个PRIMARY KEY的WHERE子句一起使用的表，这里所有的索引部分使用一个常数表达式并且索引部分被定义为NOT NULL。

    所有下列的表用作常数表：

    mysql> SELECT * FROM t WHERE primary_key=1;
mysql> SELECT * FROM t1,t2
           WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
  • 对联结表的最好联结组合是通过尝试所有可能性来找到:(。如果所有在ORDER BY和GROUP BY的列来自同一个表，那么当廉洁时，该表首先被选中。
  • 如果有一个ORDER BY子句和一个不同的GROUP BY子句，或如果ORDER BY或GROUP BY包含不是来自联结队列中的第一个表的其他表的列，创建一个临时表。
  • 如果你使用SQL_SMALL_RESULT，MySQL将使用一个在内存中的表。
  • 因为DISTINCT被变换到在所有的列上的一个GROUP BY，DISTINCT与ORDER BY结合也将在许多情况下需要一张临时表。
  • 每个表的索引被查询并且使用跨越少于30% 的行的索引。如果这样的索引没能找到，使用一个快速的表扫描。
  • 在一些情况下，MySQL能从索引中读出行，甚至不咨询数据文件。如果索引使用的所有列是数字的，那么只有索引树被用来解答查询。
  • 在每个记录被输出前，那些不匹配HAVING子句的行被跳过。

下面是一些很快的查询例子：

mysql> SELECT COUNT(*) FROM tbl_name;
mysql> SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
mysql> SELECT MAX(key_part2) FROM tbl_name
           WHERE key_part_1=constant;
mysql> SELECT ... FROM tbl_name
           ORDER BY key_part1,key_part2,... LIMIT 10;
mysql> SELECT ... FROM tbl_name
           ORDER BY key_part1 DESC,key_part2 DESC,... LIMIT 10;

下列查询仅使用索引树就可解决(假设索引列是数字的)：

mysql> SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;
mysql> SELECT COUNT(*) FROM tbl_name
           WHERE key_part1=val1 AND key_part2=val2;
mysql> SELECT key_part2 FROM tbl_name GROUP BY key_part1;

下列查询使用索引以排序顺序检索，不用一次另外的排序：

mysql> SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,...
mysql> SELECT ... FROM tbl_name ORDER BY key_part1 DESC,key_part2 DESC,...

10.5.4 MySQL怎样优化LEFT JOIN

在MySQL 中，A LEFT JOIN B实现如下：

  • 表B被设置为依赖于表A。
  • 表A被设置为依赖于所有用在LEFT JOIN条件的表(除B外)。
  • 所有LEFT JOIN条件被移到WHERE子句中。
  • 进行所有标准的联结优化，除了一个表总是在所有它依赖的表之后被读取。如果有一个循环依赖，MySQL将发出一个错误。
  • 进行所有标准的WHERE优化。
  • 如果在A中有一行匹配WHERE子句，但是在B中没有任何行匹配LEFT JOIN条件，那么在B中生成所有列设置为NULL的一行。
  • 如果你使用LEFT JOIN来找出在某些表中不存在的行并且在WHERE部分你有下列测试：column_name IS NULL，这里column_name 被声明为NOT NULL的列，那么MySQL在它已经找到了匹配LEFT JOIN条件的一行后，将停止在更多的行后寻找(对一特定的键组合)。

10.5.5 MySQL怎样优化LIMIT

在一些情况中，当你使用LIMIT #而不使用HAVING时，MySQL将以不同方式处理查询。

  • 如果你用LIMIT只选择一些行，当MySQL一般比较喜欢做完整的表扫描时，它将在一些情况下使用索引。
  • 如果你使用LIMIT #与ORDER BY，MySQL一旦找到了第一个 # 行，将结束排序而不是排序整个表。
  • 当结合LIMIT #和DISTINCT时，MySQL一旦找到#个唯一的行，它将停止。
  • 在一些情况下，一个GROUP BY能通过顺序读取键(或在键上做排序)来解决，并然后计算摘要直到键值改变。在这种情况下，LIMIT #将不计算任何不必要的GROUP。
  • 只要MySQL已经发送了第一个#行到客户，它将放弃查询。
  • LIMIT 0将总是快速返回一个空集合。这对检查查询并且得到结果列的列类型是有用的。
  • 临时表的大小使用LIMIT #计算需要多少空间来解决查询。

10.5.6 INSERT查询的速度

插入一个记录的时间由下列组成：

  • 连接：(3)
  • 发送查询给服务器：(2)
  • 分析查询：(2)
  • 插入记录：（1 x 记录大小）
  • 插入索引：（1 x 索引）
  • 关闭：(1)

这里的数字有点与总体时间成正比。这不考虑打开表的初始开销(它为每个并发运行的查询做一次)。

表的大小以N log N (B 树)的速度减慢索引的插入。

加快插入的一些方法：

  • 如果你同时从同一客户插入很多行，使用多个值表的INSERT语句。这比使用分开INSERT语句快(在一些情况中几倍)。
  • 如果你从不同客户插入很多行，你能通过使用INSERT DELAYED语句得到更高的速度。见7.14 INSERT句法。
  • 注意，用MyISAM，如果在表中没有删除的行，能在SELECT:s正在运行的同时插入行。
  • 当从一个文本文件装载一个表时，使用LOAD DATA INFILE。这通常比使用很多INSERT语句快20倍。见7.16 LOAD DATA INFILE句法。
  • 当表有很多索引时，有可能多做些工作使得LOAD DATA INFILE更快些。使用下列过程：
    1. 有选择地用CREATE TABLE创建表。例如使用mysql或Perl-DBI。
    2. 执行FLUSH TABLES，或外壳命令mysqladmin flush-tables。
    3. 使用myisamchk --keys-used=0 -rq /path/to/db/tbl_name。这将从表中删除所有索引的使用。
    4. 用LOAD DATA INFILE把数据插入到表中，这将不更新任何索引，因此很快。
    5. 如果你有myisampack并且想要压缩表，在它上面运行myisampack。见10.6.3 压缩表的特征。
    6. 用myisamchk -r -q /path/to/db/tbl_name再创建索引。这将在将它写入磁盘前在内存中创建索引树，并且它更快，因为避免大量磁盘寻道。结果索引树也被完美地平衡。
    7. 执行FLUSH TABLES，或外壳命令mysqladmin flush-tables。

    这个过程将被构造进在MySQL的某个未来版本的LOAD DATA INFILE。

  • 你可以锁定你的表以加速插入。
    mysql> LOCK TABLES a WRITE;
mysql> INSERT INTO a VALUES (1,23),(2,34),(4,33);
mysql> INSERT INTO a VALUES (8,26),(6,29);
mysql> UNLOCK TABLES;

    主要的速度差别是索引缓冲区仅被清洗到磁盘上一次，在所有INSERT语句完成后。一般有与有不同的INSERT语句那样夺的索引缓冲区清洗。如果你能用一个单个语句插入所有的行，锁定就不需要。锁定也将降低多连接测试的整体时间，但是对某些线程最大等待时间将上升(因为他们等待锁)。例如：

    thread 1 does 1000 inserts
thread 2, 3, and 4 does 1 insert
thread 5 does 1000 inserts

    如果你不使用锁定，2、3和4将在1和5前完成。如果你使用锁定，2、3和4将可能不在1或5前完成，但是整体时间应该快大约40%。因为INSERT, UPDATE和DELETE操作在MySQL中是很快的，通过为多于大约5次连续不断地插入或更新一行的东西加锁，你将获得更好的整体性能。如果你做很多一行的插入，你可以做一个LOCK TABLES，偶尔随后做一个UNLOCK TABLES(大约每1000行)以允许另外的线程存取表。这仍然将导致获得好的性能。当然，LOAD DATA INFILE对装载数据仍然是更快的。

为了对LOAD DATA INFILE和INSERT得到一些更快的速度，扩大关键字缓冲区。见10.2.3 调节服务器参数。

10.5.7 UPDATE查询的速度

更改查询被优化为有一个写开销的一个SELECT查询。写速度依赖于被更新数据大小和被更新索引的数量。

使更改更快的另一个方法是推迟更改并且然后一行一行地做很多更改。如果你锁定表，做一行一行地很多更改比一次做一个快。

注意，动态记录格式的更改一个较长总长的记录，可能切开记录。因此如果你经常这样做，时不时地OPTIMIZE TABLE是非常重要的。见7.9 OPTIMIZE TABLE句法。

10.5.8 DELETE查询的速度

删除一个记录的时间精确地与索引数量成正比。为了更快速地删除记录，你可以增加索引缓存的大小。见10.2.3 调节服务器参数。

从一个表删除所有行比删除行的一大部分也要得多。

10.6 选择一种表类型

用MySQL，当前(版本 3.23.5)你能从一个速度观点在4可用表的格式之间选择。

静态MyISAM
这种格式是最简单且最安全的格式，它也是在磁盘格式最快的。速度来自于数据能在磁盘上被找到的难易方式。当所定有一个索引和静态格式的东西时，它很简单，只是行长度乘以行数量。而且在扫描一张表时，用每次磁盘读取来读入常数个记录是很容易的。安全性来自于如果当写入一个静态MyISAM文件时，你的计算机崩溃，myisamchk能很容易指出每行在哪儿开始和结束，因此它通常能回收所有记录，除了部分被写入的那个。注意，在MySQL中，所有索引总能被重建。
动态MyISAM
这种格式有点复杂，因为每一行必须有一个头说明它有多长。当一个记录在更改时变长时，它也可以在多于一个位置上结束。你能使用OPTIMIZE table或myisamchk整理一张表。如果你在同一个表中有象某些VARCHAR或BLOB列那样存取/改变的静态数据，将动态列移入另外一个表以避免碎片可能是一个好主意。
压缩MyISAM
这是一个只读类型，用可选的myisampack工具生成。
内存(HEAP 堆）
这种表格式对小型/中型查找表十分有用。对拷贝/创建一个常用的查找表(用联结)到一个(也许临时)HEAP表有可能加快多个表联结。假定我们想要做下列联结，用同样数据可能要几倍时间。
SELECT tab1.a, tab3.a FROM tab1, tab2, tab3
        WHERE tab1.a = tab2.a and tab2.a = tab3.a and tab2.c != 0;

为了加速它，我们可用tab2和tab3的联结创建一张临时表，因为用相同列( tab1.a )查找。这里是创建该表和结果选择的命令。

CREATE TEMPORARY TABLE test TYPE=HEAP
        SELECT
                tab2.a as a2, tab3.a as a3
        FROM
                tab2, tab3
        WHERE
                tab2.a = tab3.a and c = 0;
SELECT tab1.a, test.a3 from tab1, test where tab1.a = test.a1;
SELECT tab1.b, test.a3 from tab1, test where tab1.a = test.a1 and something;

10.6.1 静态(定长)表的特点

  • 这是缺省格式。它用在表不包含VARCHAR、BLOB或TEXT列时候。
  • 所有的CHAR、NUMERIC和DECIMAL列充填到列宽度。
  • 非常快。
  • 容易缓冲。
  • 容易在崩溃后重建，因为记录位于固定的位置。
  • 不必被重新组织(用myisamchk)，除非一个巨量的记录被删除并且你想要归还空闲磁盘空间给操作系统。
  • 通常比动态表需要更多的磁盘空间。

10.6.2 动态表的特点

  • 如果表包含任何VARCHAR、BLOB或TEXT列，使用该格式。
  • 所有字符串列是动态的(除了那些长度不到4的列)。
  • 每个记录前置一个位图，对字符串列指出哪个列是空的('')，或对数字列哪个是零(这不同于包含NULL值的列)。如果字符串列在删除尾部空白后有零长度，或数字列有零值，它在位图中标记并且不保存到磁盘上。非空字符串存储为一个长度字节加字符串内容。
  • 通常比定长表占更多的磁盘空间。
  • 每个记录仅使用所需的空间。如果一个记录变得更大，它按需要被切开多段，这导致记录碎片。
  • 如果你与超过行长度的信息更新行，行将被分段。在这种情况中，你可能必须时时运行myisamchk -r以使性能更好。使用myisamchk -ei tbl_name做一些统计。
  • 在崩溃后不容易重建，因为一个记录可以是分很多段并且一个连接(碎片)可以丢失。
  • 对动态尺寸记录的期望行长度是：
    3
+ (number of columns + 7) / 8
+ (number of char columns)
+ packed size of numeric columns
+ length of strings
+ (number of NULL columns + 7) / 8

    对每个连接有6个字节的惩罚。无论何时更改引起记录的增大，一个动态记录被链接。每个新链接将至少是20个字节，因此下一增大将可能在同一链连中。如果不是，将有另外一个链接。你可以用myisamchk -ed检查有多少链接。所有的链接可以用 myisamchk -r 删除。

10.6.3 压缩表的特点

  • 一张用myisampack实用程序制作的只读表。所有具有MySQL扩展电子邮件支持的客户可以为其内部使用保留一个myisampack拷贝。
  • 解压缩代码存在于所有MySQL分发，以便甚至没有myisampack的客户能读取用myisampack压缩的表。
  • 占据很小的磁盘空间，使磁盘使用量减到最小。
  • 每个记录被单独压缩(很小的存取开销)。对一个记录的头是定长的(1-3 字节)，取决于表中最大的记录。每列以不同方式被压缩。一些压缩类型是：
    • 通常对每列有一张不同的哈夫曼表。
    • 后缀空白压缩。
    • 前缀空白压缩。
    • 用值0的数字使用1位存储。
    • 如果整数列的值有一个小范围，列使用最小的可能类型来存储。例如，如果所有的值在0到255的范围，一个BIGINT列(8个字节)可以作为一个TINYINT列(1字节)存储。
    • 如果列仅有可能值的一个小集合，列类型被变换到ENUM。
    • 列可以使用上面的压缩方法的组合。
  • 能处理定长或动态长度的记录，然而不能处理BLOB或TEXT列。
  • 能用myisamchk解压缩。

MySQL能支持不同的索引类型，但是一般的类型是ISAM。这是一个B树索引并且你能粗略地为索引文件计算大小为(key_length+4)*0.67，在所有的键上的总和。（这是对最坏情况，当所有键以排序顺序被插入时。）

字符串索引是空白压缩的。如果第一个索引部分是一个字符串，它也将压缩前缀。如果字符串列有很多尾部空白或是一个总不能用到全长的VARCHAR列，空白压缩使索引文件更小。如果很多字符串有相同的前缀，前缀压缩是有帮助的。

10.6.4 内存表的特点

堆桌子仅存在于内存中，因此如果mysqld被关掉或崩溃，它们将丢失，但是因为它们是很快，不管怎样它们是有用的。

MySQL内部的HEAP表使用没有溢出区的100%动态哈希并且没有与删除有关的问题。

你只能通过使用在堆表中的一个索引的用等式存取东西(通常用=操作符)。

堆表的缺点是：

  1. 你要为你想要同时使用的所有堆表需要足够的额外内存。
  2. 你不能在索引的一个部分上搜索。
  3. 你不能顺序搜索下一个条目(即使用这个索引做一个ORDER BY)。
  4. MySQL也不能算出在2个值之间大概有多少行。这被优化器使用来决定使用哪个索引，但是在另一方面甚至不需要磁盘寻道。

10.7 其他优化技巧

对加快系统的未分类的建议是：

  • 使用持久的连接数据库以避免连接开销。
  • 总是检查你的所有询问确实使用你已在表中创建了的索引。在MySQL中，你可以用EXPLAIN命令做到。见7.22 EXPLAIN句法(得到关于SELECT的信息)。
  • 尝试避免在被更改了很多的表上的复杂的SELECT查询。这避免与锁定表有关的问题。
  • 在一些情况下，使得基于来自其他表的列的信息引入一个“ 哈希”的列有意义。如果该列较短并且有合理的唯一值，它可以比在许多列上的一个大索引快些。在MySQL中，很容易使用这个额外列：SELECT * from table where hash='calculated hash on col1 and col2' and col_1='constant' and col_2='constant' and .. 。
  • 对于有很多更改的表，你应该试着避免所有VARCHAR或BLOB列。只要你使用单个VARCHAR或BLOB列，你将得到动态行长度。见9.4 MySQL表类型。
  • 只是因为行太大，分割一张表为不同的表一般没有什么用处。为了存取行，最大的性能命冲击是磁盘寻道以找到行的第一个字节。在找到数据后，大多数新型磁盘对大多数应用程序来说足够快，能读入整个行。它确实有必要分割的唯一情形是如果其动态行尺寸的表(见上述)能变为固定的行大小，或如果你很频繁地需要扫描表格而不需要大多数列。见9.4 MySQL表类型。
  • 如果你很经常地需要基于来自很多行的信息计算(如计数)，引入一个新表并实时更新计数器可能更好一些。类型的更改UPDATE table set count=count+1 where index_column=constant是很快的！当你使用象MySQL那样的只有表级锁定(多重读/单个写)的数据库时，这确实重要。这也将给出大多数数据库较好的性能，因为锁定管理器在这种情况下有较少的事情要做。 11111111111111111111111
  • 如果你需要从大的记录文件表中收集统计信息，使用总结性的表而不是扫描整个表。维护总结应该比尝试做“实时”统计要快些。当有变化而不是必须改变运行的应用时，从记录文件重新生成新的总结表(取决于业务决策)要快多了！
  • 如果可能，应该将报告分类为“实时”或“统计”，这里统计报告所需的数据仅仅基于从实际数据产生的总结表中产生。
  • 充分利用列有缺省值的事实。当被插入值不同于缺省值时，只是明确地插入值。这减少MySQL需要做的语法分析并且改进插入速度。
  • 在一些情况下，包装并存储数据到一个BLOB中是很方便的。在这种情况下，你必须在你的应用中增加额外的代码来打包/解包BLOB中的东西，但是这种方法可以在某些阶段节省很多存取。当你有不符合静态的表结构的数据时，这很实用。
  • 在一般情况下，你应该尝试以第三范式保存数据，但是如果你需要这些以获得更快的速度，你应该不用担心重复或创建总结表。
  • 存储过程或UDF(用户定义函数)可能是获得更好性能的一个好方法，然而如果你使用某些不支持它的数据库，在这种情况中，你应该总是有零一个方法(较慢的)做这些。
  • 你总是能通过在你的应用程序中缓冲查询/答案并尝试同时做很多插入/更新来获得一些好处。如果你的数据库支持锁定表(象MySQL和Oracle)，这应该有助于确保索引缓冲在所有更新后只清空一次。
  • 但你不知道何时写入你的数据时，使用INSERT /*! DELAYED */。这加快处理，因为很多记录可以用一次磁盘写入被写入。
  • 当你想要让你的选择显得更重要时，使用INSERT /*! LOW_PRIORITY */。
  • 使用SELECT /*! HIGH_PRIORITY */来取得塞入队列的选择，它是即使有人等待做一个写入也要完成的选择。
  • 使用多行INSERT语句来存储很多有一条SQL命令的行(许多SQL服务器支持它）。
  • 使用LOAD DATA INFILE装载较大数量的数据。这比一般的插入快并且当myisamchk集成在mysqld中时，甚至将更快。
  • 使用AUTO_INCREMENT列构成唯一值。
  • 当使用动态表格式时，偶尔使用OPTIMIZE TABLE以避免碎片。见7.9O PTIMIZE TABLE句法。
  • 可能时使用HEAP表以得到更快的速度。见9.4 MySQL表类型。
  • 当使用一个正常Web服务器设置时，图象应该作为文件存储。这仅在数据库中存储的一本文件的引用。这样做的主要原因是是一个正常的Web服务器在缓冲文件比数据库内容要好得多，因此如果你正在使用文件，较容易得到一个较快的系统。
  • 对经常存取的不重要数据(象有关对没有cookie用户最后显示标语的信息）使用内存表。
  • 在不同表中具有相同信息的列应该被声明为相同的并有相同的名字。在版本 3.23 前，你只能靠较慢的联结。尝试使名字简单化(在客户表中使用name而不是customer_name)。为了使你的名字能移植到其他SQL服务器，你应该使他们短于18 个字符。
  • 如果你需要确实很高的速度，你应该研究一下不同SQL服务器支持的数据存储的底层接口！例如直接存取MySQL MyISAM，比起使用SQL 接口，你能得到2-5倍的速度提升。然而为了能做到它，数据必须是在与应用程序性在同一台机器的服务器上，并且通常它只应该被一个进程存取(因为外部文件锁定确实很慢)。通过在MySQL服务器中引进底层MyISAM命令能消除以上问题(如果需要，这可能是获得更好性能的一个容易的方法)。借助精心设计的数据库接口，应该相当容易支持这类优化。
  • 在许多情况下，从一个数据库存取数据(使用一个实时连接)比存取一个文本文件快些，只是因为数据库比文本文件更紧凑(如果你使用数字数据)并且这将涉及更少的磁盘存取。你也节省代码，因为你不须分析你的文本文件来找出行和列的边界。
  • 你也能使用复制加速。见19.1 数据库复制。

10.8 使用你自己的基准测试

你决定应该测试你的应用程序和数据库，以发现瓶颈在哪儿。通过修正它(或通过用一个“哑模块”代替瓶颈)，你能容易确定下一个瓶颈(等等)。即使对你的应用程序来说，整体性能“足够好”，你至少应该对每个瓶颈做一个“计划”，如果某人“确实需要修正它”，如何解决它。

对于一些可移植的基准程序的例子，参见MySQL基准套件。见11 MySQL 基准套件。你能利用这个套件的任何程序并且为你的需要修改它。通过这样做，你能尝试不同的你的问题的解决方案并测试哪一个对你是最快的解决方案。

在系统负载繁重时发生一些问题是很普遍的，并且我们有很多与我们联系的客户，他们在生产系统中有一个(测试)系统并且有负载问题。到目前为止，被一种这些的情况是与基本设计有关的问题(表扫描在高负载时表现不好)或OS/库问题。如果系统已经不在生产系统中，它们大多数将很容易修正。

为了避免这样的问题，你应该把一些力气放在在可能最坏的负载下测试你的整个应用！

10.9 设计选择

MySQL在分开的文件中存储行数据和索引数据。许多(几乎全部)其他数据库在同一个文件中混合行和索引数据。我们相信，MySQL的选择对非常广泛的现代系统的来说是较好的。

存储行数据的另一个方法是在一个分开的区域保存每列信息(例子是SDBM和Focus)。这将对每个存取多于一列的查询获得一个性能突破。因为在多于一列被存取时，这快速退化，我们相信这个模型对通用功能的数据库不是最好。

更常见的情形是索引和数据一起被存储(就象Oracle/Sybase)。在这种情况中，你将在索引的叶子页面上找到行信息。有这布局的好处是它在许多情况下(取决于这个索引被缓冲得怎样)节省一次磁盘读。有这布局的坏处是：

  • 表扫描更慢，因为你必须读完索引以获得数据。
  • 你损失很多空间，因为你必须重复来自节点的索引(因为你不能在节点上存储行）
  • 删除将随时间变化恶化数据库表(因为节点中的索引在删除后通常不被更新)。
  • 你不能仅使用索引表为一个查询检索数据。
  • 索引数据很难缓冲。

10.10 MySQL设计局限/折衷

因为MySQL使用极快的表锁定(多次读/一次写)，留下的最大问题是在同一个表中的一个插入的稳定数据流与慢速选择的一个混合。

我们相信，在其他情况下，对大多数系统，异常快速的性能使它成为一个赢家。这种情形通常也可能通过表的多个副本来解决，但是它要花更多的力气和硬件。

对一些常见的应用环境，我们也在开发一些扩展功能以解决此问题。

10.11 可移植性

因为所有SQL服务器实现了SQL的不同部分，要花功夫编写可移植的SQL应用程序。对很简单的选择/插入，它是很容易的，但是你需要越多，它越困难，而且如果你想要应用程序对很多数据库都快，它变得更难！

为了使一个复杂应用程序可移植，你需要选择它应该与之工作的很多SQL服务器。

当你能使用MySQL的crash-me 程序（http://www.mysql.com/crash-me-choose.htmy）来找出你能与之使用的数据库服务器的选择的函数、类型和限制。crash-me现在对任何可能的事情测试了很长时间，但是它仍然理解测试过的大约450件事情。

例如，如果你想要能使用Informix 或 DB2，你不应该有比18个字符更长的列名。

MySQL基准程序和crash-me是独立于数据库的。通过观察我们怎么处理它，你能得到一个感觉，你必须为编写你的独立于数据库的应用程序做什么。基准本身可在MySQL源代码分发的“sql-bench”目录下找到。他们用DBI数据库接口以Perl写成(它解决问题的存取部分)。

到http://www.mysql.com/benchmark.html看这个基准的结果。

正如你可在这些结果看见的那样，所有数据库都有一些弱点。这就是他们不同的设计折衷导致的不同行为。

如果你为数据库的独立性而努力，你需要获得每个SQL服务器瓶颈的良好感受。MySQL在检索和更新方面很快，但是在同一个表上混合读者/写者方面将有一个问题。在另一方面，当你试图存取你最近更新了的行时，Oracle有一个很大问题(直到他们被清空到磁盘上)。事务数据库总的来说在从记录文件表中生成总结表不是很好，因为在这种情况下，行级锁定几乎没用处。

为了使你的应用程序“确实独立于数据库”，你需要定义一个容易的可扩展的接口，用它你可操纵你的数据。因为C++在大多数系统上可以得到的，使用数据库的一个C++ 类接口是有意义的。

如果你使用一些某个数据库特定的功能(在MySQL中，象REPLACE命令)，你应该为SQL服务器编码一个方法以实现同样的功能 (但是慢些)。用MySQL，你能使用/*! */语法把MySQL特定的关键词加到查询中。在/**/中的代码将被大多数其他SQL服务器视为一篇注释(被忽略)。

如果高性能真的比准确性更重要，就像在一些web应用程序那样。一种可能性是创建一个应用层，缓冲所有的结果以给你更高的性能。通过只是让老的结果在短时间后‘过期’，你能保持缓存合理地刷新。这在极高负载的情况下是相当不错的，在此情况下，你能动态地增加缓存到更大并且设定较高的过期时限直到一切回到正常。

在这种情况下，创建信息的表应该包含缓存初始大小和表一般应该被刷新几次的信息。

10.12 我们已将MySQL用在何处？

在MySQL起初开发期间，MySQL的功能适合我们的最大客户。他们为在瑞典的一些最大的零售商处理数据仓库。

我们从所有商店得到所有红利卡交易的每周总结并且我们被期望为所有店主提供有用的信息以帮助他们得出他们的广告战如何影响他们的顾客。

数据是相当巨量的(大约每月7百万宗交易总结)并且我们保存4-10年来的数据需要呈现给用户。我们每周顾客那里得到请求，他们想要“立刻”访问来自该数据的新报告。

我们通过每月将所有信息存储在压缩的“交易”表中来解决它。我们有一套简单的宏/脚本用来生成来自交易表的不同条件( 产品组，顾客id，商店...)的总结表。报告是由一个进行语法分析网页的小perl脚本动态生成的网页，在脚本中执行SQL语句并且插入结果。现在我们很想使用PHP或mod_perl，但是那时他们没有。

对图形数据，我们用C语言编写了一个简单的工具，它能基于SQL查询的结果(对结果的一些处理)产生赠品，这也从分析HTML文件的perl脚本中动态地执行。

在大多数情况下，一个新的报告通过简单地复制一个现有脚本并且修改其中的SQL查询来完成。在一些情况下，我们将需要把更多的字段加到一个现有的总结表中或产生一个新的，但是这也相当简单，因为我们在磁盘上保存所有交易表。（目前我们有至少50G的交易表和200G的其他顾客数据)。

我们也让我们的顾客直接用ODBC存取总结表以便高级用户能自己试验数据。

我们用非常中档的Sun Ultra sparcstation ( 2x200 Mz )来处理，没有任何问题。最近我们升级了服务器之一到一台2个CPU 400 Mz的Ultra sparc，并且我们现在计划处理产品级的交易，这将意味着数据增加10番。我们认为我们能通过只是为我们的系统增加更多的磁盘就能赶上它。

我们也在试验Intel-Linux以便能更便宜地得到更多的cpu动力。既然我们有二进制可移植的数据库格式(在3.32中引入)，我们将开始在应用程序的某些部分使用它。

我们最初的感觉是Linux在低到中等负载时执行的较好，但是你开始得到导致的高负载时，Solaris将表现更好，因为磁盘IO的极限，但是我们还没有关于这方面的任何结论。在与一些Linux核心开发者的讨论以后，这可能是 Linux 的副作用，它给批处理以太多的资源使得交互的性能变得很低。当大的批处理正在进行时，这使机器感觉很慢且无反应。希望这将在未来的Linux内核中解决。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册- 11 MySQL基准套件

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

11 MySQL 基准套件

本章应该包含MySQL基准套件的技术描述(和crash-me)，但是该描述还没被写成。目前，你应该研究在分发中的“sql-bench”目录下代码和结果(当然在网页http://www.mysql.com/crash-me-choose.htmy并且(通常发现了在MySQL分发的“sql-bench”目录下找到))。

基准将告诉任何用户一个给定的SQL实现在哪方面表现得很好或很糟糕。

注意，这个基准是单线程的，因此它测量操作的最小时间。

例如(在同一台NT 4.0机器上运行)：

通过索引读取 2000000行（2百万） | 秒数 | 秒数
mysql | 367 | 249
mysql_odbc | 464
db2_odbc | 1206
informix_odbc | 121126
ms-sql_odbc | 1634
oracle_odbc | 20800
solid_odbc | 877
sybase_odbc | 17614
插入(350768)行 | 秒数 | 秒数
mysql | 381 | 206
mysql_odbc | 619
db2_odbc | 3460
informix_odbc | 2692
ms-sql_odbc | 4012
oracle_odbc | 11291
solid_odbc | 1801
sybase_odbc | 4802

在上面的测试中MySQL用一个8M索引缓存运行。

注意，没有包含Oracle，因为他们要求删去。所有的 Oracle基准测试不得不被Oracle拿走！我们相信使Oracle基准测试很有偏见，因为上面的基准测试被假定来显示可以能为一个单个客户做一个标准安装。

crash-me试图确定一个数据库支持什么特征并且实际运行的查询有什么能力和限制。例如，它确定：

  • 支持的什么列类型
  • 支持多少索引
  • 支持什么功能
  • 一个查询能有多大
  • 一个VARCHAR列能有多大

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-12 MySQL实用程序

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

12 MySQL实用程序

12.1 各种MySQL程序概述

所有使用mysqlclient客户库与服务器通信的MySQL客户使用下列环境变量：

名字 | 说明
MYSQL_UNIX_PORT | 缺省套接字；用于连接localhost
MYSQL_TCP_PORT | 缺省 TCP/IP 端口
MYSQL_PWD | 缺省口令
MYSQL_DEBUG | 调试时调试-踪迹选项
TMPDIR | 临时表/文件被创建的目录

使用MYSQL_PWD是不安全的。见6.3 与MySQL服务器连接。

“mysql”客户使用MYSQL_HISTFILE环境变量中命名的文件来保存命令行历史，历史文件的缺省值是“$HOME/.mysql_history”，这里$HOME是HOME环境变量的值。

所有MySQL程序取许多不同的选项，然而，每个MySQL程序提供一个--help选项，你可以使用它得到程序不同选项的完整描述。例如，试一试mysql --help。

你能用一个选项文件覆盖所有的标准客户程序的缺省选项。见4.15.4 选择文件。

下表简单地描述MySQL程序：

myisamchk
描述、检查、优化和修复MySQL表的使用程序。因为myisamchk有许多功能，它在其自己的章节中描述。见13 维护MySQL安装。
make_binary_release
制作一个编译MySQL的一个二进制的版本。这能用FTP传送到在ftp.tcx.se 网站的“/pub/mysql/Incoming”以方便其它MySQL用户。
msql2mysql
一个外壳脚本，转换mSQL程序到MySQL。它不能处理所有的情况，但是当转换时，它给出一个好起点。
mysql
mysql是一个简单的SQL外壳(具有GNU readline 能力)，它支持交互式和非交互式使用。当交互地使用时，查询结果以ASCII表的格式被表示。当非交互地使用时(例如，作为一个过滤器)，结果是以定位符分隔的格式表示。（输出格式可以使用命令行选项改变)你可以简单地象这样运行脚本：
shell> mysql database < script.sql > output.tab

如果你在客户中由于内存不足造成问题，使用--quick选项！这迫使mysql使用mysql_use_result()而非mysql_store_result()来检索结果集合。

mysqlaccess
一个脚本，检查对主机、用户和数据库组合的存取权限。
mysqladmin
执行管理操作的实用程序，例如创建或抛弃数据库，再装载授权表，清洗表到磁盘中和再打开日志文件。mysqladmin也可以被用来从服务器检索版本，进程和状态信息。见12.2 管理一个 MySQL 服务器。
mysqlbug
MySQL错误报告脚本。当填写一份错误报告到MySQL邮件列表时，应该总是使用该脚本。
mysqld
SQL守护进程。它应该一直在运行。
mysqldump
以SQL语句或定位符分隔的文本文件将一个MySQL数据库倾倒一个文件中。这是最早由Igor Romanenko编写的自由软件的增强版本。见12.3 从MySQL数据库和表倾倒结构和数据。
mysqlimport
使用LOAD DATA INFILE将文本文件倒入其各自的表中。见12.4 从文本文件导入数据。
mysqlshow
显示数据库，表，列和索引的信息。
mysql_install_db
以缺省权限创建MySQL授权表。这通常仅被执行一次。就是在系统上第一次安装MySQL时。
replace
一个实用程序，由msql2mysql使用，但是有更一般的适用性。replace改变文件中或标准输入上的字符串。使用一台有限状态机首先匹配更长的字符串，能被用来交换字符串。例如，这个命令在给定的文件中交换a和b：
shell> replace a b b a -- file1 file2 ...
safe_mysqld
一个脚本，用某些更安全的特征启动mysqld守护进程，例如当一个错误发生时，重启服务器并且记载运行时刻信息到一个日志文件中。

12.2 管理一个MySQL服务器

用于执行管理性操作。语法是：

shell> mysqladmin [OPTIONS] command [command-option] command ...

通过执行mysqladmin --help，你可以得到你mysqladmin的版本所支持的一个选项列表。

目前mysqladmin支持下列命令：

create databasename | 创建一个新数据库
drop databasename | 删除一个数据库及其所有表
extended-status | 给出服务器的一个扩展状态消息
flush-hosts | 洗掉所有缓存的主机
flush-logs | 洗掉所有日志
flush-tables | 洗掉所有表
flush-privileges | 再次装载授权表(同reload)
kill id,id,... | 杀死mysql线程
password | 新口令，将老口令改为新口令
ping | 检查mysqld是否活着
processlist | 显示服务其中活跃线程列表
reload | 重载授权表
refresh | 洗掉所有表并关闭和打开日志文件
shutdown | 关掉服务器
status | 给出服务器的简短状态消息
variables | 打印出可用变量
version | 得到服务器的版本信息

所有命令可以被缩短为其唯一的前缀。例如：

shell> mysqladmin proc stat
+----+-------+-----------+----+-------------+------+-------+------+
| Id | User  | Host      | db | Command     | Time | State | Info |
+----+-------+-----------+----+-------------+------+-------+------+
| 6  | monty | localhost |    | Processlist | 0    |       |      |
+----+-------+-----------+----+-------------+------+-------+------+
Uptime: 10077  Threads: 1  Questions: 9  Slow queries: 0  Opens: 6  Flush tables: 1
Open tables: 2  Memory in use: 1092K  Max memory used: 1116K

mysqladmin status命令结果有下述列：

Uptime | MySQL服务器已经运行的秒数
Threads | 活跃线程（客户）的数量
Questions | 从mysqld启动起来自客户问题的数量
Slow queries | 已经超过long_query_time秒的查询数量
Opens | mysqld已经打开了多少表
Flush tables | flush ..., refresh和reload命令数量
Open tables | 现在被打开的表数量
Memory in use | 由mysqld代码直接分配的内存(只有在MySQL用--with-debug编译时可用)
Max memory used | 由mysqld代码直接分配的最大内存(只有在MySQL用--with-debug编译时可用)

12.3 从MySQL数据库和表中倒出结构和数据

实用程序，为备份或为把数据转移到另外的SQL服务器上倾倒一个数据库或许多数据库。倾倒将包含 创建表或充实表的SQL语句。

shell> mysqldump [OPTIONS] database [tables]

如果你不给定任何表，整个数据库将被倾倒。

通过执行mysqldump --help，你能得到你mysqldump的版本支持的选项表。

注意，如果你运行mysqldump没有--quick或--opt选项，mysqldump将在倾倒结果前装载整个结果集到内存中，如果你正在倾倒一个大的数据库，这将可能是一个问题。

mysqldump支持下列选项：

--add-locks
在每个表倾倒之前增加LOCK TABLES并且之后UNLOCK TABLE。(为了使得更快地插入到MySQL)。
--add-drop-table
在每个create语句之前增加一个drop table。
--allow-keywords
允许创建是关键词的列名字。这由表名前缀于每个列名做到。
-c, --complete-insert
使用完整的insert语句(用列名字)。
-C, --compress
如果客户和服务器均支持压缩，压缩两者间所有的信息。
--delayed
用INSERT DELAYED命令插入行。
-e, --extended-insert
使用全新多行INSERT语法。（给出更紧缩并且更快的插入语句）
-#, --debug[=option_string]
跟踪程序的使用(为了调试)。
--help
显示一条帮助消息并且退出。
--fields-terminated-by=...

--fields-enclosed-by=...

--fields-optionally-enclosed-by=...

--fields-escaped-by=...

--fields-terminated-by=...
这些选择与-T选择一起使用，并且有相应的LOAD DATA INFILE子句相同的含义。见7.16 LOAD DATA INFILE语法。
-F, --flush-logs
在开始倾倒前，洗掉在MySQL服务器中的日志文件。
-f, --force,
即使我们在一个表倾倒期间得到一个SQL错误，继续。
-h, --host=..
从命名的主机上的MySQL服务器倾倒数据。缺省主机是localhost。
-l, --lock-tables.
为开始倾倒锁定所有表。
-t, --no-create-info
不写入表创建信息(CREATE TABLE语句）
-d, --no-data
不写入表的任何行信息。如果你只想得到一个表的结构的倾倒，这是很有用的！
--opt
同--quick --add-drop-table --add-locks --extended-insert --lock-tables。应该给你为读入一个MySQL服务器的尽可能最快的倾倒。
-pyour_pass, --password[=your_pass]
与服务器连接时使用的口令。如果你不指定“=your_pass”部分，mysqldump需要来自终端的口令。
-P port_num, --port=port_num
与一台主机连接时使用的TCP/IP端口号。（这用于连接到localhost以外的主机，因为它使用 Unix套接字。）
-q, --quick
不缓冲查询，直接倾倒至stdout；使用mysql_use_result()做它。
-S /path/to/socket, --socket=/path/to/socket
与localhost连接时（它是缺省主机)使用的套接字文件。
-T, --tab=path-to-some-directory
对于每个给定的表，创建一个table_name.sql文件，它包含SQL CREATE 命令，和一个table_name.txt文件，它包含数据。 注意：这只有在mysqldump运行在mysqld守护进程运行的同一台机器上的时候才工作。.txt文件的格式根据--fields-xxx和--lines--xxx选项来定。
-u user_name, --user=user_name
与服务器连接时，MySQL使用的用户名。缺省值是你的Unix登录名。
-O var=option, --set-variable var=option
设置一个变量的值。可能的变量被列在下面。
-v, --verbose
冗长模式。打印出程序所做的更多的信息。
-V, --version
打印版本信息并且退出。
-w, --where='where-condition'
只倾倒被选择了的记录；注意引号是强制的！
"--where=user='jimf'" "-wuserid>1" "-wuserid<1"

最常见的mysqldump使用可能制作整个数据库的一个备份：

mysqldump --opt database > backup-file.sql

但是它对用来自于一个数据库的信息充实另外一个MySQL数据库也是有用的：

mysqldump --opt database | mysql --host=remote-host -C database

12.4 从文本文件导入数据

mysqlimport提供一个到LOAD DATA INFILESQL语句的命令行接口。mysqlimport的大多数选项直接对应于LOAD DATA INFILE的相同选项。见7.16 LOAD DATA INFILE语法。

mysqlimport象这样调用：

shell> mysqlimport [options] filename ...

对于在命令行上命名的每个文本文件，mysqlimport剥去文件名的扩展名并且使用它决定哪个表导入文件的内容。例如，名为“patient.txt”、“patient.text”和“patient”将全部被导入名为patient的一个表中。

mysqlimport支持下列选项：

-C, --compress
如果客户和服务器均支持压缩，压缩两者之间的所有信息。
-#, --debug[=option_string]
跟踪程序的使用(为调试)。
-d, --delete
在导入文本文件前倒空表格。
--fields-terminated-by=...

--fields-enclosed-by=...

--fields-optionally-enclosed-by=...

--fields-escaped-by=...

--fields-terminated-by=...
这些选项与对应于LOAD DATA INFILE的子句相同的含义。见7.16 LOAD DATA INFILE语法。
-f, --force
忽略错误。例如，如果对于一个文本文件的一个表不存在，继续处理任何余下的文件。没有--force，如果表不存在，mysqlimport退出。
--help
显示一条帮助消息并且退出。
-h host_name, --host=host_name
导入数据到命名的主机上的MySQL服务器。缺省主机是localhost。
-i, --ignore
见为--replace选项的描述。
-l, --lock-tables
在处理任何文本文件前为写入所定所有的表。这保证所有的表在服务器上被同步。
-L, --local
从客户读取输入文件。缺省地，如果你连接localhost(它是缺省主机)，文本文件被假定在服务器上。
-pyour_pass, --password[=your_pass]
与服务器连接时使用的口令。如果你不指定“=your_pass”部分，mysqlimport要求来自终端的口令。
-P port_num, --port=port_num
与一台主机连接时使用的TCP/IP端口号。（这被用于连接到除localhost以外的主机，因为它使用Unix套接字。）
-r, --replace
--replace和--ignore选项控制对输入在唯一键值上有重复的现有记录的输入处理。如果你指定--replace，新行将代替有相同唯一键的存在的行。如果你指定--ignore，跳过输入在唯一键值上有重复的现有记录。如果你不指定任何一个选项，当找到一个重复的键值，出现一个错误，并且文本文件余下部分被忽略。
-s, --silent
安静模式。只有在错误发生时，写出输出。
-S /path/to/socket, --socket=/path/to/socket
与localhost(它是缺省主机)连接时使用的套接字文件。
-u user_name, --user=user_name
MySQL使用的用户名字当与服务者联接时。缺省价值是你的 Unix 登录名字。
-v, --verbose
冗长模式。打印程序所做的更多信息。
-V, --version
打印版本信息并且退出。

以下是使用mysqlimport运行的一个样本：

$ mysql --version
mysql  Ver 9.33 Distrib 3.22.25, for pc-linux-gnu (i686)
$ uname -a
Linux xxx.com 2.2.5-15 #1 Mon Apr 19 22:21:09 EDT 1999 i586 unknown
$ mysql -e 'CREATE TABLE imptest(id INT, n VARCHAR(30))' test
$ ed
a
100     Max Sydow
101     Count Dracula
.
w imptest.txt
32
q
$ od -c imptest.txt
0000000   1   0   0  \t   M   a   x       S   y   d   o   w  \n   1   0
0000020   1  \t   C   o   u   n   t       D   r   a   c   u   l   a  \n
0000040
$ mysqlimport --local test imptest.txt
test.imptest: Records: 2  Deleted: 0  Skipped: 0  Warnings: 0
$ mysql -e 'SELECT * FROM imptest' test
+------+---------------+
| id   | n             |
+------+---------------+
|  100 | Max Sydow     |
|  101 | Count Dracula |
+------+---------------+

12.5 MySQL压缩只读表生成器

myisampack被用来压缩MyISAM表，而pack_isam被用来压缩ISAM表。由于ISAM表被淘汰，这里我们将只讨论myisampack。

myisampack是当你订购超过10个许可证或扩展的支持时，你得到的一个额外的实用程序。因为这些仅以二进制形式被分发，他们仅在某些平台上可用。

下面我们仅谈论myisampack, 但是每件事情对pack_isam也是持有的。

myisampack通过单独压缩表中的每个列来工作。当表被打开时，需要加压缩的信息被读进内存，这使得在存取单个记录时能得到更好的性能，因为你只需要解压缩一个记录，不是更大的磁盘块，象在 MSDOS上使用Stacker时一样。通常，myisampack压缩数据文件40%-70%。

MySQL使用内存映射(mmap())在压缩表上而如果mmap()的使用不工作，倒回到正常的读/写文件。

当前myisampack有2个限制：

  • 在压缩后，表只能读。
  • myisampack也能压缩BLOB或TEXT列。较老的pack_isam不能做到。

修正这些限制以在我们的TODO表上，但是具有低优先级。

myisampack象这样调用：

shell> myisampack [options] filename ...

每个文件名应该是一个索引(“.MYI”) 文件名。如果你不在数据库目录下，你应该指定文件的路径名。允许省略“.MYI”扩展名。

myisampack支持下列选项：

-b, --backup
制作表的一个备份，为tbl_name.OLD。
-#, --debug=debug_options
输出调试日志。debug_options串经常是'd:t:o,filename'。
-f, --force
即使它变得更大或如果临时文件存在，强制表的压缩。(myisampack在压缩表时创建一个名位“tbl_name.TMD”的临时文件。如果你杀死myisampack，“.TMD”文件不能被删除。通常，如果myisampack发现“tbl_name.TMD”存在，它以一个错误退出。用--force，myisampack不管怎样都压缩表。
-?, --help
显示一条帮助消息并且退出。
-j big_tbl_name, --join=big_tbl_name
联结所有在命令行上被命名的表到一个单独的表big_tbl_name中。所有要被合并的表必须是相同的(同样的列名字和类型，同样的索引，等等。）
-p #, --packlength=#
指定记录长度存储尺寸，按字节。值应该是1、2或3。(myisampack用1、2或3字节的长度指针存储所有行。在最一般的情况下，myisampack在它开始包装文件以前，能确定正确的长度值，但是它可能注意到在包装过程期间，它能使用了更短的长度。在这种情况下，myisampack在下一次你包装同样文件时间打印出一条提示，你可以使用更短的记录长度。）
-s, --silent
安静模式。只有当错误发生时，写出输出。
-t, --test
不压缩表，仅仅测试压缩它。
-T dir_name, --tmp_dir=dir_name
使用命名的目录作为写入临时表的位置。
-v, --verbose
冗长模式。写出有关进展和包装结果的信息。
-V, --version
显示版本信息和出口。
-w, --wait
如果表正在使用，等待并且再试。如果mysqld服务器以--skip-locking选项被调用，如果表可能在包装过程中被更新，调用myisampack不是一个好主意。

下面显示的命令顺序说明了一个典型的表压缩桌子压缩过程：

shell> ls -l station.*
-rw-rw-r--   1 monty    my         994128 Apr 17 19:00 station.MYD
-rw-rw-r--   1 monty    my          53248 Apr 17 19:00 station.MYI
-rw-rw-r--   1 monty    my           5767 Apr 17 19:00 station.frm

shell> myisamchk -dvv station

MyISAM file:     station
Isam-version:  2
Creation time: 1996-03-13 10:08:58
Recover time:  1997-02-02  3:06:43
Data records:              1192  Deleted blocks:              0
Datafile: Parts:           1192  Deleted data:                0
Datafile pointer (bytes):     2  Keyfile pointer (bytes):     2
Max datafile length:   54657023  Max keyfile length:   33554431
Recordlength:               834
Record format: Fixed length

table description:
Key Start Len Index   Type                       Root  Blocksize    Rec/key
1   2     4   unique  unsigned long              1024       1024          1
2   32    30  multip. text                      10240       1024          1

Field Start Length Type
1     1     1
2     2     4
3     6     4
4     10    1
5     11    20
6     31    1
7     32    30
8     62    35
9     97    35
10    132   35
11    167   4
12    171   16
13    187   35
14    222   4
15    226   16
16    242   20
17    262   20
18    282   20
19    302   30
20    332   4
21    336   4
22    340   1
23    341   8
24    349   8
25    357   8
26    365   2
27    367   2
28    369   4
29    373   4
30    377   1
31    378   2
32    380   8
33    388   4
34    392   4
35    396   4
36    400   4
37    404   1
38    405   4
39    409   4
40    413   4
41    417   4
42    421   4
43    425   4
44    429   20
45    449   30
46    479   1
47    480   1
48    481   79
49    560   79
50    639   79
51    718   79
52    797   8
53    805   1
54    806   1
55    807   20
56    827   4
57    831   4

shell> myisampack station.MYI
Compressing station.MYI: (1192 records)
- Calculating statistics

normal:     20  empty-space:      16  empty-zero:        12  empty-fill:  11
pre-space:   0  end-space:        12  table-lookups:      5  zero:         7
Original trees:  57  After join: 17
- Compressing file
87.14%

shell> ls -l station.*
-rw-rw-r--   1 monty    my         127874 Apr 17 19:00 station.MYD
-rw-rw-r--   1 monty    my          55296 Apr 17 19:04 station.MYI
-rw-rw-r--   1 monty    my           5767 Apr 17 19:00 station.frm

shell> myisamchk -dvv station

MyISAM file:     station
Isam-version:  2
Creation time: 1996-03-13 10:08:58
Recover time:  1997-04-17 19:04:26
Data records:              1192  Deleted blocks:              0
Datafile: Parts:           1192  Deleted data:                0
Datafilepointer (bytes):      3  Keyfile pointer (bytes):     1
Max datafile length:   16777215  Max keyfile length:     131071
Recordlength:               834
Record format: Compressed

table description:
Key Start Len Index   Type                       Root  Blocksize    Rec/key
1   2     4   unique  unsigned long             10240       1024          1
2   32    30  multip. text                      54272       1024          1

Field Start Length Type                         Huff tree  Bits
1     1     1      constant                             1     0
2     2     4      zerofill(1)                          2     9
3     6     4      no zeros, zerofill(1)                2     9
4     10    1                                           3     9
5     11    20     table-lookup                         4     0
6     31    1                                           3     9
7     32    30     no endspace, not_always              5     9
8     62    35     no endspace, not_always, no empty    6     9
9     97    35     no empty                             7     9
10    132   35     no endspace, not_always, no empty    6     9
11    167   4      zerofill(1)                          2     9
12    171   16     no endspace, not_always, no empty    5     9
13    187   35     no endspace, not_always, no empty    6     9
14    222   4      zerofill(1)                          2     9
15    226   16     no endspace, not_always, no empty    5     9
16    242   20     no endspace, not_always              8     9
17    262   20     no endspace, no empty                8     9
18    282   20     no endspace, no empty                5     9
19    302   30     no endspace, no empty                6     9
20    332   4      always zero                          2     9
21    336   4      always zero                          2     9
22    340   1                                           3     9
23    341   8      table-lookup                         9     0
24    349   8      table-lookup                        10     0
25    357   8      always zero                          2     9
26    365   2                                           2     9
27    367   2      no zeros, zerofill(1)                2     9
28    369   4      no zeros, zerofill(1)                2     9
29    373   4      table-lookup                        11     0
30    377   1                                           3     9
31    378   2      no zeros, zerofill(1)                2     9
32    380   8      no zeros                             2     9
33    388   4      always zero                          2     9
34    392   4      table-lookup                        12     0
35    396   4      no zeros, zerofill(1)               13     9
36    400   4      no zeros, zerofill(1)                2     9
37    404   1                                           2     9
38    405   4      no zeros                             2     9
39    409   4      always zero                          2     9
40    413   4      no zeros                             2     9
41    417   4      always zero                          2     9
42    421   4      no zeros                             2     9
43    425   4      always zero                          2     9
44    429   20     no empty                             3     9
45    449   30     no empty                             3     9
46    479   1                                          14     4
47    480   1                                          14     4
48    481   79     no endspace, no empty               15     9
49    560   79     no empty                             2     9
50    639   79     no empty                             2     9
51    718   79     no endspace                         16     9
52    797   8      no empty                             2     9
53    805   1                                          17     1
54    806   1                                           3     9
55    807   20     no empty                             3     9
56    827   4      no zeros, zerofill(2)                2     9
57    831   4      no zeros, zerofill(1)                2     9

由myisampack打印的信息在下面描述：

normal
不是用额外压缩的列数。
empty-space
仅包含空格值的列数；这些将占据1位。
empty-zero
只包含二进制0值的列数；这些将占据1位。
empty-fill
不占据其类型全部字节范围的整形列数；这些被改变为一种更小的类型(例如，一个INTEGER列可以被改变为MEDIUMINT)。
pre-space
用前导空间存储的小数的列数。在这种情况下，每个值将包含一个前导空格的数量的计数。
end-space
有很多拖后空格的列数。在这种情况下，每个值将包含一个拖后空格的数量的计数。
table-lookup
列只有少数不同的值，并且它在哈夫曼压缩前被变换一个ENUM。
zero
所有值为零的列数。
Original trees
哈夫曼树的初始数目。
After join
在联结哈夫曼树以节省一些表头空间后余下的不同树的数量。

在一张表被压缩以后，myisamchk -dvv打印出每个字段的额外信息：

Type
字段类型可以包含下列描述符：
constant
所有行有相同的值。
no endspace
不存储尾空格。
no endspace, not_always
不存储尾空格而且不对所有值做尾空格压缩。
no endspace, no empty
不存储尾空格。不存储空值。
table-lookup
列被变换到一个ENUM。
zerofill(n)
值中最高n位总是0并且不被存储。
no zeros
不存储零。
always zero
0值以1位被存储。
Huff tree
与字段相关的哈夫曼树
Bits
在哈夫曼树里使用的位数。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-13 维护 MySQL 安装

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

13 维护MySQL安装

13.1 使用myisamchk进行表的维护和崩溃恢复

为了检查/修复MyISAM表(.MYI和.MYD)，你应该使用myisamchk实用程序。为了检查/修复ISAM表(.ISM和.ISD)，你应该使用isamchk实用程序。见9.4 MySQL 桌子类型。

在下文中，我们将讨论myisamchk，但是也适用于老的isamchk。

你可以使用myisamchk实用程序来获得有关你的数据库桌表的信息、检查和修复他们或优化他们。下列小节描述如何调用myisamchk（包括它的选项的描述)，如何建立一个表维护的时间表，并且如何使用myisamchk执行其各种功能。

如果你用--skip-locking运行mysqld（它在一些系统上是缺省的，如Linux)，当mysqld正在使用同一个表时，你不能可靠地使用myisamchk检查一张表。如果你能肯定在你运行myisamchk时没有人通过mysqld正在存取表，在你开始检查表之前，你仅需做mysqladmin flush-tables。如果你不能保证， 那么当你检查表时，你必须停掉mysqld。如果你在mysqld正在更新表时运行myisamchk，你可能得到一个表已破坏的警告，即使它没有。

如果你没使用--skip-locking，你能在任何时间使用myisamchk检查表。当你这样时，所有试图更新表的客户在继续前将等到myisamchk就绪。

如果你使用myisamchk修复或优化表，你必须总是保证mysqld服务器不在使用表(如果你正在使用--skip-locking，这也适用)。如果你不停掉mysqld，在你运行myisamchk前，你至少应该做一个mysqladmin flush-tables。

在大多数情况下，你也可使用命令OPTIMIZE TABLES优化并修复表，但是这不如myisamchk快或可靠(在真正的致命错误的情况下)。在另一方面，OPTIMIZE TABLE较易使用并且你不必须关心清空表。见7.9OPTIMIZE TABLE句法。

13.1.1 myisamchk调用语法

myisamchk这样调用：

shell> myisamchk [options] tbl_name

options指定你想要myisamchk做什么。他们在下面描述。（你也可以通过调用myisamchk --help得到一张选项表。) 没有选项，myisamchk简单地检查你的表。为了得到更多的信息或告诉myisamchk执行校正操作，指定在下面和下小节描述的选项择。

tbl_name是你想要检查的数据库表。如果你不在数据库目录的某处运行myisamchk，你必须指定到文件的路径，因为myisamchk不知道你的数据库位于哪儿。实际上，myisamchk别在乎你正在操作的文件是否位于一个数据库目录；你可以拷贝对应于一张数据库表的文件到别处并且在那里执行恢复操作。

如果你愿意，你可以myisamchk命令行命名几个表。你也能指定一个名字作为一个索引文件(用“ .MYI”后缀)，它允许你通过使用模式“*.MYI”指定在一个目录所有的表。例如，如果你在一个数据库目录，你可以这样在目录下检查所有的表：

shell> myisamchk *.MYI

如果你不在数据库目录下，你可通过指定到目录的路径检查所有在那里的表：

shell> myisamchk /path/to/database_dir/*.MYI

你甚至可以通过为MySQL数据目录的路径指定一个通配符来检查所有的数据库中的所有表：

shell> myisamchk /path/to/datadir/*/*.MYI

myisamchk支持下列选项：

-a, --analyze
分析键值的分布。这通过让联结优化器更好地选择表应该以什么次序联结和应该使用哪个键来改进联结性能。
-#, --debug=debug_options
输出调试记录文件。debug_options字符串经常是'd:t:o,filename'。
-d, --description
打印出关于表的一些信息。
-e, --extend-check
非常彻底地检查表。这仅在极端情况下是必要的。通常，myisamchk应该找出所有错误，即使没有改选项。
-f, --force
覆盖老的临时文件。如果你在检查表时使用-f (运行myisamchk没有-r)，myisamchk在检查期间将自动为出现一个错误的表用-r重启。
--help
显示一条帮助消息并且退出。
-i, --information
打印有关被检查的表的信息统计。
-k #, --keys-used=#
与-r一起使用。告诉ISAM表处理器仅更新头#个索引。较高编号的索引被撤销。这能用来使插入变得更快！撤销的索引能通过使用myisamchk -r被重新激活。
-l, --no-symlinks
在修复时，不跟随符号连接。通常myisamchk修复一个符号连接所指的表。
-q, --quick
与-r一起使用使得一个修复更快。通常，原来的数据文件没被接触；你能指定第二个-q强制使用原来的数据文件。
-r, --recover
恢复模式。可以修复几乎所有一切，除非唯一的键不是唯一。
-o, --safe-recover
恢复模式。使用一个老的恢复方法；这比-r慢些，但是能处理一-r不能处理的情况。
-O var=option, --set-variable var=option
设置一个变量的值。可能的变量列在下面。
-s, --silent
沉默模式。当错误发生时，仅写输出。你能使用-s两次(-ss)非常沉默地做myisamchk。
-S, --sort-index
以从高到低的顺序排序索引树块。这将优化搜寻并且将使按键值的表扫描更快。
-R index_num, --sort-records=index_num
根据一个索引排序记录。这使你的数据更局部化并且可以加快在该键上的SELECT和ORDER BY的范围搜索。（第一次做排序可能很慢！) 为了找出一张表的索引编号，使用SHOW INDEX，它以myisamchk看见他们的相同顺序显示一张表的索引。索引从1开始编号。
-u, --unpack
解开一个用myisampack压缩的表。
-v, --verbose
冗长模式。打印更多的信息。这能与-d和-e一起使用。为了更冗长，使用-v多次(-vv, -vvv)！
-V, --version
打印myisamchk版本并退出。
-w, --wait
如果表被锁定，等待。

对--set-variable(-O)选项，可能的变量是：

key_buffer_size       当前值: 16776192
read_buffer_size      当前值: 262136
write_buffer_size     当前值: 262136
sort_buffer_size      当前值: 2097144
sort_key_blocks       当前值: 16
decode_bits           当前值: 9

13.1.2 myisamchk内存使用

当你运行myisamchk时，内存分配很重要。myisamchk使用不超过你用-O选项指定的内存量。如果你想在很大的文件上使用myisamchk，你首先应该确定你想要它使用多少内存。缺省仅使用大约 3M 来修复。通过使用更大的值，你能使myisamchk更快地操作。例如，如果你有多于32M内存，你能使用例如这些选项(除了任何你可能指定的选项)：

shell> myisamchk -O sort=16M -O key=16M -O read=1M -O write=1M ...

使用-O sort=16M应该可能对大多数情形就足够了。

必须明白，myisamchk使用在TMPDIR里面的临时文件。如果TMPDIR指向一个内存文件系统，你可能很容易得到内存溢出的错误。如果它发生，设定TMPDIR指向有更多空间的某个目录并且重启myisamchk。

13.2 建立一个数据库表维护规范

在一个定期基础而非等到问题出现才实施数据库表的检查是一个好主意。为维护目的，你能使用myisamchk -s检查桌子。-s选项使myisamchk以沉默模式运行，当错误出现时，仅仅打印消息。

在服务器启动时检查表是一个好主意。例如，无论何时机器在更新当中重新启动了，你通常需要检查所有可能被影响了的表。（这是一个“期望破坏了的表”) 如果重启后有一个旧的“.pid”（进程ID)，你能为safe_mysqld加入一个测试，运行myisamchk检查所有在过去24小时修改过的表)。（“.pid”文件在mysqld启动时由它创建，并它正常终止时删除。在系统启动时存在一个“.pid”文件表明mysqld异常地终止了。）

一个更好的测试将是检查任何表，它的最后修改时间是比“.pid”文件更新。

你也应该定期在正常系统操作期间检查表。在TcX，我们运行一个cron任务，每周一次检查我们所有重要的表，在一个“crontab”文件中使用这样的行：

35 0 * * 0 /path/to/myisamchk -s /path/to/datadir/*/*.MYI

这打印出损坏的表的信息，因此我们能检验并且在需要时修复他们。

当我们现在几年(这确实是真的)都没有任何意外损坏的表时(由于除硬件故障外的其他原因造成损坏的表)，每周一次对我们是足够了。

我们建议现在开始，你对所有最后24小时内被更新了表每晚都执行myisamchk -s，直到你变得象我们那样信任MySQL。

13.3 获得关于一个表的信息

为了获得关于一个表的描述或统计，使用显示在下面的命令。我们以后更详细地解释某些信息。

myisamchk -d tbl_name
以“描述模式”运行myisamchk，生成你的表的描述。如果你用--skip-locking选项启动MySQL服务器，myisamchk可以当它运行时报告被一个更新的表的错误。然而，既然在描述模式中myisamchk不改变表，没有破坏数据的任何风险。
myisamchk -d -v tbl_name
为了生成更多关于myisamchk正在做什么的信息，加上-v告诉它以冗长模式运行。
myisamchk -eis tbl_name
仅显示一个表最重要的信息。因为必须读取整个表，它很慢。
myisamchk -eiv tbl_name
这类似-eis，只是告诉你正在做什么。

myisamchk -d输出的例子：

MyISAM file:     company.MYI
Record format:       Fixed length
Data records:           1403698  Deleted blocks:         0
Recordlength:               226

table description:
Key Start Len Index   Type
1   2     8   unique  double
2   15    10  multip. text packed stripped
3   219   8   multip. double
4   63    10  multip. text packed stripped
5   167   2   multip. unsigned short
6   177   4   multip. unsigned long
7   155   4   multip. text
8   138   4   multip. unsigned long
9   177   4   multip. unsigned long
    193   1           text

myisamchk -d -v输出的例子：

MyISAM file:         company
Record format:       Fixed length
File-version:        1
Creation time:       1999-10-30 12:12:51
Recover time:        1999-10-31 19:13:01
Status:              checked
Data records:           1403698  Deleted blocks:              0
Datafile parts:         1403698  Deleted data:                0
Datafilepointer (bytes):      3  Keyfile pointer (bytes):     3
Max datafile length: 3791650815  Max keyfile length: 4294967294
Recordlength:               226

table description:
Key Start Len Index   Type                  Rec/key     Root Blocksize
1   2     8   unique  double                      1 15845376      1024
2   15    10  multip. text packed stripped        2 25062400      1024
3   219   8   multip. double                     73 40907776      1024
4   63    10  multip. text packed stripped        5 48097280      1024
5   167   2   multip. unsigned short           4840 55200768      1024
6   177   4   multip. unsigned long            1346 65145856      1024
7   155   4   multip. text                     4995 75090944      1024
8   138   4   multip. unsigned long              87 85036032      1024
9   177   4   multip. unsigned long             178 96481280      1024
    193   1           text

myisamchk -eis输出的例子：

Checking MyISAM file: company
Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4
Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3
Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4
Total:    Keyblocks used:  98%  Packed:   17%

Records:          1403698    M.recordlength:     226   Packed:             0%
Recordspace used:     100%   Empty space:          0%  Blocks/Record:   1.00
Record blocks:    1403698    Delete blocks:        0
Recorddata:     317235748    Deleted data:         0
Lost space:             0    Linkdata:             0

User time 1626.51, System time 232.36
Maximum resident set size 0, Integral resident set size 0
Non physical pagefaults 0, Physical pagefaults 627, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 639, Involuntary context switches 28966

myisamchk -eiv输出的例子：

Checking MyISAM file: company
Data records: 1403698   Deleted blocks:       0
- check file-size
- check delete-chain
block_size 1024:
index  1:
index  2:
index  3:
index  4:
index  5:
index  6:
index  7:
index  8:
index  9:
No recordlinks
- check index reference
- check data record references index: 1
Key:  1:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
- check data record references index: 2
Key:  2:  Keyblocks used:  98%  Packed:   50%  Max levels:  4
- check data record references index: 3
Key:  3:  Keyblocks used:  97%  Packed:    0%  Max levels:  4
- check data record references index: 4
Key:  4:  Keyblocks used:  99%  Packed:   60%  Max levels:  3
- check data record references index: 5
Key:  5:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 6
Key:  6:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 7
Key:  7:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 8
Key:  8:  Keyblocks used:  99%  Packed:    0%  Max levels:  3
- check data record references index: 9
Key:  9:  Keyblocks used:  98%  Packed:    0%  Max levels:  4
Total:    Keyblocks used:   9%  Packed:   17%

- check records and index references
[LOTS OF ROW NUMBERS DELETED]

Records:          1403698    M.recordlength:     226   Packed:             0%
Recordspace used:     100%   Empty space:          0%  Blocks/Record:   1.00
Record blocks:    1403698    Delete blocks:        0
Recorddata:     317235748    Deleted data:         0
Lost space:             0    Linkdata:             0

User time 1639.63, System time 251.61
Maximum resident set size 0, Integral resident set size 0
Non physical pagefaults 0, Physical pagefaults 10580, Swaps 0
Blocks in 4 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 10604, Involuntary context switches 122798

这是对于用在上述例子中的表的数据大小和索引文件的大小：

-rw-rw-r--   1 monty    tcx     317235748 Jan 12 17:30 company.MYD
-rw-rw-r--   1 davida   tcx      96482304 Jan 12 18:35 company.MYM

对myisamchk产生信息的类型在下面解释。“keyfile”是索引文件。“记录”和“行”是同义词。

ISAM file
ISAM(索引)文件名。
Isam-version
ISAM格式的版本。当前总是2。
Creation time
数据文件被创建的时间。
Recover time
索引/数据文件上次被重建的时间。
Data records
在表中有多少记录。
Deleted blocks
有多少删除的块仍然保留着空间。你可以优化表以使这个空间减到最小。见13.4.3 表优化。
Datafile: Parts
对动态记录格式，这指出有多少数据块。对于一个没有碎片的优化过的表，这与Data records相同。
Deleted data
不能回收的删除数据有多少字节。你可以优化表以使这个空间减到最小。见13.4.3 表优化。
Datafile pointer
数据文件指针的大小，以字节计。它通常是2、3、4或5个字节。大多数表用2个字节管理，但是目前这还不能从MySQL控制。对固定表，这是一个记录地址。对动态表，这是一个字节地址。
Keyfile pointer
索引文件指针的大小，以字节计。它通常是1、2或3个字节。大多数表用 2 个字节管理，但是它自动由MySQL计算。它总是一个块地址。
Max datafile length
表的数据文件(.MYD文件)能够有多长，以字节计。
Max keyfile length
表的关键字文件(.MYI文件)能够有多长，以字节计。
Recordlength
每个记录占多少空间，以字节计。
Record format
用于存储表行的格式。上面的例子使用Fixed length。其他可能的值是Compressed和Packed.
table description
在表中所有键值的一张表。对每个键，给出一些底层的信息：
Key
该键的编号。
Start
该索引部分从记录的哪里开始。
Len
该索引部分是多长。对于紧凑的数字，这应该总是列的全长。对字符串，它可以比索引的列的全长短些，因为你能索引字符串列的前缀。
Index
unique或multip（multiple)。表明一个值是否能在该索引中存在多次。
Type
这索引部分有什么数据类型。这是一个packed、stripped或empty选项的 ISAM 数据类型。
Root
根索引块的地址。
Blocksize
每个索引块的大小。缺省是1024，但是值可以在编译时改变。
Rec/key
这是由优化器使用的统计值。它告诉对该键的每个值有多少条记录。唯一键总是有一个1值。在一个表被装载后(或改变很大)，这可以用myisamchk -a更新。如果这根本没被更新，给定一个30的缺省值。
在上面第一个例子中，第个9键是有2个部分的多部键。
Keyblocks used
键块使用的百分比是什么。因为在例子中使用的表只能用myisamchk被重新组织，值非常高(很接近理论上的最大值)。
Packed
MySQL试图用一个公共后缀压缩键。这只能被用于CHAR/VARCHAR/DECIMAL键。对长字符串如姓名，这能显著地减少使用空间。在上面的第3个例子中，第4个键是10个字符长并且在空间上达到60%的缩减。
Max levels
对于该键的B树有多深。有长键的大表有较高的值。
Records
表中有多少行。
M.recordlength
平均记录长度。对于有定长记录的表，这是准确的记录长度。
Packed
MySQL从字符串的结尾去掉空格。Packed值表明这样做达到的节约的百分比。
Recordspace used
数据文件被使用的百分比。
Empty space
数据文件未被使用的百分比。
Blocks/Record
每个记录的平均块数 (即，一个碎片记录由多少个连接组成)。对固定格式表，这总是1。该值应该尽可能保持接近1.0。如果它变得太大，你可用myisamchk重新组织表。见13.4.3 表优化。
Recordblocks
多少块(连接)被使用。对固定格式，它与记录的个数相同。
Deleteblocks
多少块(连接)被删除。
Recorddata
在数据文件中使用了多少字节。
Deleted data
在数据文件中多少字节被删除(未使用)。
Lost space
如果一个记录被改为更短的长度，就损失了一些空间。这是所有这样的损失之和，以字节计。
Linkdata
当使用动态表格式，记录碎片用指针连接(每个4 ～ 7字节)。 Linkdata被这样的指针使用的内存量之和。

如果一张表已经用myisampack压缩了，myisamchk -d打印每个表列的附加信息。对于它的一个例子及其含义的描述，见12.5 MySQL压缩只读表生成器。

13.4 使用myisamchk进行崩溃恢复

由MySQL用来存储数据的文件格式以已经被广泛地测试过，但是总是有外部情况可以导致数据库表被破坏：

  • mysqld进程在一个写入当中被杀死。
  • 计算机的意外关闭(例如，如果计算机掉电）。
  • 一个硬件错误

这章描述如何检查和处理在MySQL数据库中的数据损坏。如果你的表损坏很多，你应该尝试找出其原因！见G.1 调试一个MySQL服务器。

在执行崩溃恢复时，理解在一个数据库中的每一个表tbl_name对应的在数据库目录中的3个文件是很重要的：

文件 | 用途
“tbl_name.frm” | 表定义(表格)文件
“tbl_name.MYD” | 数据文件
“tbl_name.MYI” | 索引文件

这3个文件的每一个文件类型可能遭受不同形式的损坏，但是问题最常发生在数据文件和索引文件。

myisamchk通过一行一行地创建一个“.MYD”（数据 )文件的副本来工作，它通过由删除老的“.MYD 文件并且重命名新文件到原来的文件名结束修复阶段。如果你使用--quick，myisamchk不创建一个临时“.MYD”文件，只是假定“.MYD”文件是正确的并且仅创建一个新的索引文件，不接触“.MYD”文件，这是安全的，因为myisamchk自动检测“.MYD”文件是否损坏并且在这种情况下，放弃修复。你也可以给myisamchk两个--quick选项。在这种情况下，myisamchk不会在一些错误上(象重复键)放弃，相反试图通过修改“.MYD”文件解决它们。通常，只有在你在太少的空闲磁盘空间上实施一个正常修复，使用两个--quick选项才有用。在这种情况下，你应该至少在运行myisamchk前做一个备份。

13.4.1 怎样检查表的错误

为了检查一张表，使用下列命令：

myisamchk tbl_name
这能找出所有错误的99.99%。它不能找出的是仅仅涉及数据文件的损坏(这很不常见)。如果你想要检查一张表，你通常应该没有选项地运行myisamchk或用-s或--silent选项的任何一个。
myisamchk -e tbl_name
它做一个完全彻底的数据检查(-e意思是“扩展检查”)。它对每一行做每个键的读检查以证实他们确实指向正确的行。这在一个有很多键的大表上可能花很长时间。myisamchk通常将在它发现第一个错误以后停止。如果你想要获得更多的信息，你能增加--verbose(-v)选项。这使得myisamchk继续一直到最多20个错误。在一般使用中，一个简单的myisamchk（没有除表名以外的参数)就足够了。
myisamchk -e -i tbl_name
象前面的命令一样，但是-i选项告诉myisamchk还打印出一些统计信息。

13.4.2 怎样修复表

一张损坏的表的症状通常是查询意外中断并且你能看到例如这些错误：

  • “tbl_name.frm”被锁定不能改变。
  • 不能找到文件“tbl_name.MYI”（Errcode ：### ）。
  • 从表处理器的得到错误###(此时，错误135是一个例外）。
  • 意外的文件结束。
  • 记录文件被毁坏。

在这些情况下，你必须修复表。myisamchk通常能检测并且修复出错的大部分东西。

修复过程包含最多4个阶段，在下面描述。在你开始前，你应该cd到数据库目录和检查表文件的权限，确保他们可被运行mysqld的Unix用户读取(和你，因为你需要存取你正在检查的文件)。如果它拒绝你修改文件，他们也必须是可被你写入的。

阶段1：检查你的表

运行myisamchk *.MYI或(myisamchk -e *.MYI，如果你有更多的时间)。使用-s（沉默)选项禁止不必要的信息。

你必须只修复那些myisamchk报告有一个错误的表。对这样的表，继续到阶段2。

如果在检查时，你得到奇怪的错误(例如out of memory错误)，或如果myisamchk崩溃，到阶段3。

舞台 2 ：简单安全的修复

首先，试试myisamchk -r -q tbl_name(-r -q意味着“快速恢复模式”)。这将试图不接触数据文件来修复索引文件。如果数据文件包含它应有的一切和在数据文件指向正确地点的删除连接，这应该管用并且表可被修复。开始修理下一张表。否则，使用下列过程：

  1. 在继续前做数据文件的一个备份。
  2. 使用myisamchk -r tbl_name(-r意味着“恢复模式”)。这将从数据文件中删除不正确的记录和已被删除的记录并重建索引文件。
  3. 如果前面的步骤失败，使用myisamchk --safe-recover tbl_name。安全恢复模式使用一个老的恢复方法，处理常规恢复模式不行的少数情况(但是更慢)。

如果在修复时，你得到奇怪的错误(例如out of memory错误)，或如果myisamchk崩溃，到阶段3。

舞台 3 ：困难的修理

如果在索引文件的第一个16K块被破坏，或包含不正确的信息，或如果索引文件丢失，你只应该到这个阶段 。在这种情况下，创建一个新的索引文件是必要的。按如下这样做：

  1. 把数据文件移更安全的地方。
  2. 使用表描述文件创建新的(空)数据和索引文件：
    shell> mysql db_name
mysql> DELETE FROM tbl_name;
mysql> quit
  3. 将老的数据文件拷贝到新创建的数据文件之中。（不要只是将老文件移回新文件之中；你要保留一个副本以防某些东西出错。）

回到阶段2。现在myisamchk -r -q应该工作了。（这不应该是一个无限循环)。

阶段4：非常困难的修复

只有描述文件也破坏了，你才应该到达这个阶段。这应该从未发生过，因为在表被创建以后，描述文件就不再改变了。

  1. 从一个备份恢复描述文件并且回到阶段3。你也可以恢复索引文件并且回到阶段2。对后者，你应该用myisamchk -r启动。
  2. 如果你没有一个备份但是确切地知道表是怎样被创建的，在另一个数据库中创建表的一个拷贝。删除新的数据文件，然后从其他数据库将描述和索引文件移到破坏的数据库中。这给了你新的描述和索引文件，但是让数据文件独自留下来了。回到阶段2并且尝试重建索引文件。

13.4.3 表优化

为了组合成碎片的记录并且消除由于删除或更新记录而浪费的空间， 以恢复模式运行myisamchk：

shell> myisamchk -r tbl_name

你可以用SQL的OPTIMIZE TABLE语句使用的相同方式来优化一张表，OPTIMIZE TABLE比较容易，但是myisamchk更快。也没有在一个实用程序和服务器之间不必要的交互可能性，因为当你使用OPTIMIZE TABLE时，服务器做所有的工作。

myisamchk也有你可用来改进一个表的性能的很多其他选项：

-S, --sort-index

-R index_num, --sort-records=index_num

-a, --analyze

对于选项完整的描述见13.1.1 myisamchk调用语法。

13.5 日志文件维护

当MySQL与日志文件一起使用时，你有时想要删除/备份旧的日志文件并且告诉MySQL在新文件中开始记录。见9.2 更新日志。

在一个 Linux (Redhat)的安装上，你可为此使用mysql-log-rotate脚本。如果你从RPM分发安装MySQL，脚本应该自动被安装了。

在其他系统上，你必须自己安装一个短脚本，你可从cron启动来处理日志文件。

你可以通过使用mysqladmin flush-logs或SQL命令FLUSH LOGS来强制MySQL开始使用新的日志文件。如果你正在使用MySQL 3.21，你必须使用mysqladmin refresh。

上面的命令做下列事情：

  • 如果使用标准日志(--log)，关闭并重新打开日志文件。(“ mysql.log”为缺省)。
  • 如果使用更新日志(--log-update)，关闭更新日志并且重新打开有一个更高的顺序闭编号的新日志文件。

如果你只使用一个更新日志，你只须清空日志文件，然后移走旧的更新日志文件到一个备份中。如果你使用一般的日志，你可以这样做：

shell> cd mysql-data-directory
shell> mv mysql.log mysql.old
shell> mysqladmin flush-tables

然后做一个备份并删除“mysql.old”。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-14 向MySQL增加新函数

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

14 为MySQL增加新函数

有2种方法把新函数加到MySQL中：

  • 你可以通过用户定义函数(UDF)接口加入函数。用户定义函数用CREATE FUNCTION和DROP FUNCTION语句动态地增加和删除。见7.30 CREATE FUNCTION/DROP FUNCTION句法。
  • 你可以加入函数作为一个原生的(内置的)MySQL函数。原生函数被编译进mysqld服务器并且在一个永久的基础上可得到。

每种方法都有优点和缺点：

  • 如果你编写一个用户定义函数，你必须安装服务器外还得自己安装对象文件。如果你编译函数进服务器中，你不需要那样做。
  • 你能把UDF加到MySQL二进制代码发行中。原生函数要求你修改源代码分发。
  • 如果你升级你的MySQL分发，你能继续使用你的以前安装的UDF。对于原生函数，你必须在每次升级时重复你的修改。

无论你使用哪种方法增加新函数，他们可以象原生函数例如ABS()或SOUNDEX()那样使用。

14.1 增加一个新的用户定义函数

对于UDF的工作机制，函数必须用C或C++编写并且你的操作系统必须支持动态装载。MySQL源代码分发包括一个文件“sql/udf_example.cc”，它定义了5个新函数。请教这个文件看UDF调用约定怎样工作。

对每一个你想在SQL语句中使用的函数，你应该定义对应的C(或 C++)函数。在下面的讨论中，“xxx”用于一个函数名的例子。为了区别SQL和C/C++用法，XXX()(大写)表明SQL函数调用，而xxx()((小写)表明C/C++函数调用。

你编写实现XXX()的接口的C/C++函数是：

xxx()（必需的）
主函数。这是计算函数结果的地方。SQL 类型于你的C/C++函数返回类型的对应关系如下：
SQL 类型 | C/C++ 类型
STRING | char *
INTEGER | long long
REAL | double
xxx_init()（可选）
为xxx()的初始化函数，它可用于：
  • 检查传到XXX()的参数数量。
  • 检查参数是一种所需的类型，或，另外地，当主函数被调用时，告诉MySQL，为了强制参数到你想要的类型。
  • 分配任何由主函数所需的内存。
  • 指定结果的最大长度。
  • 指定(对REAL函数)小数位的最大数目。
  • 指定结果是否能是NULL。
xxx_deinit()（可选）
为xxx()的结束函数，它应该释放初始化函数分配了的任何内存。

当一条SQL语句调用XXX()时，MySQL调用初始化函数xxx_init()，让它执行任何所需的设置，例如参数检查或内存分配。如果xxx_init()返回一个错误，SQL语句用一条错误消息并被放弃而主函数和结束函数不被调用，否则，为每行调用主函数xxx()一次。在所有行被处理完后，结束函数xxx_deinit()被调用，因此它能执行任何必要的清除。

所有函必须是线程安全的(不只是主函数，还有初始化和结束函数)。这意味着，你不允许分配任何改变的全局或静态变量！如果你需要内存，你应该在xxx_init()种分配它并且在xxx_deinit()中释放它。

14.1.1 UDF的调用顺序

主函数应该如下定义。注意返回类型和参数不同，取决于你是否在CREATE FUNCTION语句中声明SQL函数XXX()返回STRING、INTEGER或REAL：

对STRING函数：

char *xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *result, unsigned long *length,
              char *is_null, char *error);

对INTEGER函数：

long long xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

对于REAL函数：

double xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

初始化和结束函数象这样被声明：

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

void xxx_deinit(UDF_INIT *initid);

initid参数被传给所有3个函数，它指向一个UDF_INIT结构，被用来在函数之间传递信息。UDF_INIT结构成员列在下面。初始化函数应该填写它想要改变的任何成员。（对一个成员使用缺省值，不改变它。）

my_bool maybe_null
如果xxx()能返回NULL，xxx_init()应该设置maybe_null为1。如果参数的任何一个被声明maybe_null，缺省值是1。
unsigned int decimals
小数位数目。缺省值是在被传给主函数的参数中小数位的最大数目。（例如，如果函数传递1.34、1.345和1.3，缺省值将是3，因为1.345有3个小数位。
unsigned int max_length
字符串结果的最大长度。缺省值不同，取决于函数的结果类型。对字符串函数，缺省是最长的参数的长度。对整数函数，缺省是21位。对实数函数，缺省是13加上由initid->decimals指出的小数位数。（对数字函数，长度包括任何符号位或小数点字符。）
char *ptr
函数可为它自己的目的使用的一个指针。例如，函数能使用initid->ptr在函数之间传递分配的内存。在xxx_init()中，分配内存并将它赋给这个指针：
initid->ptr = allocated_memory;

在xxx()和xxx_deinit()中，参照initid->ptr来使用或释放内存。

14.1.2 参数处理

args参数指向一个UDF_ARGS成员，其结构列在下面：

unsigned int arg_count
参数个数。如果你想要函数用一个特定数量的参数被调用，在初始化函数中检查这个值。例如：
if (args->arg_count != 2)
{
    strcpy(message,"XXX() requires two arguments");
    return 1;
}
enum Item_result *arg_type
为每个参数的类型。可能的类型值是STRING_RESULT、INT_RESULT和REAL_RESULT。为了确保参数是一种给定的类型，而如果他们不是，返回一个错误，在初始化函数中检查arg_type数组。例如：
if (args->arg_type[0] != STRING_RESULT
      && args->arg_type[1] != INT_RESULT)
{
    strcpy(message,"XXX() requires a string and an integer");
    return 1;
}

作为另一种要求你的函数的参数类型是特定类型的选择，你可以使用初始化函数设置arg_type成员是你想要的类型。这导致MySQL为每个xxx()调用强制参数为那些类型，例如，为了指定头 2个参数到字符串和整数的强制，在xxx_init()中做这些：

args->arg_type[0] = STRING_RESULT;
args->arg_type[1] = INT_RESULT;
char **args
args->args将关于你的函数用它调用的参数的一般特性的信息传递到初始化函数。对一个常数参数i，args->args[i]指向参数值。（见下面关于如何正确存取值的指令) 对一个非常数的参数，args->args[i]是0。一个常数参数只是使用常数的一个表达式，例如3或4*7-2或SI(3.14)。一个非常数参数是引用可能每行不同的值的一个表达式，例如列名字或用非常数参数调用的函数。对主函数的每次调用，args->args包含对当前正在处理的行所传递的实际参数。函数可以如下地引用一个参数i：
  • 一个STRING_RESULT类型的参数由一个字符串指针加一个长度给出，允许处理任意的长度的二进制的数据或数据。字符串内容可由args->args[i]得到并且字符串长度是args->lengths[i]。你不应该假设字符串是以空(null)结束的。
  • 对于一个INT_RESULT类型的参数，你必须强制转换args->args[i]为一个long long值：
    long long int_val;
int_val = *((long long*) args->args[i]);
  • 对一个REAL_RESULT类型的参数，你必须强制转换args->args[i]为一个double值：
    double    real_val;
real_val = *((double*) args->args[i]);
unsigned long *lengths
对初始化函数，lengths数组指出每个参数的最大字符串长度。对于主函数调用，lengths包含为当前正在被处理的行传递的任何字符串参数的实际长度。对INT_RESULT或REAL_RESULT类型的参数，lengths仍然包含参数的最大长度(就象对初始化函数)。

14.1.3 返回值和出错处理

如果没有出现错误，初始化函数应该返回0，否则返回1。如果发生一个错误，xxx_init()应该在message参数中存储一条空字符结束的错误消息，消息将被返回给客户。消息缓冲区是MYSQL_ERRMSG_SIZE个字符长，但是你应该试着保持消息不到80个字符以便它适合一幅标准终端屏幕的宽度。

对long long和double函数，主函数xxx()的返回值是函数值。对字符串函数，字符串在result和length参数中被返回。result是至少255个字节长的一个缓冲区，设置这些为返回值的内容和长度。例如：

memcpy(result, "result string", 13);
*length = 13;

字符串函数返回值也通常指向结果。

为了在主函数中表明一个NULL返回值，设定is_null为1：

*is_null = 1;

为了在函数中表明一个错误返回，设定error参数为1：

*error = 1;

如果对任何行xxx()设置*error为1，对当前行函数值是NULL，并且在该语句中处理的后续行，XXX()被调用。(xxx()甚至将不为随后的行被调用。）注意：在MySQL 3.22.10以前的版本中，你应该都设置*error和*is_null：

*error = 1;
*is_null = 1;

14.1.4 编译并安装用户定义函数

实现UDF的文件必须在服务器运行的主机上被编译并且安装。这个过程下面描述，UDF例子文件包含在MySQL源代码分发的“udf_example.cc”中，这个文件包含下列函数：

  • metaphon()返回字符串参数的一个变音位(metaphon)字符串。这有点象一个soundex字符串，但是它更针对英语音调。
  • myfunc_double()返回在其参数中所有字符的ASCII值的和，除以其参数长度之和。
  • myfunc_int()返回其参数长度之和。
  • lookup()返回对主机名的IP数。
  • reverse_lookup()返回对一个IP数的主机名。函数可以以一个字符串"xxx.xxx.xxx.xxx"或4位数字被调用。

一个可动态装载的文件应该编译为一个共享的对象文件，使用象这样的命令：

shell> gcc -shared -o udf_example.so myfunc.cc

通过运行在你的MySQL源代码树的“sql”目录下的下列命令，你能很容易地找出对你的系统正确的编译器选项：

shell> make udf_example.o

你应该运行一个类似于make显示的编译命令，除了你应该删除接近行结尾的-c选项并且在行最后增加-o udf_example.so。（在一些系统上，你可能需要在命令上保留-c。）

一旦你编译了包含UDF 的一个共享对象，你必须安装它并且把它告诉MySQL。自“udf_example.cc”编译一个共享对象产生一个名字类似“udf_example.so”的文件（准确的名字可以依平台不同而不同)。拷贝这个文件到被某个ld寻找的目录，例如“/usr/lib”。在许多系统上，你能设定LD_LIBRARY或LD_LIBRARY_PATH环境变量，指向有UDF函数文件的目录。dopen手册页告诉你你应该在你的系统上使用哪个变量。你应该在mysql.server或safe_mysqld中设置它并且重启mysqld。

在库被安装以后，用这些命令通知mysqld有关新的函数的信息：

mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
mysql> CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
mysql> CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";

函数可使用DROP FUNCTION删除：

mysql> DROP FUNCTION metaphon;
mysql> DROP FUNCTION myfunc_double;
mysql> DROP FUNCTION myfunc_int;
mysql> DROP FUNCTION lookup;
mysql> DROP FUNCTION reverse_lookup;

CREATE FUNCTION和DROP FUNCTION语句在mysql数据库中更新系统表func。函数名、类型和共享库名被保存在该表中。你必须有对mysql的insert和delete权限以创建和抛弃函数。

你不应该使用CREATE FUNCTION增加一个已经被创建的函数。如果你需要重新安装函数，你应该用DROP FUNCTION删除它，然后用CREATE FUNCTION重新安装它。你将需要这样做，例如，如果你重新编译你的函数的一个新版本，以便mysqld获得新版本，否则服务器将继续使用旧版本。

活跃函数在每次服务器启动时再次装载，除非你使用--skip-grant-tables选项启动mysqld。在这种情况下，UDF初始化被跳过并且UDF不可用。（活跃函数是一个用CREATE FUNCTION装载并且没有用DROP FUNCTION删除的函数。)

14.2 增加一个新的原生函数

增加一个新的原生函数的过程在下面描述。注意，你不能往一个二进制分发中加入新函数，因为该过程涉及修改MySQL源代码。你必须从源代码分发自行编译MySQL。也要注意，如果你迁移到MySQL的其他版本（例如，当一个新版本被释放时)，你将需要用新版本重复该过程。

为了加入一个新的原生MySQL函数，遵循这些步骤：

  1. 在“lex.h”加入1行，它在sql_functions[]数组中定义函数名。
  2. 在“sql_yacc.yy”加入2行。一行指出示yacc应该定义的预处理器符号(这应该加在文件的开始)，然后定义函数参数并且将一个具有这些参数“项目”加到simple_expr语法分析规则中。有一个例子，检查在“sql_yacc.yy 所有的SOUNDEX出现看看它使怎样做的。
  3. 在“item_func.h”中，声明一个继承Item_num_func或Item_str_func的类，取决于你的函数是返回一个数字或是一个字符串。
  4. 在“item_func.cc”，增加下列声明之一，取决于你是正在定义一个数字或是字符串函数：
    double   Item_func_newname::val()
longlong Item_func_newname::val_int()
String  *Item_func_newname::Str(String *str)
  5. 你也可能应该定义下列函数：
    void Item_func_newname::fix_length_and_dec()

    这个函数至少应该基于给定的参数计算max_length，max_length是函数可以返回的字符的最大数目。如果主函数不能返回一个NULL值，这个函数也应该设置maybe_null = 0。函数可以通过检查参数的maybe_null变量以便检查函数参数的任何一个是否能返回NULL。

所有函数必须是线程安全的（thread-safed）。

对字符串函数，已知有一些额外的考虑：

  • String *str参数提供一个可以用来保存结果的字符串缓冲区。
  • 函数应该返回保存结果的字符串。
  • 所有的当前字符串函数试图避免分配任何内存，除非绝对必要！

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-15 为MySQL增加新过程

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

15 为MySQL增加新过程

在MySQL中，你可以定义一个用C++写地过程，它能在查询被送到客户前存取和修改查询中的数据。修改可一行一行地或在GROUP BY层次上进行。

我们已经在MySQL3.23中创建了一个过程例子来显示它能做什么。

15.1 analyse过程

analyse([max elements,[max memory]])

这个过程定义在“sql/sql_analyse.cc”，它检验来自你的查询的结果并返回结果的分析。

  • max elements（缺省256)是analyse将注意的每列不同值的最大数量。这被analyse用来检查最佳的列类型是否应该是ENUM类型。
  • max memory（缺省8192)是在analyse尝试寻找所有不同值的时候应该分配给每列的最大内存量。
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])

15.2 编写一个过程

暂时，对此的唯一文档是源代码。:(

你可以检验下列文件找到关于过程的所有信息：

  • “sql/sql_analyse.cc”
  • “sql/procedure.h”
  • “sql/procedure.cc”
  • “sql/sql_select.cc”

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-16 MySQL的ODBC支持

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

16 MySQL对ODBC的支持

MySQL利用MyODBC程序为ODBC提供支持。

16.1 MyODBC支持的操作系统

MyODBC是在Windows95和Windows NT上的一个32位ODBC(2.50) level 0驱动程序。我们希望谁能将它移植到Windows 3.x。

16.2 怎样报告MyODBC的问题

MyODBC已经用Acess、Admndemo.exe、C++ Builder、Centura Team Developer(早先是Gupta SQL/Windows)、ColdFusion(在Solaris和用Server Pack 5的NT上)、Crystal Reports、DataJunction、Notes 4.5/4.6、SBSS、Perl DBD-ODBC、Paradox、Powerbuilder、Powerdesigner 32位、VC++和Visual Basic。

如果你听说有任何其他的应用程序用MyODBC一起工作，请把它寄到myodbc@lists.mysql.com！

16.3 已知可用MyODBC工作的程序

大多数程序应该可用MyODBC工作，但对下面列出的每一个，我们自己测试了它或从它运行的一些用户得到了证实：

程序
说明
Access
为使Access工作：
  • 你应该在桌中有主键。
  • 你应该在所有你想要能被修改的表中有一个时间戳记。
  • 仅使用双精度浮点数的字段。当用单精度浮点数进行比较时，Access失败。
  • 当与MySQL连接时，设置“Return matching rows”（返回匹配的行）选项域。
  • 在NT上的Access将报告BLOB列为OLE OBJECTS。如果你想要有MEMO列，你应该用ALTER TABLE把列改成TEXT。
  • Access不能总是正确地处理DATE列。如果你对此有一个问题，把列改为DATETIME。
  • 在一些情况下，Access可以产生不合法的SQL查询，而MySQL不能理解。你可以通过从Access菜单"Query|SQLSpecific|Pass-Through"来修正它。
DataJunction
你必须改变它来输出VARCHAR而非ENUM，因为它以能引起MySQL困惑的方式导出后者。
Execl
工作。一些建议：
  • 如果你对日期有问题，试着使用CONCAT()函数作为字符串选择他们。例如：
    select CONCAT(rise_time), CONCAT(set_time)
    from sunrise_sunset;

    这种方式作为字符串检索出的值应该被Excel97识别为时间值，例子中CONCAT()的目的是欺骗ODBC认为列是“字符串类型”。没有CONCAT()，ODBC知道列是时间类型，而Excel不理解它。注意这是Excel的一个错误，因为它自动将一个字符串转换为一个时间。如果数据源是一个文本文件，这问题将很大，但是当数据源是对每列报告准确类型的一个ODBC连接时，只是有点傻。

odbcadmin
为ODBC的测试程序。
Delphi
你必须使用DBE 3.2或更新。当与MySQL连接时，设置“Don't optimize column width”（不优化列宽度）选项域。另外，有一些潜在有用的delphi代码安装一个ODBC入口和针对MyODBC的一个BDE的入口(BDE入口需要一个BDE Alias Editor，可以到Delphi Super Page上免费拥有)：（感谢Bryan Brunton bryan@flesherfab.com）
fReg:= TRegistry.Create;
  fReg.OpenKey('\Software\ODBC\ODBC.INI\DocumentsFab', True);
  fReg.WriteString('Database', 'Documents');
  fReg.WriteString('Description', ' ');
  fReg.WriteString('Driver', 'C:\WINNT\System32\myodbc.dll');
  fReg.WriteString('Flag', '1');
  fReg.WriteString('Password', '');
  fReg.WriteString('Port', ' ');
  fReg.WriteString('Server', 'xmark');
  fReg.WriteString('User', 'winuser');
  fReg.OpenKey('\Software\ODBC\ODBC.INI\ODBC Data Sources', True);
  fReg.WriteString('DocumentsFab', 'MySQL');
  fReg.CloseKey;
  fReg.Free;

  Memo1.Lines.Add('DATABASE NAME=');
  Memo1.Lines.Add('USER NAME=');
  Memo1.Lines.Add('ODBC DSN=DocumentsFab');
  Memo1.Lines.Add('OPEN MODE=READ/WRITE');
  Memo1.Lines.Add('BATCH COUNT=200');
  Memo1.Lines.Add('LANGDRIVER=');
  Memo1.Lines.Add('MAX ROWS=-1');
  Memo1.Lines.Add('SCHEMA CACHE DIR=');
  Memo1.Lines.Add('SCHEMA CACHE SIZE=8');
  Memo1.Lines.Add('SCHEMA CACHE TIME=-1');
  Memo1.Lines.Add('SQLPASSTHRU MODE=SHARED AUTOCOMMIT');
  Memo1.Lines.Add('SQLQRYMODE=');
  Memo1.Lines.Add('ENABLE SCHEMA CACHE=FALSE');
  Memo1.Lines.Add('ENABLE BCD=FALSE');
  Memo1.Lines.Add('ROWSET SIZE=20');
  Memo1.Lines.Add('BLOBS TO CACHE=64');
  Memo1.Lines.Add('BLOB SIZE=32');

  AliasEditor.Add('DocumentsFab','MySQL',Memo1.Lines);
C++Builder
用BDE 3.0测试过。唯一知道的问题是，当表框架改变时，差询字段不被更新。然而BDE似乎认不出主键，只是索引PRIMARY，尽管这已经不是个问题。
Visual Basic
为了能更新一张表，你必须为表定义一个主键。

16.4 怎样填写ODBC管理程序的各种域

在Windows95上，有3种可能性来指定服务器名：

  • 使用服务器的IP地址。
  • 增加一个文件“lmhosts”，具有下列信息：
    ip hostname

    例如：

    194.216.84.21 my
  • 设置PC以使用DNS。

怎么填写“ODBC设置”的例子：

Windows DSN name:   test
Description:        This is my test database
MySql Database:     test
Server:             194.216.84.21
User:               monty
Password:           my_password
Port:

对Windows DSN name域的值是在你的Windows ODBC设置中唯一的任何名字。

你不必为在ODBC设置屏的Server, User, Password或Port域指定值。然而如果你这样做，当你试图做一个连接时，这些值将在以后作为缺省值使用，那时你有改变值的选择。

如果没给出端口号，使用缺省端口(3306)。

如果你指定选项Read options from C:\my.cnf，组client和odbc将从“C:\my.cnf”文件中读出。你可以使用可用于mysql_options()的所有选项。见20.4.37 mysql_options()。

16.5 怎样在ODBC中获得一个AUTO_INCREMENT列的值

一个常见的问题是怎样得到一个自动从一个INSERT产生的ID值，用ODBC，你可以这样做(假定auto是一个AUTO_INCREMENT字段)：

INSERT INTO foo (auto,text) VALUES(NULL,'text');
SELECT LAST_INSERT_ID();

或，如果你是只是想把ID插入到另外一个表中，你可以这样做：

INSERT INTO foo (auto,text) VALUES(NULL,'text');
INSERT INTO foo2 (id,text) VALUES(LAST_INSERT_ID(),'text');

得益于一些ODBC应用程序(至少Delphi和Access)，下列查询可被用来找出最新插入的行：

SELECT * FROM tbl_name WHERE auto IS NULL;

16.6 报告MyODBC的问题

如果你碰到MyODBC困难，你应该通过ODBC管理器制作一个日志文件(当从ODBCADMIN要求日志时，你获得的日志文件)和一个MyODBC日志文件来开始。为了获得一个MyODBC日志文件，在MyODBC连接/配置屏幕上标注“Trace MyODBC”选项标志。日志文件将被写入文件“C:\myodbc.log”。注意为了此选项起作用，你必须使用MYSQL.DLL而不是MYSQL2.DLL！

检查MyODBC发给MySQL服务器的查询；你应该可以通过在“myodbc.log”文件中寻找字符串>mysql_real_query找到它。

你也应该试着在mysql监视器或admndemo中重复查询以找出是MyODBC出错还是MySQL出错。

如果你发现某些东西是错的，请值将相关的行(最大40排)发到myodbc@lists.mysql.com。请决不要发送整个MyODBC或ODBC日志文件！

如果你不能找出是什么错误，最后的选择制作一个档案(tar或zip)，包含一个MyODBC日志文件，ODBC日志文件和一个解释这个问题的 README文件。你可以把这发到ftp://www.mysql.com/pub/mysql/secret。至于在TCX的我们能访问你上载的文件并且我们将分离数据！

如果你能创造一个也显示出这个问题的程序，请也上载它！

如果程序与一些其他SQL服务器一起工作，你应该制作一个 ODBC 日志文件，在哪儿你在其他SQL服务器做完全一样的事情。

记住，你能提供我们越多的信息，我们越可能解决这个问题！

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-17 与一些常用程序一起使用MySQL

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

17 与一些常用程序一起使用MySQL

17.1 与Apache一起使用MySQL

贡献者小节包括让你从MySQL数据库验证你的用户并且也让你将你的日志文件记载到一个MySQL表中的程序。见B 贡献的程序。

你可以改变 Apache日志格式以使它很容易被MySQL读取，把下列行放进Apache配置文件中：

LogFormat \
        "\"%h\",%{%Y%m%d%H%M%S}t,%>s,\"%b\",\"%{Content-Type}o\",  \
        \"%U\",\"%{Referer}i\",\"%{User-Agent}i\""

在MySQL中，现在你可以这样做：

LOAD DATA INFILE '/local/access_log' INTO TABLE table_name
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-18 问题和常见错误

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

18 问题和常见错误

18.1 如果MySQL总是崩溃怎么办

所有MySQL在发布它们之前，在许多平台上被测试。这并不意味着在MySQL中没有任何错误，但是如果有错误，它们是很少的并且很能难发现。如果你有一个问题并且如果你尝试找出究竟是什么摧毁了你的系统，它将总是有帮助的，因为你将有一个更好机会使得它被快速修复。

首先你应该试着找出问题mysqld守护进程是否死掉或你的问题是否与你的客户有关。你可以用mysqladmin version检查你的mysqld服务器正常执行了多长时间，如果mysqld死了，你可以在文件“mysql-data-directory/'hostname'.err”中找到其原因。

因为很难知道一些东西为什么崩溃，首先试着检查为其它人工作的东西是否使你崩溃。请尝试下列事情：

  • 与mysqladmin shutdown停止mysqld守护进程，在所有表上运行myisamchk --silent --force */*.MYI并重启mysqld守护经进程。这将保证你从一个干净的状态运行。见13 维护MySQL安装。
  • 使用mysqld --log并且试着从日志信息确定是否是某个特定的查询杀死了服务器。全部错误的95%与特定的查询有关！通常它是在日志文件中就在MySQL重启之前的最后查询之一。你也许可以使用下列过程验证它：
    • 停止MySQL守护进程(用mysqladmin shutdown)。
    • 在MySQL数据库目录下做文件的一个备份。
    • 与myisamchk -s */*.MYI检查表以验证所有表是正确的。如果有任何表被损坏，用myisamchk -r path-to-table.MYI修复它。
    • 从MySQL数据目录删除(或移走)任何旧的日志文件。
    • 用safe_mysql --log启动服务器。
    • 如果mysqld现在死掉，你可以通过恢复备份并执行mysql < mysql-log-file来测试问题是否是一个特定的查询引起的。当然你可以通过用safe_mysqld --data=path-to-backup-directory启动另一个MySQL服务器，在某个其他目录而不是标准MySQL数据库目录下做后面的测试。
  • 你试用了基准测试吗？他们应该很好地测试MySQL。你也可以增加代码模拟你的应用程序！基准程序可在源代码分发的“bench”目录下找到，或对二进制分发，在你的MySQL安装目录下“sql-bench”目录。
  • 试一下fork_test.pl和fork2_test.pl。
  • 对任何错误检查文件“mysql-data-directory/'hostname'.err”。
  • 如果你配置MySQL以便调试，如果出错，收集可能的错误信息将更容易。使用--with-debug选项的configure重新配置MySQL然后重新编译。见G.1 调试一个 MySQL 服务器。
  • 为调试而配置MySQL使它包含一个安全的内存分配器以便能发现一些错误。它也提供关于正在发生什么的大量输出。
  • 你为你的操作系统使用了最新的补丁吗？
  • 使用mysql的--skip-locking选项.在一些系统上，lockd锁管理器不能正确工作；--skip-locking选项告诉mysqld不使用外部锁。（这意味着你不能在同一个数据上运行两个mysqld服务器而且如果你使用myisamchk，你一定要小心，但是它对为了测试试用选项可能有益。）
  • 当mysqld好象正在运行但没有反应时，你尝试过mysqladmin -u root processlist吗？有时mysqld不是毫无反应，尽管你可能这样认为。问题可能是所有在用的连接，或可能用内部锁定问题。mysqladmin processlist甚至在这些情况下将通常可以进行一个连接，并且能提供有关当前连接数量及其状态的有用信息。
  • 在你运行其他查询时，在一个单独窗口中运行命令mysqladmin -i 5 status，产生统计。
  • 尝试下列步骤：
    1. 通过gdb（或其他调试器)启动mysqld。
    2. 运行你的测试脚本。
    3. 当mysqld核心倾倒(core dump)，做back（或你调试器中的回溯-backtrace命令)。
  • 尝试用一个Perl脚本模拟你的应用程序以强制MySQL崩溃或表现不正确。
  • 或发一份正式的错误报告。见2.3 如何报告错误或问题，但是要不平常更详细。因为MySQL为很多人的工作，导致崩溃的东西可能只存在于你的计算机上(例如，与你的特定系统库有关的一个错误)。
  • 如果你的问题有具有动态长度行的表有关，并且你不使用BLOB/TEXT列(但是仅VARCHAR列)，你可以用ALTER TABLE试着将全部VARCHAR改为CHAR，这将强制MySQL使用固定尺寸的行。固定尺寸的行占据很小的额外空间，但是更能容忍崩溃！当前动态行的代码在 TCX 至少使用3 年的时间，没有任何问题，但是从本质上讲，动态长度的行对错误更敏感，因此如果上述对你有帮助，尝试一下可能是一个好主意！

18.2 使用MySQL时的一些常见错误

18.2.1 MySQL server has gone away错误

本小节也涉及有关Lost connection to server during query的错误。

对MySQL server has gone away错误最常见的原因是服务器超时了并且关闭了连接。缺省地，如果没有事情发生，服务器在 8个小时后关闭连接。你可在启动mysqld时通过设置wait_timeout变量改变时间限制。

你可以通过执行mysqladmin version并且检验正常运行的时间来检查MySQL还没死掉。

如果你有一个脚本，你只须再发出查询让客护进行一次自动的重新连接。

在这种请下，你通常能获得下列错误代码(你得到的是OS相关的)：

CR_SERVER_GONE_ERROR | 客户不能发送一个问题给服务器。
CR_SERVER_LOST | 当写服务器时，客户没有出错，但是它没有得到对问题的一个完整的答案(或任何答案)。

如果你向服务器发送不正确的或太大的查询，你也可能得到这些错误。如果mysqld得到一个太大或不正常的包，它认为客户出错了并关闭连接。如果你需要较大的查询(例如，如果你正在处理较大的BLOB列)，你可以使用-O max_allowed_packet=#选项(缺省1M)启动mysqld以增加查询限制。多余的内存按需分配，这样mysqld只有在你发出较大差询时或mysqld必须返回较大的结果行时，才使用更多的内存！

18.2.2 Can't connect to [local] MySQL server错误

一个MySQL客户可以两种不同的方式连接mysqld服务器：Unix套接字，它通过在文件系统中的一个文件(缺省“/tmp/mysqld.sock”)进行连接；或TCP/IP，它通过一个端口号连接。Unix套接字比TCP/IP更快，但是只有用在连接同一台计算机上的服务器。如果你不指定主机名或如果你指定特殊的主机名localhost，使用Unix套接字。

错误(2002）Can't connect to ...通常意味着没有一个MySQL服务器运行在系统上或当试图连接mysqld服务器时，你正在使用一个错误的套接字文件或TCP/IP端口。

由检查(使用ps)在你的服务器上有一个名为mysqld的进程启动！如果没有任何mysqld过程，你应该启动一个。见4.15.2 启动MySQL服务器的问题。

如果一个mysqld过程正在运行，你可以通过尝试这些不同的连接来检查服务器(当然，端口号和套接字路径名可能在你的安装中是不同的)：

shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h 'ip for your host' version
shell> mysqladmin --socket=/tmp/mysql.sock version

注意hostname命令使用反引号“`”而非正引号“'”；这些导致hostname输出（即，当前主机名)被代替进mysqladmin命令中。

这是可能造成Can't connect to local MySQL server错误的一些原因：

  • mysqld不在运行。
  • 你正在使用MIT-pthreads的一个系统上运行。如果正在运行在一个没有原生线程的系统上，mysqld使用 MIT-pthreads 软件包。见4.2 由MySQL支持的操作系统。然而，MIT-pthreads不支持Unix套接字，因此当与服务器连接时，在这样一个系统上，你总是必须明确地指定主机名。试试使用这个命令检查到服务器的连接：
    shell> mysqladmin -h `hostname` version
  • 某人删除了mysqld使用的Unix套接字(缺省“/tmp/mysqld.sock”)。你可能有一个cron任务删除了MySQL套接字(例如，一个把旧文件从“/tmp”目录中删除的任务)。你总是可以运行mysqladmin version并且检查mysqladmin正在试图使用的套接字确实存在。在这种情况下，修复方法是删除cron任务而不删除“mysqld.sock 或将套接字放在其他地方。你能用这个命令在MySQL配置时指定一个不同的套接字地点：
    shell> ./configure --with-unix-socket-path=/path/to/socket

    你也可以使用--socket=/path/to/socket选项启动safe_mysqld和在启动你的MySQL客户前设置环境变量MYSQL_UNIX_PORT为套接字路径名。你可用--socket=/path/to/socket选项启动mysqld服务器。如果你改变了服务器的套接字路径名，你也必须通知MySQL客户关于新路径的情况。你可以通过设置环境变量MYSQL_UNIX_PORT为套接字路径名或由提供套接字路径名作为客户的参数做到。你可用这个命令测试套接字：

    shell> mysqladmin --socket=/path/to/socket version
  • 你正在使用 Linux和线程已经死了(核心倾倒了)。在这种情况中，你必须杀死其它mysqld线程(例如在启动一个新的MySQL服务器之前，可以用mysql_zap脚本）。见18.1 如果MySQL总是崩溃怎么办。

如果你得到错误Can't connect to MySQL server on some_hostname，你可以尝试下列步骤找出问题是什么：

  • 通过执行telnet your-host-name tcp-ip-port-number并且按几次回车来检查服务器是否正常运行。如果有一个MySQL运行在这个端口上，你应该得到一个包含正在运行的MySQL服务器的版本号的应答。如果你得到类似于telnet: Unable to connect to remote host: Connection refused的一个错误，那么没有服务器在使用的端口上运行。
  • 尝试连接本地机器上的mysqld守护进程，并用mysqladmin variables检查mysqld被配置使用的TCP/IP端口(变量port)。
  • 检查你的mysqld服务器没有用--skip-networking选项启动。

18.2.3 Host '...' is blocked错误

如果你得到象这样的一个错误：

Host 'hostname' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'

这意味着，mysqld已经得到了大量(max_connect_errors)的主机'hostname'的在中途被中断了的连接请求。在max_connect_errors次失败请求后，mysqld认定出错了(象来字一个黑客的攻击)，并且阻止该站点进一步的连接，直到某人执行命令mysqladmin flush-hosts。

缺省地，mysqld在10个连接错误后阻塞一台主机。你可以通过象这样启动服务器很容易地调整它：

shell> safe_mysqld -O max_connect_errors=10000 &

注意，对给定的主机，如果得到这条错误消息，你应该首先检查该主机的TCP/IP连接有没有问题。如果你的TCP/IP连接不在运行，增加max_connect_errors变量的值对你也不会有帮助！

18.2.4 Too many connections错误

如果在你试土连接MySQL时，你得到错误Too many connections，这意味着已经有max_connections个客户连接了mysqld服务器。

如果你需要比缺省(100)更多的连接，那么你应该重启mysqld，用更大的 max_connections 变量值。

注意，mysqld实际上允许(max_connections+1)个客户连接。最后一个连接是为一个用Process权限的用户保留的。通过不把这个权限给一般用户(他们不应该需要它)，有这个权限一个管理员可以登录并且使用SHOW PROCESSLIST找出什么可能出错。见7.21 SHOW句法(得到表，列的信息）。

18.2.5 Out of memory错误

如果你发出查询并且得到类似于下面的错误：

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory

注意，错误指向了MySQL客户mysql。这个错误的原因很简单，客户没有足够的内存存储全部结果。

为了修正这个问题，首先检查你的查询是否正确。它应该返回这么多的行，这合理吗？如果是这样，你可以使用mysql --quick，它使用mysql_use_result()检索结果集合。这将较少的负担放在了客户端(只是服务器更多)。

18.2.6 Packet too large错误

当一个MySQL客户或mysqld服务器得到一个比max_allowed_packet个字节长的包，它发出一个Packet too large错误并终止连接。

如果你正在使用mysql客户，你可以通过用mysql --set-variable=max_allowed_packet=8M指定一个更大的缓冲区来启动客户程序。

如果你正在使用不允许你指定最大包大小的其他客户(例如 DBI)，你需要在你启动服务器时设置包大小。你可以使用mysqld的命令行选项设置max_allowed_packet为一个更大的尺寸。例如，如果你正期望将一个全长的BLOB存入一张表中，你将需要用--set-variable=max_allowed_packet=24M选项来启动服务器。

18.2.7 The table is full错误

这个错误发生在内存临时表变得比tmp_table_size字节大时。为了避免这个问题，你可以使用mysqld的-O tmp_table_size=#选项来增加临时表的大小，或在你发出有疑问的查询之前使用SQL选项SQL_BIG_TABLES。见7.25 SET OPTION句法。

你也可以使用--big-tables选项启动mysqld。这与为所有查询使用SQL_BIG_TABLES完全相同。

18.2.8 Commands out of sync in client错误

如果你在你的客户代码中得到Commands out of sync; You can't run this command now，你正在以错误的次序调用客户函数！

这可能发生，例如，如果你正在使用mysql_use_result()并且在你已经调用了mysql_free_result()之前试图执行新查询。如果你在mysql_use_result()或mysql_store_result()之间试图执行返回数据的2个查询，它也可能发生。

18.2.9 Ignoring user错误

如果你得到下列错误：

Found wrong password for user: 'some_user@some_host'; Ignoring user

这意味着在mysqld启动时或在它再次装载权限表时，它在user表中找到了一个有一个无效口令的条目。结果，条目简单地被权限系统忽略。

可能导致这个问题的原因和修正：

  • 你可能正在运行一个有一个老的user表的新版本mysqld。你可以通过执行mysqlshow mysql user看看口令字段是否少于 16个字符来检查它。如果是这样，你可以通过运行scripts/add_long_password脚本改正这种情况。
  • 用户有一个老式的口令(8个字符长)并且你没使用--old-protocol选项启动mysqld。用一个新口令更新在user表中的用户或用--old-protocol重启mysqld。
  • 你没有使用PASSWORD()函数在在user表中指定了一个口令。使用mysql以一个新口令更新在user表中的用户。确保使用PASSWORD()函数：
    mysql> update user set password=PASSWORD('your password')
           where user='XXX';

18.2.10 Table 'xxx' doesn't exist错误

如果你得到错误Table 'xxx' doesn't exist或Can't find file: 'xxx' (errno: 2)，这意味着在当前数据库中没有名为xxx的表存在。

注意，因为MySQL使用目录和文件存储数据库和表，数据库和表名件是区分大小写的！（在Win32上，数据库和表名不是区分大小写的，但是在查询中对所有表的引用必须使用相同的大小写！）

你可以用SHOW TABLES检查你在当前数据库中有哪个表。见7.21 SHOW句法(得到表、列的信息）。

18.3 MySQL怎样处理一个溢出的磁盘

当出现一个磁盘溢出的情况时，MySQL做下列事情：

  • 它每分钟检查一次看是否有足够空间写入当前行。如果有足够的空间，它继续好像发生什么事情。
  • 每6分钟它将有关磁盘溢出的警告写入日志文件。

为了缓和这个问题，你可以采取下列行动：

  • 继续，你只需释放足够的空闲磁盘空间以便插入所有记录。
  • 放弃线程，你必须发一个mysqladmin kill到线程。在下一次检查磁盘时，线程将被放弃(在1分钟内)。
  • 注意，其他线程可能正在等待引起“磁盘溢出”条件的表。如果你有几个“锁定的”的线程，杀死正在等待磁盘溢出条件的那个线程将允许其他线程继续。

18.4 如何从一个文本文件运行SQL命令

一般地，mysql客户被交互性地使用，象这样：

shell> mysql database

然而，也可以把你的SQL命令放在一个文件中并且告诉mysql从该文件读取其输入。要想这样做，创造一个文本文件“text_file”，它包含你想要执行的命令。然后如下那样调用mysql：

shell> mysql database < text_file

你也能启动有一个USE db_name语句的文本文件。在这种情况下，在命令行上指定数据库名是不必要的：

shell> mysql < text_file

见12.1 不同的MySQL程序概述。

18.5 MySQL在哪儿存储临时文件

MySQL使用TMPDIR环境变量的值作为存储临时文件的目录的路径名。如果你没有设置TMPDIR，MySQL使用系统缺省值，它通常是“/tmp”或“/usr/tmp”。如果包含你的临时文件目录的文件系统太小，你应该编辑safe_mysqld设定TMPDIR指向你有足够空间的一个文件系统！你也可以使用mysqld的--tmpdir选项目设置临时目录。

MySQL以“隐含文件”创建所有临时文件。这保证了如果mysqld被终止，临时文件也将被删除。使用隐含文件的缺点是你将看不到一个大的临时文件填满了临时文件目录所在的文件系统。

当排序(ORDER BY或GROUP BY)时，MySQL通常使用一个或两个临时文件。最大磁盘空间需求是：

(存储东西的长度 + sizeof (数据库指针))
* 匹配的行数
* 2

sizeof(数据库指针)通常是4，但是在未来对确实很大的表可能增加。

对一些SELECT查询，MySQL也创建临时SQL表。这些没被隐含且有“SQL_*”格式的名字。

ALTER TABLE和OPTIMIZE TABLE在原数据库表的同一个目录中创建一张临时表。

18.6 怎样保护“/tmp/mysql.sock ”不被删除

如果你有这个问题，事实上任何人可以删除MySQL通讯套接字“/tmp/mysql.sock”，在Unix的大多数版本上，你能通过为其设置sticky（t）位来保护你的“/tmp”文件系统。作为root登录并且做下列事情：

shell> chmod +t /tmp

这将保护你的“/tmp”文件系统使得文件仅能由他们的所有者或超级用户(root)删除。

你能执行ls -ld /tmp检查sticky位是否被设置，如果最后一位许可位是t，该位被设置了。

18.7 Access denied错误

见6.6 权限系统如何工作。并且特别要看6.13 引起Access denied错误的原因。

18.8 怎样作为一个一般用户运行MySQL

MySQL服务器mysqld能被任何用户启动并运行。为了将mysqld改由Unix用户user_name来运行，你必须做下列事情：

  1. 如果它正在运行，停止服务器(使用mysqladmin shutdown)。
  2. 改变数据库目录和文件以便user_name有权限读和写文件(你可能需要作为Unix的root用户才能做到)：
    shell> chown -R user_name /path/to/mysql/datadir

    如果在MySQL数据目录中的目录或文件是符号链接，你也将需要顺着那些链接并改变他们指向的目录和文件。chown -R不能跟随符号链接。

  3. 以user_name用户启动服务器，或如果你正在使用MySQL 3.22或以后版本，以Unix root用户启动mysqld并使用--user=user_name选项，mysqld将在接受任何连接之前切换到以Unix user_name用户运行。
  4. 如果在系统被重新启动时，你使用mysql.server脚本启动mysqld，你应该编辑mysql.server用su以用户user_name运行mysqld，或使用--user选项调用mysqld。（不改变safe_mysqld是必要的。）

现在，你的mysqld进程应该正在作为Unix用户user_name运行，并运行完好。尽管有一件事情没有变化：权限表的内容。缺省 地(就在运行了脚本mysql_install_db安装的权限表后)，MySQL用户root是唯一有存取mysql数据库或创建或抛弃数据库权限的用户。除非你改变了那些权限，否则他们仍然保持。当你作为一个Unix用户而不是root登录时，这不应该阻止你作为MySQL root用户来存取MySQL；只要为客户程序指定-u root的选项。

注意通过在命令行上提供-u root，作为root存取MySQL，与作为Unix root用户或其他Unix用户运行MySQL 没有关系。MySQL的存取权限和用户名与Unix用户名字是完全分开的。唯一与Unix用户名有关的是，如果当你调用一个客户程序时，你不提供一个-u选项，客户将试图使用你的Unix登录名作为你的MySQL用户名进行连接。

如果你的Unix机器本身不安全，你可能应该至少在存取表中为MySQL root用户放上一个口令。否则，在那台机器上有一个帐号的任何用户能运行mysql -u root db_name并且做他喜欢做的任何事情。

18.9 怎样重新设置一个忘记的口令

如果你忘记了MySQL的root用户的口令，你可以用下列过程恢复它。

  1. 通过发送一个kill（不是kill -9)到mysqld服务器来关闭mysqld服务器。pid 被保存在一个.pid文件中，通常在MySQL数据库目录中：
    kill `cat /mysql-data-directory/hostname.pid`

    你必须是一个UNIX root用户或运行服务器的相同用户做这个。

  2. 使用--skip-grant-tables选项重启mysqld。
  3. 用mysql -h hostname mysql连接mysqld服务器并且用一条GRANT命令改变口令。见7.26 GRANT和REVOKE句法。你也可以用mysqladmin -h hostname -u user password 'new password' 进行。
  4. 用mysqladmin -h hostname flush-privileges或用SQL命令FLUSH PRIVILEGES来装载权限表。

18.10 文件许可权限问题

如果你有与文件许可有关的问题，例如，如果当你创建一张表时，mysql发出下列错误消息：

ERROR: Can't find file: 'path/with/filename.frm' (Errcode: 13)

那么可能是在mysqld启动时，环境变量UMASK可能设置不正确。缺省的umask值是0660。你可以如下启动safe_mysqld改变其行为：

shell> UMASK=384  # = 600 in octal
shell> export UMASK
shell> /path/to/safe_mysqld &

18.11 文件没找到

如果你从MySQL得到ERROR '...' not found (errno: 23), Can't open file: ... (errno: 24)或任何其他有errno 23或errno 24的错误，它意味着，你没有为MySQL分配足够的文件描述符。你能使用perror实用程序得到错误号含义是什么的描述：

shell> perror 23
File table overflow
shell> perror 24
Too many open files

这里的问题是mysqld正在试图同时保持打开太多的文件。你也可以告诉mysqld一次不打开那么多的文件，或增加mysqld可得到的文件描述符数量。

为了告诉mysqld一次保持打开更少的文件，你可以通过使用safe_mysqld的-O table_cache=32选项（缺省值是64)使表缓冲更小。减小max_connections值也将减少打开文件的数量(缺省值是90)。

要想改变mysqld可用的文件描述符数量，修改safe_mysqld脚本。脚本中有一条注释了的行ulimit -n 256。你可以删除'#'字符来去掉该行的注释，并且改变数字256改变为mysqld可用的文件描述符的数量。

ulimit能增加文件描述符的数量，但是只能到操作系统强加的限制。如果你需要增加每个进程可用的文件描述符数量的OS限制，参见你的操作系统文档。

注意，如果你运行tcsh外壳，ulimit将不工作！当你请求当前限制时，tcsh也将报告不正确的值！在这种情况下，你应该用sh启动safe_mysqld！

18.12 使用DATE列的问题

一个DATE值的格式是'YYYY-MM-DD'。根据ANSI SQL，不允许其他格式。你应该在UPDATE表达式和SELECT语句的WHERE子句中使用这个格式。例如：

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

为了方便，如果日期用在数字上下文，MySQL自动变换一个日期到一个数字(并且反过来也如此)。当更新时和将一个日期与TIMESTAMP、DATE或DATETIME列比较的一个WHERE子句中，也是足够灵活以允许一种“宽松”的字符串格式。（宽松格式意味着任何标点字符用作在部件之间的分割符。例如，'1998-08-15'和'1998#08#15'是等价的。）MySQL也能变换不包含分割符的一个字符串(例如 '19980815')，如果它作为一个日期说得通。

特殊日期'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,'19970505')=0;

STRCMP()是字符串函数，因此它将idate转换为一个字符串并且实施字符串比较。它不将'19970505'转换为一个日期并实施日期比较。

注意，MySQL不检查日期是否正确。如果你存储一个不正确的日期，例如'1998-2-31'，错误的日期将被存储。如果日期不能被变换到任何合理的值，在DATE字段中存储一个0。这主要是一个速度问题并且我们认为检查日期是应用程序的责任，而不服务器。

18.13 时区问题

如果你有一个问题，SELECT NOW()以GMT时间返回值而不是你的本地时间，你必须设定TZ环境变量为你的当前时区。这应该在服务器运行的环境进行，例如在safe_mysqld或mysql.server中。

18.14 在搜索中的大小写敏感性

缺省地，MySQL搜索是大小写不敏感的(尽管有一些字符集从来不是忽略大小写的，例如捷克语)。这意味着，如果你用col_name LIKE 'a%'搜寻，你将得到所有以A或a开始的列值。如果你想要使这个搜索大小写敏感，使用象INDEX(col_name, "A")=0检查一个前缀。或如果列值必须确切是"A"，使用STRCMP(col_name, "A") = 0。

简单的比较操作(>=、>、= 、< 、<=、排序和聚合)是基于每个字符的“排序值”。有同样排序值的字符(象E，e和'e)被视为相同的字符！

LIKE比较在每个字符的大写值上进行(E==e 但是E<>'e）。

如果你想要一个列总是被当作大小写敏感的方式，声明它为BINARY。见7.7 CREATE TABLE句法。

如果你使用以所谓的big5编码的中文数据，你要使所有的字符列是BINARY，它可行，是因为big5编码字符的排序顺序基于 ASCII代码的顺序。

18.15 NULL值问题

NULL值的概念是造成SQL的新手的混淆的普遍原因，他们经常认为NULL是和一个空字符串''的一样的东西。不是这样的！例如，下列语句是完全不同的：

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

两个语句把值插入到phone列，但是第一个插入一个NULL值而第二个插入一个空字符串。第一个的含义可以认为是“电话号码不知道”，而第二个则可意味着“她没有电话”。

在SQL中，NULL值在于任何其他值甚至NULL值比较时总是假的（FALSE）。包含NULL的一个表达式总是产生一个NULL值，除非在包含在表达式中的运算符和函数的文档中指出。在下列例子，所有的列返回NULL：

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

如果你想要寻找值是NULL的列，你不能使用=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 = "";

在MySQL中，就像很多其他的SQL服务器一样，你不能索引可以有NULL值的列。你必须声明这样的列为NOT NULL，而且，你不能插入NULL到索引的列中。

当用LOAD DATA INFILE读取数据时，空列用''更新。如果你想要在一个列中有NULL值，你应该在文本文件中使用\N。字面上的词'NULL'也可以在某些情形下使用。见7.16 LOAD DATA INFILE句法。

当使用ORDER BY时，首先呈现NULL值。如果你用DESC以降序排序，NULL值最后显示。当使用GROUP BY时，所有的NULL值被认为是相等的。

为了有助于NULL的处理，你能使用IS NULL和IS NOT NULL运算符和IFNULL()函数。

对某些列类型，NULL值被特殊地处理。如果你将NULL插入表的第一个TIMESTAMP列，则插入当前的日期和时间。如果你将NULL插入一个AUTO_INCREMENT列，则插入顺序中的下一个数字。

18.16 alias问题

你可以在GROUP BY、ORDER BY或在HAVING部分中使用别名引用列。别名也可以用来为列取一个更好点的名字：

SELECT SQRT(a*b) as rt FROM table_name GROUP BY rt HAVING rt > 0;
SELECT id,COUNT(*) AS cnt FROM table_name GROUP BY id HAVING cnt > 0;
SELECT id AS "Customer identity" FROM table_name;

注意，你的 ANSI SQL 不允许你在一个WHERE子句中引用一个别名。这是因为在WHERE代码被执行时，列值还可能没有终结。例如下列查询是不合法：

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

WHERE语句被执行以确定哪些行应该包括GROUP BY部分中，而HAVING用来决定应该只用结果集合中的哪些行。

18.17 从关联的表中删除行

因为MySQL不支持子选择或在DELETE语句中使用多个表，你应该使用下列方法从2个关联的表中删除行：

  1. 在主表中基于某个WHERE条件SELECT行。
  2. 在主表中基于相同的条件DELETE行。
  3. DELETE FROM related_table WHERE related_column IN (selected_rows)

如果在related_column查询中的字符的全部数量超过1,048,576(缺省值max_allowed_packet），你应该分成更小的部分并且执行多个DELETE语句。如果related_column是一个索引，你每次只删除100-1000个related_column id将可能使得DELETE最快。如果related_column不是一个索引，速度与IN子句中参数的数量无关。

18.18 解决没有匹配行的问题

如果你有一个复杂的查询，涉及多个表，但没有返回任何行，你应该使用下列过程查找你的询问有什么不对：

  1. EXPLAIN测试查询并且检查你是否能找出显然是错误的一些东西。见7.22 EXPLAIN句法(得到关于一个SELECT的信息)。
  2. 仅选择那些在WHERE子句中使用的字段。
  3. 一次从查询中删除一个表，直到它返回一些行。如果表很大，对查询使用LIMIT 10是一个好主意。
  4. 对应该已经匹配一行的列做一个SELECT，针对从询问中做后被删除的表。
  5. 如果你将FLOAT或DOUBLE列与有小数的数字进行比较，你不能使用=!。这个问题在大多数计算机语言是常见的，因为浮点值不是准确的值。
    mysql> SELECT * FROM table_name WHERE float_column=3.5;
   ->
mysql> SELECT * FROM table_name WHERE float_column between 3.45 and 3.55;

    在大多数情况下，将FLOAT改成一个DOUBLE将修正它！

  6. 如果你仍然不能发现错误是什么，创建一个最小的可运行mysql test < query.sql的测试来显示你的问题。你可以用mysqldump --quick database tables > query.sql创建一个测试文件，在一个编辑器编辑文件，删除一些插入行(如果有太多这些语句)并且在文件末尾加入你的选择语句。测试你仍然有问题，可以这样做：
    shell> mysqladmin create test2
shell> mysql test2 < query.sql

    使用mysqlbug的邮寄测试文件到mysql@lists.mysql.com。

18.19 与ALTER TABLE有关的问题

如果ALTER TABLE死于这样一个错误：

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

问题可能是MySQL在前一个ALTER TABLE中已经崩溃并且留下了一个名为“A-xxx”或“B-xxx”的老的数据库表。在这种情况下，到MySQL数据目录中并删除所有名字以A-或B-开始的文件。（你可以把他们移到别的地方而不是删除他们)。

ALTER TABLE工作方式是：

  • 以要求的改变创建一个名为“A-xxx”的新表。
  • 从老表把所有行拷贝到“A-xxx”。
  • 老表被改名为“B-xxx”。
  • “A-xxx”被改名为你的老表的名字。
  • “B-xxx”被删除。

如果某些改名操作出错，MySQL试图还原改变。如果出错严重(当然，这不应该发生。)，MySQL可能留下了老表为“B-xxx”但是一个简单改名就应该恢复你的数据。

18.20 怎样改变一张表中列的顺序

SQL的要点是中抽象应用程序以避免数据存储格式。你应该总是以你想要检索数据的意愿指定顺序。例如：

SELECT col_name1, col_name2, col_name3 FROM tbl_name;

将以col_name1、col_name2、col_name3的顺序返回列，而：

SELECT col_name1, col_name3, col_name2 FROM tbl_name;

将以col_name1、col_name3、col_name2的顺序返回列。

在一个应用程序中，你应该决不基于他们的位置使用SELECT * 检索列，因为被返回的列的顺序永远不能保证；对你的数据库的一个简单改变可能导致你的应用程序相当有戏剧性地失败。

不管怎样，如果你想要改变列的顺序，你可以这样做：

  1. 以正确的列顺序创建一张新表。
  2. 执行INSERT INTO new_table SELECT fields-in-new_table-order FROM old_table.
  3. 删除或改名old_table。
  4. ALTER TABLE new_table RENAME old_table。

去首先, 先前, 下一个, 最终部分，目录.


MySQL中文参考手册- 19 用MySQL解决一些常见问题

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

19 用MySQL解决一些常见问题

19.1 数据库复制

一方面复制可以用来增加健壮性和速度。对健壮性，你有2个系统，而如果你出了问题，切换到备份即可。额外的速度通过把非更新查询的一部分送到复制服务器来达到。当然，这只在非更新查询为主时有用，但是这正是一般的情形。

一方面复制计划在不久的未来实现。这将被实现，使得从服务器将以较低优先级的更新和延迟插入被同步到最新数据(这将给读者以比写者更高的优先级)。

MySQL(至今)没有数据库复制，但是有一些如何实现的信息。

复制一个数据库最一般的方法是使用更新日志。见9.2 更新日志。这要求充当一个主数据库(进行数据改变的)并且另一个或多个充当从数据库。要更新一个从数据库，只要运行mysql < update_log。提供对于从数据库适当的主机、用户和口令选项，并且将主数据库的更新日志作为输入。

如果你从未从一张表中删除任何东西，你可以使用一个TIMESTAMP列找出自上一次复制以来(通过比较作你上次做复制的时间）表中哪个行被插入和被改变，且仅拷贝这些行到镜像中。

有可能使用更新日志(对删除)和时间戳记（在两端）做成一个双向更新系统统，但是在这种情况下，当同一数据在两端被改变时，你必须能处理冲突。你可能想保持旧版本以帮助决定什么被更新了。

因为在这种情况中复制用SQL语句进行，你不应该在更新数据库的语句中使用下列函数；他们不能返回与原数据库相同的值：

  • DATABASE()
  • GET_LOCK()和RELEASE_LOCK()
  • RAND()
  • USER(), SYSTEM_USER()或SESSION_USER()
  • VERSION()

所有的时间函数可安全地使用，比如如果需要，时间戳记被送到镜像。LAST_INSERT_ID()也可安全地使用。

19.2 数据库备份

因为MySQL表作为文件存储，做一个备份是容易的。为了得到一个一致的备份，在相关的表上做一个LOCK TABLES。见7.24 LOCK TABLES/UNLOCK TABLES句法。你只需一个读锁定；当你在数据库目录中做文件的一个拷贝时，这允许其他线程继续查询该表。如果你想要做一个SQL级的备份，你可以SELECT INTO OUTFILE。

备份一个数据库的另一个方法是使用mysqldump程序：

  1. 为你的数据库做一个完整的备份：
    shell> mysqldump --tab=/path/to/some/dir --opt --full

    你也可以简单地拷贝所有的表文件(“*.frm”、“*.MYD”和“*.MYI”文件)，只要服务器不在更新任何东西。

  2. 停止mysqld如果它正在运行，然后以--log-update选项启动它。你将得到一个名为“hostname.n”形式的日志文件， 这里n是随着你每次执行mysqladmin refresh或mysqladmin flush-logs、FLUSH LOGS语句、或重启服务器而递增的一个数字。这些日志文件向你提供了在你执行mysqldump处后面进行的复制数据库改变的所需信息。

如果你必须恢复一些东西，尝试首先用myisamchk -r恢复你的表。这应该处理所有情况的99.9%。如果myisamchk失败，尝试下列过程：

  1. 恢复原来的mysqldump备份。
  2. 执行下列命令以再次运行更新日志中的更改：
    shell> ls -1 -t -r hostname.[0-9]* | xargs cat | mysql

ls被用来以正确的顺序得到所有的日志文件。

你也可以与SELECT * INTO OUTFILE 'file_name' FROM tbl_name做有选择的备份并且用LOAD DATA INFILE 'file_name' REPLACE ...恢复。为了避免重复记录，在表中你需要一个PRIMARY KEY或UNIQUE键。当在唯一键值上一个新记录与一个老记录重复时，REPLACE关键词使得老记录用一个新记录替代。

19.3 在同一台机器上运行多个MySQL服务器

有些情况下你可能想要在同一台机器上运行多个服务器。例如，你可能想要测试一个新的MySQL版本而让你现有生产系统的设置不受到干扰，或你可能是想要为不同的客户提供独立的MySQL安装一个因特网服务供应商。

如果你想要运行多个服务器，最容易的方法是用不同的TCP/IP端口和套接字文件重新编译服务器，因此他们不是侦听同一个TCP/IP端口或套接字。

假设一个现存服务器配置为缺省端口号和套接字文件，那么用一个这样的configure命令行设置新的服务器：

shell> ./configure  --with-tcp-port=port_number \
             --with-unix-socket=file_name \
             --prefix=/usr/local/mysql-3.22.9

这里port_number和file_name应该不同于缺省端口号和套接字文件路径名，而且--prefix值应该指定一个不同于现存的MySQL安装所在的安装目录。

你可以用这个命令检查由任何当前执行的MySQL所使用的套接字和端口：

shell> mysqladmin -h hostname --port=port_number variables

如果你有一个MySQL服务器正运行在你使用了的端口上，你将得到MySQL的一些最重要的可配置变量的一张表，包括套接字名等。

你也应该编辑你机器的初始化脚本(可能是“mysql.server”)来启动并杀死多个mysqld服务器。

你不必重新编译一个新MySQL服务器，只要以一个不同的端口和套接字启动即可。你可以通过指定在运行时safe_mysqld使用的选项来改变端口和套接字：

shell> /path/to/safe_mysqld --socket=file_name --port=port_number

如果你在与开启日志的另一个服务器相同的一个数据库目录下运行新服务器，你也应该用safe_mysqld的--log和--log-update选项来指定日志文件的名字，否则，两个服务器可能正在试图写入同一个日志文件。

警告：通常你决不应该有在同一个数据库中更新数据的2个服务器！如果你的OS不支持无故障(fault-free)的系统锁定，这可能导致令人惊讶的事情发生！

如果你想要为第二个服务器使用另一个数据库目录，你可以使用safe_mysqld的--datadir=path选项。

当你想要连接一个正在运行的使用一个不同于编译进你的客户程序中端口的MySQL服务器时，你可以使用下列方法之一：

  • 以--host 'hostname' --port=port_numer或[--host localhost] --socket=file_name启动客户。
  • 在你的C或Perl程序中，当连接MySQL服务器时，你可以给出端口和套接字参数。
  • 在你启动客户程序之前，设置MYSQL_UNIX_PORT和MYSQL_TCP_PORT环境变量，指向Unix套接字和TCP/IP的端口。如果你通常使用一个特定的套接字或端口，你应该将设置这些环境变量的命令放进你的“.login”文件中。见12.1 不同的 MySQL程序概述。
  • 在你的主目录下的“.my.cnf”文件中指定缺省套接字和TCP/IP端口。见4.15.4 选项文件。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册- 20 MySQL客户工具和API

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

20 MySQL客户工具和API

20.1 MySQL C API

C API代码是随MySQL分发的，它被包含在mysqlclient库且允许C程序存取一个数据库。

在 MySQL源代码分发中的很多客户是用C编写的。如果你正在寻找演示怎样使用C API的例子，看一下这些客户程序。

大多数其他客户 API(除了Java的所有)都使用mysqlclient库与MySQL服务器通信。这意味着，例如，你能利用很多被其他客户程序使用的同一环境变量，因为他们从库中引用。对这些变量的一张表，见12.1 不同的MySQL程序的概述。

客户有一个最大通讯缓冲区大小。初始分配的缓冲区大小(16K字节) 自动地增加到最大尺寸(缺省的最大值是24M)。因为缓冲区大小只是按保证需求而被增加，简单地增加缺省的最大限制并不造成更多被消耗。该尺寸检查主要是一个对错误的查询和通讯包的检查。

通讯缓冲区必须足够大以便一个单独的SQL语句(对客户-服务器传输)和一行返回的数据(对服务器-客户传输)。每个线程的通讯缓冲区被动态扩大到最大限制来处理任何查询或行。例如，如果你包含大到16M数据的BLOB值，你必须有一个至少16M通讯缓冲区限制(在服务器和客户两端)。客户的缺省最大值是24M，但是在服务器端的缺省最大值是1M。你可以在服务器启动时通过改变max_allowed_packet参数的值来改变它。见10.2.3 调节服务器参数。

MySQL服务器在每个查询后缩小每个通讯缓冲区到net_buffer_length个字节。对客户，与一个连接相关的缓冲区的大小没被减少，直到连接被关闭，在此时客户内存被回收。

如果你用线程的编程，你应该用--with-thread-safe-client编译MySQL C API，这将使C API线程对每个连接更安全。你可以让2个线程共享相同的连接，只要如果你做下列事情：

两个线程不能同时在同一个连接上发送查询到MySQL。特别是你必须保证在一个mysql_query()和mysql_store_result()之间没有其他线程正在使用同一个连接。
许多线程能存取用mysql_store_result()检索出来的不同结果集合。
如果你使用mysql_use_result，你必须保证没有其他线程在同一个连接上正在询问任何东西，直到结果集合被关闭。

20.2 C API数据类型

MYSQL
这个结构表示对一个数据库连接的句柄，它被用于几乎所有的MySQL函数。
MYSQL_RES
这个结构代表返回行的一个查询的(SELECT, SHOW, DESCRIBE, EXPLAIN)的结果。从查询返回的信息在本章下文称为结果集合。
MYSQL_ROW
这是一个行数据的类型安全(type-safe)的表示。当前它实现为一个计数字节的字符串数组。（如果字段值可能包含二进制数据，你不能将这些视为空终止串，因为这样的值可以在内部包含空字节) 行通过调用mysql_fetch_row()获得。
MYSQL_FIELD
这个结构包含字段信息，例如字段名、类型和大小。其成员在下面更详细地描述。你可以通过重复调用mysql_fetch_field()对每一列获得MYSQL_FIELD结构。字段值不是这个结构的部分；他们被包含在一个MYSQL_ROW结构中。
MYSQL_FIELD_OFFSET
这是一个相对一个MySQL字段表的偏移量的类型安全的表示。（由mysql_field_seek()使用。) 偏移量是在一行以内的字段编号，从0开始。
my_ulonglong
该类型用于行编号和mysql_affected_rows()、mysql_num_rows()和mysql_insert_id()。这种类型提供0到1.84e19的一个范围。在一些系统上，试图打印类型my_ulonglong的值将不工作。为了打印出这样的值，将它变换到unsigned long并且使用一个%lu打印格式。例如：
printf (Number of rows: %lu\n", (unsigned long) mysql_num_rows(result));

MYSQL_FIELD结构包含列在下面的成员：

char * name
字段名，是一个空结尾的字符串。
char * table
包含该字段的表的名字，如果它不是可计算的字段。对可计算的字段，table值是一个空字符串。
char * def
这字段的缺省值，是一个空结尾的字符串。只要你使用，只有你使用mysql_list_fields()才可设置它。
enum enum_field_types type
字段类型。type值可以是下列之一：
类型值 | 类型含义
FIELD_TYPE_TINY | TINYINT字段
FIELD_TYPE_SHORT | SMALLINT字段
FIELD_TYPE_LONG | INTEGER字段
FIELD_TYPE_INT24 | MEDIUMINT字段
FIELD_TYPE_LONGLONG | BIGINT字段
FIELD_TYPE_DECIMAL | DECIMAL或NUMERIC字段
FIELD_TYPE_FLOAT | FLOAT字段
FIELD_TYPE_DOUBLE | DOUBLE或REAL字段
FIELD_TYPE_TIMESTAMP | TIMESTAMP字段
FIELD_TYPE_DATE | DATE字段
FIELD_TYPE_TIME | TIME字段
FIELD_TYPE_DATETIME | DATETIME字段
FIELD_TYPE_YEAR | YEAR字段
FIELD_TYPE_STRING | 字符串(CHAR或VARCHAR)字段
FIELD_TYPE_BLOB | BLOB或TEXT字段(使用max_length决定最大长度）
FIELD_TYPE_SET | SET字段
FIELD_TYPE_ENUM | ENUM字段
FIELD_TYPE_NULL | NULL- 类型字段
FIELD_TYPE_CHAR | 不推荐；使用FIELD_TYPE_TINY代替

你可以使用IS_NUM()宏来测试字段是否有一种数字类型。将type值传给IS_NUM()并且如果字段是数字的，它将计算为TRUE：

if (IS_NUM(field->type))
    printf("Field is numeric\n");
unsigned int length
字段宽度，在表定义中指定。
unsigned int max_length
对结果集合的字段的最大宽度(对实际在结果集合中的行的最长字段值的长度)。如果你使用mysql_store_result()或mysql_list_fields()，这包含字段最大长度。如果你使用mysql_use_result()，这个变量的值是零。
unsigned int flags
字段的不同位标志。flags值可以是零个或多个下列位设置：
标志值 | 标志含义
NOT_NULL_FLAG | 字段不能是NULL
PRI_KEY_FLAG | 字段是一个主键的一部分
UNIQUE_KEY_FLAG | 字段是一个唯一键的一部分
MULTIPLE_KEY_FLAG | 字段是一个非唯一键的一部分。
UNSIGNED_FLAG | 字段有UNSIGNED属性
ZEROFILL_FLAG | 字段有ZEROFILL属性
BINARY_FLAG | 字段有BINARY属性
AUTO_INCREMENT_FLAG | 字段有AUTO_INCREMENT属性
ENUM_FLAG | 字段是一个ENUM（不推荐）
BLOB_FLAG | 字段是一个BLOB或TEXT（不推荐）
TIMESTAMP_FLAG | 字段是一个TIMESTAMP（不推荐）

BLOB_FLAG、ENUM_FLAG和TIMESTAMP_FLAG标志的使用是不推荐的，因为他们指出字段的类型而非它的类型属性。对FIELD_TYPE_BLOB、FIELD_TYPE_ENUM或FIELD_TYPE_TIMESTAMP，最好是测试field->type。下面例子演示了一个典型的flags值用法：

if (field->flags & NOT_NULL_FLAG)
    printf("Field can't be null\n");

你可以使用下列方便的宏决来确定flags值的布尔状态：

IS_NOT_NULL(flags) | 真，如果该字段被定义为NOT NULL
IS_PRI_KEY(flags) | 真，如果该字段是一个主键
IS_BLOB(flags) | 真，如果该字段是一个BLOB或TEXT（不推荐；相反测试field->type）
unsigned int decimals
对数字字段的小数位数。

20.3 C API函数概述

在 C API 中可用的函数列在下面，并且在下一节更详细地描述。见20.4 C API函数描述。

mysql_affected_rows() | 返回被最新的UPDATE, DELETE或INSERT查询影响的行数。
mysql_close() | 关闭一个服务器连接。
mysql_connect() | 连接一个MySQL服务器。该函数不推荐；使用mysql_real_connect()代替。
mysql_change_user() | 改变在一个打开的连接上的用户和数据库。
mysql_create_db() | 创建一个数据库。该函数不推荐；而使用SQL命令CREATE DATABASE。
mysql_data_seek() | 在一个查询结果集合中搜寻一任意行。
mysql_debug() | 用给定字符串做一个DBUG_PUSH。
mysql_drop_db() | 抛弃一个数据库。该函数不推荐；而使用SQL命令DROP DATABASE。
mysql_dump_debug_info() | 让服务器将调试信息写入日志文件。
mysql_eof() | 确定是否已经读到一个结果集合的最后一行。这功能被反对; mysql_errno()或mysql_error()可以相反被使用。
mysql_errno() | 返回最近被调用的MySQL函数的出错编号。
mysql_error() | 返回最近被调用的MySQL函数的出错消息。
mysql_escape_string() | 用在SQL语句中的字符串的转义特殊字符。
mysql_fetch_field() | 返回下一个表字段的类型。
mysql_fetch_field_direct () | 返回一个表字段的类型，给出一个字段编号。
mysql_fetch_fields() | 返回一个所有字段结构的数组。
mysql_fetch_lengths() | 返回当前行中所有列的长度。
mysql_fetch_row() | 从结果集合中取得下一行。
mysql_field_seek() | 把列光标放在一个指定的列上。
mysql_field_count() | 返回最近查询的结果列的数量。
mysql_field_tell() | 返回用于最后一个mysql_fetch_field()的字段光标的位置。
mysql_free_result() | 释放一个结果集合使用的内存。
mysql_get_client_info() | 返回客户版本信息。
mysql_get_host_info() | 返回一个描述连接的字符串。
mysql_get_proto_info() | 返回连接使用的协议版本。
mysql_get_server_info() | 返回服务器版本号。
mysql_info() | 返回关于最近执行得查询的信息。
mysql_init() | 获得或初始化一个MYSQL结构。
mysql_insert_id() | 返回有前一个查询为一个AUTO_INCREMENT列生成的ID。
mysql_kill() | 杀死一个给定的线程。
mysql_list_dbs() | 返回匹配一个简单的正则表达式的数据库名。
mysql_list_fields() | 返回匹配一个简单的正则表达式的列名。
mysql_list_processes() | 返回当前服务器线程的一张表。
mysql_list_tables() | 返回匹配一个简单的正则表达式的表名。
mysql_num_fields() | 返回一个结果集合重的列的数量。
mysql_num_rows() | 返回一个结果集合中的行的数量。
mysql_options() | 设置对mysql_connect()的连接选项。
mysql_ping() | 检查对服务器的连接是否正在工作，必要时重新连接。
mysql_query() | 执行指定为一个空结尾的字符串的SQL查询。
mysql_real_connect() | 连接一个MySQL服务器。
mysql_real_query() | 执行指定为带计数的字符串的SQL查询。
mysql_reload() | 告诉服务器重装授权表。
mysql_row_seek() | 搜索在结果集合中的行，使用从mysql_row_tell()返回的值。
mysql_row_tell() | 返回行光标位置。
mysql_select_db() | 连接一个数据库。
mysql_shutdown() | 关掉数据库服务器。
mysql_stat() | 返回作为字符串的服务器状态。
mysql_store_result() | 检索一个完整的结果集合给客户。
mysql_thread_id() | 返回当前线程的ID。
mysql_use_result() | 初始化一个一行一行地结果集合的检索。

为了连接服务器，调用mysql_init()以初始化一个连接处理器，然后用该处理器调用mysql_real_connect()(还有其他信息例如主机名、用户名和口令)。当你用该连接完成工作后，调用mysql_close()终止它。

当一个连接活跃时，客户可以用mysql_query()或mysql_real_query()将SQL查询发送到服务器。两者的差别是mysql_query()期望查询作为一个空结尾的字符串来指定而mysql_real_query()期望一个计数的字符串。如果字符串包含二进制数据(它可以包括空字节)，你必须使用mysql_real_query()。

对与每个非--SELECT查询(例如，INSERT、UPDATE、DELETE等)，你可以调用mysql_affected_rows()知道有多少行受到影响(改变)。

对于SELECT查询，你作为一个结果集合来检索选择的行。（注意一些语句是类SELECT的，他们返回行。这些包括SHOW、DESCRIBE和EXPLAIN。他们应该象SELECT语句相同的方式来对待。）

对客户，有两种方法处理结果集合。一种方法是通过调用mysql_store_result()立刻检索全部结果。该函数从服务器获得查询返回的所有行，并将他们存储在客户端。第二种方法是对客户通过调用mysql_use_result()初始化一个一行一行地结果集合的检索。该函数初始化检索，但是实际上不从服务器获得任何行。

在两种情况中，你通过mysql_fetch_row()存取行。用mysql_store_result()、mysql_fetch_row()储存取已经从服务器被取出的行。用mysql_use_result()、mysql_fetch_row()实际上从服务器检索行。调用mysql_fetch_lengths()可获得关于每行中数据值尺寸的信息。

在你用完一个结果集合以后，调用mysql_free_result()释放由它使用的内存。

两种检索机制是互补的。客户程序应该选择最适合他们的要求的途径。在实践中，客户通常更愿意使用mysql_store_result()。

mysql_store_result()的一个优点是既然行均被客户取到，你不仅能顺序存取行，你也能mysql_data_seek()或mysql_row_seek()在结果集合中前后移动以改变在结果集合中的当前行位置。你也能通过调用mysql_num_rows()知道有多少行。另一方面，mysql_store_result()的内存需求对较大结果集合可能很高，并且你最可能遇到out-of-memory情况。

mysql_use_result()的一个优点是客户为结果集合需要较少的内存，因为它一次只是维持一行(并且因为有较少的分配开销，mysql_use_result()能更快些)。缺点是你必须尽快处理每一行以避免困住服务器，你不必再结果集合中随意存取行(你只能顺序存取行)，而且你不知道在结果集合中有多少行，直到你检索全部结果。还有，你必须检索出所有行，即使你在检索中途确定你已找到了想寻找的信息。

API使得客户正确应答查询成为可能(仅检索必要的行)，不用知道查询是否是一个SELECT。你可以通过在mysql_query()（或mysql_real_query())之后调用mysql_store_result()做到。如果结果集合调用成功并且查询是一个SELECT，你能读取行。如果结果集合调用，调用mysql_field_count()确定结果是否是实际期望的。如果mysql_field_count()返回0，查询没有返回数据(表明它是一个INSERT、UPDATE、DELETE等)，所以不期望返回行。如果mysql_field_count()是非零，查询应该有返回行，但是没有。这表明查询是一个失败的SELECT。见mysql_field_count()如何能做到的例子的描述。

mysql_store_result()和mysql_use_result()都允许你获得有关组成结果集合的字段的信息(字段数量、他们的名字和类型等等)。你可以通过重复调用mysql_fetch_field()在行中顺序存取字段信息，或调用mysql_fetch_field_direct()存取行中的字段编号。当前字段光标位置可以通过调用mysql_field_seek()改变，设置字段光标影响到后续mysql_fetch_field()调用。你也能通过调用mysql_fetch_fields()马上获得字段信息。

对于检测和报告错误，MySQL借助于mysql_errno()和mysql_error()函数提供错误信息的存取。他们返回最近调用的可能成功或失败的函数的错误代码或错误消息，允许你确定何时发生一个错误和什么错误。

20.4 C API函数描述

在下面的描述中，一个NULL参数或返回值含义是在C编程语言环境的NULL，不是一个MySQL NULL值。

返回一个值的函数一般返回一个指针或一个整数。除非另外指定，返回一个指针的函数返回一个非 NULL值表明成功，或一个NULL值表明一个错误，而返回一个整数的函数返回零表示成功，或非零表示一个错误。注意，“非零”只有这个含义。除非函数描述另外说明，不要测试一个零以外的其他值：

if (result)                   /* 正确 */
    ... error ...

if (result < 0)               /* 不正确 */
    ... error ...

if (result == -1)             /* 不正确 */
    ... error ...

当函数返回一个错误时，函数描述的错误小节列出错误可能的类型。你可以调用mysql_errno()找出发生了这些重的哪一个。错误的字符串表示可以调用mysql_error()获得。

20.4.1 mysql_affected_rows()

my_ulonglong mysql_affected_rows(MYSQL *mysql)

20.4.1.1 说明

返回受到最后一个UPDATE、DELETE或INSERT查询影响(变化)的行数。可以在针对UPDATE、DELETE或INSERT语句的mysql_query()之后立即调用。对于SELECT语句，mysql_affected_rows()的功能于mysql_num_rows()相同。

mysql_affected_rows()目前以一个宏(macro)来实现。

20.4.1.2 返回值

大于零的一个整数表示受到影响或检索出来的行数。零表示没有匹配查序中WHERE子句的记录或目前还没有查询被执行。-1表示查询返回一个错误，或对于一个SELECT查询，mysql_affected_rows()在调用mysql_store_result()之前被调用。

20.4.1.3 错误

没有。

20.4.1.4 范例

mysql_query(&mysql,"UPDATE products SET cost=cost*1.25 WHERE group=10");
printf("%d products updated",mysql_affected_rows(&mysql));

20.4.2 mysql_close()

void mysql_close(MYSQL *mysql)

20.4.2.1 说明

关闭一个以前打开了的连接。如果句柄由mysql_init()或mysql_connect()自动分配，mysql_close()也释放被mysql指向的连接句柄。

20.4.2.2 返回值

没有。

20.4.2.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务者的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.3 mysql_connect()

MYSQL *mysql_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd)

20.4.3.1 说明

该函数不推荐使用，而更好使用mysql_real_connect()。

mysql_connect()试图建立一个对运行在host的一个MySQL数据库引擎的连接。mysql_connect()必须在你能执行其他API函数之前成功地完成，除了mysql_get_client_info()。

参数的含义与mysql_connect()相应的参数相同，不同的是连接参数可以是NULL。在这种情况下，C API 自动为连接结构分配内存，并且当你调用mysql_close()，释放它。这种方法的缺点是如果连接失败，你不能检索出一条错误消息。（为了从mysql_errno()或mysql_error()得到错误信息，你必须提供一个有效的MYSQL指针。）

20.4.3.2 返回值

同mysql_real_connect()。

20.4.3.3 错误

同mysql_real_connect()。

20.4.4mysql_change_user()

my_bool mysql_change_user(MYSQL *mysql, const char *user, const char *password, const char *db)

20.4.4.1 说明

改变用户并且使得由db指定数据库成为由mysql指定的连接上的缺省(当前)数据库。在随后的查询中，这个数据库是不包括一个明确的数据库指定符的表引用的缺省值。

这个函数功能在MySQL 3.23.3中引入。

除非连接的用户能被认证或如果他没有权限使用数据库，mysql_change_user()失败。在这种情况下，用户和数据库都没被改变。

如果你不想有一个缺省数据库，db参数可以被设置为NULL。

20.4.4.2 返回值

成功，零。如果发生一个错误发生，非零。

20.4.4.3 错误

与你能从mysql_real_connect()得到的相同。

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务者关闭了。
CR_SERVER_LOST
对服务者的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。
ER_UNKNOWN_COM_ERROR
MySQL服务器未实现这个命令(可能是一个老的服务器）
ER_ACCESS_DENIED_ERROR
用户或口令错误。
ER_BAD_DB_ERROR
数据库不存在。
ER_DBACCESS_DENIED_ERROR
用户没有数据库的存取权利。
ER_WRONG_DB_NAME
数据库名字太长。

20.4.4.4 范例

if (mysql_change_user(&mysql, "user", "password", "new_database"))
{
   fprintf(stderr, "Failed to change user.  Error: %s\n",
           mysql_error(&mysql));
}

20.4.5 mysql_create_db()

int mysql_create_db(MYSQL *mysql, const char *db)

20.4.5.1 说明

创建由db参数命名的数据库。

这个函数不推荐，而最好使用mysql_query()发出一条SQL CREATE DATABASE语句。

20.4.5.2 返回值

如果数据库成功地被创造，零。如果发生一个错误，非零。

20.4.5.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务者的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.5.4 范例

if(mysql_create_db(&mysql, "my_database"))
{
   fprintf(stderr, "Failed to create new database.  Error: %s\n",
           mysql_error(&mysql));
}

20.4.6 mysql_data_seek()

void mysql_data_seek(MYSQL_RES *result, unsigned long long offset)

20.4.6.1 说明

在一个查询结果集合中定位任意行。这要求结果集合结构包含查询的全部结果，这样mysql_data_seek()可以仅需与mysql_store_result()一起使用，不是与mysql_use_result()。

偏移量应该是从0到mysql_num_rows(result)-1范围的一个值。

20.4.6.2 返回值

无。

20.4.6.3 错误

无。

20.4.7 mysql_debug()

void mysql_debug(char *debug)

20.4.7.1 说明

用一个给定字符串做一个DBUG_PUSH。mysql_debug()使用Fred Fish 调试库。为了使用这个函数，你必须编译客户库以支持调试。见G.1 调试一个MySQL服务器和节G.2 调试一个MySQL客户。

20.4.7.2 返回值

无。

20.4.7.3 错误

无。

20.4.7.4 范例

下面所示的调用使得客户库在客户机器上的“/tmp/client.trace”中产生一个跟踪文件：

mysql_debug("d:t:O,/tmp/client.trace");

20.4.8 mysql_drop_db()

int mysql_drop_db(MYSQL *mysql, const char *db)

20.4.8.1 说明

抛弃由db参数命名的数据库。

这个函数不推荐，而最好使用mysql_query()发出一条SQL DROP DATABASE语句。

20.4.8.2 返回值

如果数据库成功地被破抛弃，零。如果发生一个错误，非零。

20.4.8.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务者的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.8.4 范例

if(mysql_drop_db(&mysql, "my_database"))
  fprintf(stderr, "Failed to drop the database: Error: %s\n",
          mysql_error(&mysql));

20.4.9 mysql_dump_debug_info()

int mysql_dump_debug_info(MYSQL *mysql)

20.4.9.1 说明

指示服务者将一些调试信息写入日志文件。连接的用户对此必须有precess权限才能工作。

20.4.9.2 返回值

如果命令成功，零。如果发生一个错误，非零。

20.4.9.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务者关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.10 mysql_eof()

my_bool mysql_eof(MYSQL_RES *result)

20.4.10.1 说明

这个函数不推荐，而使用mysql_errno()或mysql_error()。

mysql_eof()确定是否已经读到了一个结果集合的最后一行。

如果你从成功的mysql_store_result()调用获得一个结果集合，客户程序用一个操作收到全部集合。在这种情况下，从mysql_fetch_row()返回一个NULL总是意味着已经到达了结果集合的尾部，没必要调用mysql_eof()。

在另一方面，如果你使用mysql_use_result()初始化一个结果集合的检索，该集合的行随着你重复调用mysql_fetch_row()一个一个地从服务器获得。因为在这个过程中在连接上可能发生一个错误，从mysql_fetch_row()返回一个NULL值并不意味着集合正常到达了尾部。在这种情况下，你能使用mysql_eof()确定发生了什么。如果到达结果集合的尾部，mysql_eof()返回非零值，并且如果发生一个错误，返回零。

在时间上，mysql_eof()先于标准MySQL错误函数mysql_errno()和mysql_error()。因为这些错误函数提供相同的信息，他们的使用更好mysql_eof()，它现在不建议使用。（事实上，他们提供更多的信息，因为mysql_eof()值返回一个布尔值，而错误函数指出当发生错误时的出错原因。）

20.4.10.2 返回值

如果发生一个错误，零。如果到达结果集合的结束，非零。

20.4.10.3 错误

无。

20.4.10.4 范例

下列例子显示你必须如何使用mysql_eof()：

mysql_query(&mysql,"SELECT * FROM some_table");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result)))
{
    // do something with data
}
if(!mysql_eof(result))  // mysql_fetch_row() failed due to an error
{
    fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}

然而，你可以用标准MySQL错误函数完成同样的效果：

mysql_query(&mysql,"SELECT * FROM some_table");
result = mysql_use_result(&mysql);
while((row = mysql_fetch_row(result)))
{
    // do something with data
}
if(mysql_errno(&mysql))  // mysql_fetch_row() failed due to an error
{
    fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}

20.4.11 mysql_errno()

unsigned int mysql_errno(MYSQL *mysql)

20.4.11.1 说明

对于由mysql指定的连接，mysql_errno()返回最近调用的可能成功或失败的API函数的错误代码。返回值零意味着没有错误发生。客户错误消息编号列出在MySQL“errmsg.h”头文件中。服务器错误消息编号列出在“mysqld_error.h”中。

20.4.11.2 返回值：

一个错误代码值。如果没有错误发生，零。

20.4.11.3 错误

无。

20.4.12 mysql_error()

char *mysql_error(MYSQL *mysql)

20.4.12.1 说明

对于由mysql指定的连接，mysql_errno()返回最近调用的可能成功或失败的API函数的错误代码。如果没有错误发生，返回空字符串("")。这意味着下列两个测试是等价的：

if(mysql_errno(&mysql))
{
    // an error occurred
}

if(mysql_error(&mysql)[0] != '\0')
{
    // an error occurred
}

客户错误消息的语言可通过重新编译MySQL客户库来改变。目前，你能在几种不同的语言间选取错误消息。见9.1 MySQL支持什么语言？。

20.4.12.2 返回值

一个描述错误的字符串。如果没有错误发生，空字符串。

20.4.12.3 错误

无。

20.4.13 mysql_escape_string()

unsigned int mysql_escape_string(char *to, const char *from, unsigned int length)

20.4.13.1 说明

把在from中的字符串编码为在一条SQL语句中可以发给服务器的转义的SQL字符串，将结果放在to中， 并且加上一个终止的空字节。编码的字符是NUL（ASCII 0)、‘\n’、‘\r’、‘\’、‘'’、‘"’和Control-Z(见7.1 文字：如何写字符串和数字)。

由from指向的字符串必须是length个字节长。你必须分配to的缓冲区至少length*2+1个字节长。（在更坏的情况，每个字符可能需要使用2个字节被编码，并且你需要为终止空字节的空间) 当mysql_escape_string()返回时，to的内容将是空字符终止的字符串。返回值是编码后的字符串的长度，不包括终止空字符。

20.4.13.2 范例

char query[1000],*end;

end = strmov(query,"INSERT INTO test_table values(");
*end++ = '\'';
end += mysql_escape_string(end,"What's this",11);
*end++ = '\'';
*end++ = ',';
*end++ = '\'';
end += mysql_escape_string(end,"binary data: \0\r\n",16);
*end++ = '\'';
*end++ = ')';

if (mysql_real_query(&mysql,query,(unsigned int) (end - query)))
{
   fprintf(stderr, "Failed to insert row, Error: %s\n",
           mysql_error(&mysql));
}

例子中所用的strmov()函数被包括在mysqlclient库中且功能类似于strcpy()，但是返回一个指向空终止的第一个参数的指针。

20.4.13.3 返回值

放进to的值的长度，不包括终止空字符。

20.4.13.4 错误

无。

20.4.14 mysql_fetch_field()

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)

20.4.14.1 说明

返回作为一个MYSQL_FIELD结构的一个结果集合的一个列的定义。重复调用这个函数在结果集合中检索所有关于列的信息。当没有剩下更多的字段时，mysql_fetch_field()返回NULL。

在每次你执行一个新的SELECT查询，mysql_fetch_field()被重置（reset)以返回有关第一列的信息。由mysql_fetch_field()返回的字段也受调用mysql_field_seek()的影响。

如果你调用mysql_query()在一张表上执行一个SELECT，但是没调用mysql_store_result()，如果你调用mysql_fetch_field()询问一个BLOB字段的长度，MySQL返回缺省BLOB长度(8K字节)。（选择8K的长度是因为MySQL不知道BLOB的最大长度。这应该在某个时候是它可配置) 一旦你已经检索了结果集合，field->max_length包含了在特定查询中对于该列最大值的长度。

20.4.14.2 返回值

当前列的MYSQL_FIELD结构。如果没有列剩下，NULL。

20.4.14.3 错误

无。

20.4.14.4 范例

MYSQL_FIELD *field;

while((field = mysql_fetch_field(result)))
{
    printf("field name %s\n", field->name);
}

20.4.15 mysql_fetch_fields()

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)

20.4.15.1 说明

返回一个结果集合的所有MYSQL_FIELD结构的数组。每个结构提供结果结合中一列的字段定义。

20.4.15.2 返回值

一个结果集合的所有MYSQL_FIELD结构的一个数组。

20.4.15.3 错误

无。

20.4.15.4 范例

unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *fields;

num_fields = mysql_num_fields(result);
fields = mysql_fetch_fields(result);
for(i = 0; i < num_fields; i++)
{
   printf("Field %u is %s\n", i, fields[i].name);
}

20.4.16 mysql_fetch_field_direct()

MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *result, unsigned int fieldnr)

20.4.16.1 说明

给定在一个结果集合中的一个列的字段编号fieldnr，返回作为MYSQL_FIELD结构的列的字段定义。你可以使用这个函数检索任意列的义。fieldnr的值应该在从0到mysql_num_fields(result)-1范围内。

20.4.16.2 返回值

指定列的MYSQL_FIELD结构。

20.4.16.3 错误

无。

20.4.16.4 范例

unsigned int num_fields;
unsigned int i;
MYSQL_FIELD *field;

num_fields = mysql_num_fields(result);
for(i = 0; i < num_fields; i++)
{
    field = mysql_fetch_field_direct(result, i);
    printf("Field %u is %s\n", i, field->name);
}

20.4.17 mysql_fetch_lengths()

unsigned long *mysql_fetch_lengths(MYSQL_RES *result)

20.4.17.1 说明

返回在结果集合内的当前行的列长度。如果你计划拷贝字段值，这个长度信息对优化也是有用的，因为你可以避免调用strlen()。另外，如果结果集合中包含二进制数据，你必须使用这个函数确定数据的大小，因为strlen()对包含空字符的任何字段返回不正确的结果。

空列和包含NULL的列的长度值是零。为了看清如何区分这两种情况，见mysql_fetch_row()的说明。

20.4.17.2 返回值

表示每列大小的无符号长整数的一个数组(不包括任何终止空字符)。如果出现一个错误，NULL。

20.4.17.3 错误

mysql_fetch_lengths()只对结果集合的当前行有效。如果你在调用mysql_fetch_row()之前或在检索出在结果中的所有以后，它返回NULL。

20.4.17.4 范例

MYSQL_ROW row;
unsigned long *lengths;
unsigned int num_fields;
unsigned int i;

row = mysql_fetch_row(result);
if (row)
{
    num_fields = mysql_num_fields(result);
    lengths = mysql_fetch_lengths(result);
    for(i = 0; i < num_fields; i++)
    {
         printf("Column %u is %lu bytes in length.\n", i, lengths[i]);
    }
}

20.4.18 mysql_fetch_row()

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

20.4.18.1 说明

检索一个结果集合的下一行。当在mysql_store_result()之后使用时，如果没有更多的行可见所时，mysql_fetch_row()返回NULL。当在mysql_use_result()之后使用时，当没有更多的行可检索时或如果出现一个错误，mysql_fetch_row()返回NULL。

在行中值的数量由mysql_num_fields(result)给出。如果row保存了从一个对用mysql_fetch_row()调用返回的值，指向该值的指针作为row[0]到row[mysql_num_fields(result)-1]来存取。在行中的NULL值由NULL指针指出。

在行中字段值的长度可以通过调用mysql_fetch_lengths()获得。空字段和包含NULL的字段长度都是 0；你可以通过检查该值的指针区分他们。如果指针是NULL，字段是NULL；否则字段是空的。

20.4.18.2 返回值

下一行的一个MYSQL_ROW结构。如果没有更多的行可检索或如果出现一个错误，NULL。

20.4.18.3 错误

CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.18.4 范例

MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;

num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result)))
{
   unsigned long *lengths;
   lengths = mysql_fetch_lengths(result);
   for(i = 0; i < num_fields; i++)
   {
       printf("[%.*s] ", (int) lengths[i], row[i] ? row[i] : "NULL");
   }
   printf("\n");
}

20.4.19 mysql_field_count()

unsigned int mysql_field_count(MYSQL *mysql)

如果你正在使用一个比3.22.24早MySQL版本，你应该使用unsigned int mysql_num_fields(MYSQL *mysql)。

20.4.19.1 说明

返回在连接上的最近查询的列的数量。

这个函数一般用在mysql_store_result()返回NULL时（这样你没有结果设置指针)。在这种情况中，你能调用mysql_field_count()确定mysql_store_result()是否应该产生了一个非空的结果。这允许一个客户程序执行正确的操作，而不必知道查询是否是一条SELECT（或类SELECT)语句。下面显示的例子说明这怎样可以做到。

见20.4.51 为什么在mysql_query()返回成功后，mysql_store_result()有时返回NULL?。

20.4.19.2 返回值

在结果集合中表示字段数量字的一个无符号整数。

20.4.19.3 错误

无。

20.4.19.4 范例

MYSQL_RES *result;
unsigned int num_fields;
unsigned int num_rows;

if (mysql_query(&mysql,query_string))
{
    // error
}
else // query succeeded, process any data returned by it
{
    result = mysql_store_result(&mysql);
    if (result)  // there are rows
    {
        num_fields = mysql_num_fields(result);
        // retrieve rows, then call mysql_free_result(result)
    }
    else  // mysql_store_result() returned nothing; should it have?
    {
        if(mysql_field_count(&mysql) == 0)
        {
            // query does not return data
            // (it was not a SELECT)
            num_rows = mysql_affected_rows(&mysql);
        }
        else // mysql_store_result() should have returned data
        {
            fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
        }
    }
}

另一个选择是用mysql_errno(&mysql)代替mysql_field_count(&mysql)调用。在这种情况中，你直接检查来自mysql_store_result()的一个错误而非从mysql_field_count()值来推断语句是否是一个SELECT。

20.4.20 mysql_field_seek()

MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset)

20.4.20.1 说明

将字段光标设置到给定的偏移量。下一次调用mysql_fetch_field()将检索与该偏移量关联的列的字段定义。

为了定位于行的起始，传递一个值为0的offset值。

20.4.20.2 返回值

字段光标的先前的值。

20.4.20.3 错误

无。

20.4.21mysql_field_tell()

MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *result)

20.4.21.1 说明

返回用于最后一个mysql_fetch_field()的字段光标的位置。这个值可用作mysql_field_seek()的一个参数。

20.4.21.2 返回值

字段光标的当前偏移量。

20.4.21.3 错误

无。

20.4.22 mysql_free_result()

void mysql_free_result(MYSQL_RES *result)

20.4.22.1 说明

释放由mysql_store_result()、mysql_use_result()、mysql_list_dbs()等为一个结果集合分配的内存。当你用完了一个结果集合时，你必须调用mysql_free_result()来释放它使用的内存。

20.4.22.2 返回值

无。

20.4.22.3 错误

无。

20.4.23 mysql_get_client_info()

char *mysql_get_client_info(void)

20.4.23.1 说明

返回代表客户库的版本的字符串。

20.4.23.2 返回值

代表MySQL客户库版本的一个字符串。

20.4.23.3 错误

无。

20.4.24 mysql_get_host_info()

char *mysql_get_host_info(MYSQL *mysql)

20.4.24.1 说明

返回描述正在使用的连接类型的字符串，包括服务其主机名。

20.4.24.2 返回值

表示服务器主机名者和连接类型的字符串。

20.4.24.3 错误

无。

20.4.25 mysql_get_proto_info()

unsigned int mysql_get_proto_info(MYSQL *mysql)

20.4.25.1 说明

返回当前连接使用的协议版本。

20.4.25.2 返回值

表示被当前连接使用的协议版本的一个无符号整数。

20.4.25.3 错误

无。

20.4.26 mysql_get_server_info()

char *mysql_get_server_info(MYSQL *mysql)

20.4.26.1 说明

返回表示服务器版本号的字符串。

20.4.26.2 返回值

表示服务器版本号的一个字符串。

20.4.26.3 错误

无。

20.4.27 mysql_info()

char *mysql_info(MYSQL *mysql)

20.4.27.1 说明

检索一个字符串，它提供有关最近执行的查询的信息，但是对下面列出的语句。对其他语句，mysql_info()返回NULL。字符串的格式随查询类型而变化，如下所述。数字仅仅是说明性的；字符串将包含对查询适当的值。

INSERT INTO ... SELECT ...
字符串格式： Records: 100 Duplicates: 0 Warnings: 0
INSERT INTO ... VALUES (...),(...),(...)...
字符串格式： Records: 3 Duplicates: 0 Warnings: 0
LOAD DATA INFILE ...
字符串格式： Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
ALTER TABLE
字符串绳格式： Records: 3 Duplicates: 0 Warnings: 0
UPDATE
字符串格式： Rows matched: 40 Changed: 40 Warnings: 0

注意，只有多个值在语句中指定，mysql_info()对INSERT ... VALUES语句才返回非NULL值。

20.4.27.2 返回值

表示最近执行的查询的附加信息的一个字符串。如果得不到查询的任何信息，NULL。

20.4.27.3 错误

无。

20.4.28 mysql_init()

MYSQL *mysql_init(MYSQL *mysql)

20.4.28.1 说明

分配或初始化适合mysql_real_connect()的一个MYSQL对象。如果mysql是一个NULL指针，函数分配、初始化并且返回一个新对象。否则对象被初始化并且返回对象的地址。如果mysql_init()分配一个新对象，它将在调用mysql_close()关闭连接时被释放。

20.4.28.2 返回值

一个被初始化的MYSQL*句柄。如果没有足够的内存来分配一个新对象，NULL。

20.4.28.3 错误

在内存不够的情况下，返回NULL。

20.4.29 mysql_insert_id()

my_ulonglong mysql_insert_id(MYSQL *mysql)

20.4.29.1 说明

返回由先前的查询为一个AUTO_INCREMENT列生成的ID。在你执行一个INSERT查询向一个包含AUTO_INCREMENT字段的表中插入后，使用这个函数。

注意，如果先前的查询不产生一个AUTO_INCREMENT值，mysql_insert_id()返回0。如果你需要在以后保存该值，必须在查询生成了该值后马上调用mysql_insert_id()。

也要注意，SQL的LAST_INSERT_ID()函数总是包含最近生成的AUTO_INCREMENT值，并且在查询之间不被重置，因为该函数的值在服务器端维护。

20.4.29.2 返回值

有先前的查询更新的AUTO_INCREMENT字段的值。如果在连接上没有先前的询问或如果查询没更新AUTO_INCREMENT值，返回零。

20.4.29.3 错误

无。

20.4.30 mysql_kill()

int mysql_kill(MYSQL *mysql, unsigned long pid)

20.4.30.1 说明

要求服务器杀死由pid指定的线程。

20.4.30.2 返回值

成功，零。如果出现一个错误，非零。

20.4.30.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.31 mysql_list_dbs()

MYSQL_RES *mysql_list_dbs(MYSQL *mysql, const char *wild)

20.4.31.1 说明

返回一个结果集合，它用在服务器上的匹配wild参数指定的简单正则表达式的数据库名组成。wild可以包含通配符字符“%”或“_”，或可以是匹配所有的数据库的一个NULL指针。调用mysql_list_dbs()类似于执行查询SHOW databases [LIKE wild]。

你必须用mysql_free_result()释放结果集合。

20.4.31.2 返回值

成功，一个MYSQL_RES结果集合。如果出现一个错误，NULL。

20.4.31.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_OUT_OF_MEMORY
内存溢出。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.32 mysql_list_fields()

MYSQL_RES *mysql_list_fields(MYSQL *mysql, const char *table, const char *wild)

20.4.32.1 说明

返回一个结果集合，它用在给定表中的匹配wild参数指定的简单正则表达式的列名组成。wild可以包含通配符字符“%”或“_”，或可以是匹配所有列的一个NULL指针。调用mysql_list_fields()类似于执行查询SHOW COLUMNS FROM tbl_name [LIKE wild]。

注意，建议你使用SHOW COLUMNS FROM tbl_name而不是mysql_list_fields()。

你必须用mysql_free_result()释放结果集合。

20.4.32.2 返回值

成功，一个MYSQL_RES的结果集合。如果出线一个错误，NULL。

20.4.32.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务者关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.33 mysql_list_processes()

MYSQL_RES *mysql_list_processes(MYSQL *mysql)

20.4.33.1 说明

返回一个描述当前服务器线程的结果集合。这是与mysqladmin processlist或SHOW PROCESSLIST查询报告的相同信息。

你必须用mysql_free_result()释放结果集合。

20.4.33.2 返回值

成功，一个MYSQL_RES结果集合。如果发生一个错误，NULL。

20.4.33.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务者关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.34 mysql_list_tables()

MYSQL_RES *mysql_list_tables(MYSQL *mysql, const char *wild)

20.4.34.1 说明

返回一个结果集合，它用在当前数据库中的匹配wild参数指定的简单正则表达式的表名组成。wild可以包含通配符字符“%”或“_”，或可以是匹配所有表的一个NULL指针。调用mysql_list_tables()类似于执行询问SHOW tables [LIKE wild]。

你必须用mysql_free_result()释放结果集合。

20.4.34.2 返回值

成功，一个MYSQL_RES结果集合。如果出现一个错误，NULL。

20.4.34.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不正确的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.35 mysql_num_fields()

unsigned int mysql_num_fields(MYSQL_RES *result)

或

unsigned int mysql_num_fields(MYSQL *mysql)

第二中形式在MySQL 3.22.24或更新版本上不能工作。为了传递一个MYSQL* 参数，你必须使用unsigned int mysql_field_count(MYSQL *mysql)。

20.4.35.1 说明

在结果集合中返回列的数量。

注意，你也可以通过一个指向一个结果集合或一个连接句柄的指针获得列的数量。如果mysql_store_result()或mysql_user_result()返回NULL，你将使用连接句柄（而这样你没有结果集合指针)。在这种情况下，你可以调用mysql_field_count()确定mysql_store_result()是否应该产生非空的结果。这允许客户程序采取成正确的行动，不必知道查询是否是一个SELECT（或类SELECT)语句。下面被显示出的例子说明这怎么可以被做。

见20.4.51 为什么在mysql_query()返回成功后，mysql_store_result()有时返回NULL?。

20.4.35.2 返回值

表示一个结果集合中字段数量的一个无符号整数。

20.4.35.3 错误

无。

20.4.35.4 范例

MYSQL_RES *result;
unsigned int num_fields;
unsigned int num_rows;

if (mysql_query(&mysql,query_string))
{
    // error
}
else // query succeeded, process any data returned by it
{
    result = mysql_store_result(&mysql);
    if (result)  // there are rows
    {
        num_fields = mysql_num_fields(result);
        // retrieve rows, then call mysql_free_result(result)
    }
    else  // mysql_store_result() returned nothing; should it have?
    {
        if (mysql_errno(&mysql))
    {
           fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
    }
        else if (mysql_field_count(&mysql) == 0)
        {
            // query does not return data
            // (it was not a SELECT)
            num_rows = mysql_affected_rows(&mysql);
        }
    }
}

另一个选择(如果你知道你查询应该返回了一个结果结合)是用mysql_field_count(&mysql) = 0的一个检查来代替mysql_errno(&mysql)。这只会发生在出错了的情形。

20.4.36 mysql_num_rows()

my_ulonglong mysql_num_rows(MYSQL_RES *result)

20.4.36.1 说明

在结果集合中返回行的数量。

mysql_num_rows()的使用取决于你是否使用mysql_store_result()或mysql_use_result()返回一个结果集合。如果你使用mysql_store_result()，mysql_num_rows()可以马上被调用。如果你使用mysql_use_result()，mysql_num_rows()将不会返回正确的值，直到在结果集合中的所有行均被检索了。

20.4.36.2 返回值

在结果集合中行的数量。

20.4.36.3 错误

无。

20.4.37 mysql_options()

int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg)

20.4.37.1 说明

能用于设置额外连接选项并且影响一个连接的行为。这个函数可以被多次调用来设置多个选项。

mysql_options()应该在mysql_init()之后和mysql_connect()或mysql_real_connect()之前调用。

option参数是你想要设置的选项；arg参数是选项的值。如果选项是一个整数，那么arg应该指向整数值。

可能的选项值：

选项 | 参数类型 | 功能
MYSQL_OPT_CONNECT_TIMEOUT | unsigned int * | 以秒计的连接超时。
MYSQL_OPT_COMPRESS | 不使用 | 使用压缩的客户机/服务器协议。
MYSQL_OPT_NAMED_PIPE | 不使用 | 使用命名管道连接一个在NT上的MySQL服务器。
MYSQL_INIT_COMMAND | char * | 当连接MySQL服务器时执行的命令。当重新连接时，将自动重新执行。
MYSQL_READ_DEFAULT_FILE | char * | 从命名的选项文件而不是从“my.cnf”读取选项。
MYSQL_READ_DEFAULT_GROUP | char * | 从“my.cnf”或用MYSQL_READ_DEFAULT_FILE指定的文件中的命名组中读取选项。

注意，如果你使用MYSQL_READ_DEFAULT_FILE或MYSQL_READ_DEFAULT_GROUP，总是读取client。

在选项文件中指定的组可能包含下列选项：

compress | 使用压缩的客户机/服务器协议。
database | 如果在连接命令中没有指定数据库，使用这个数据库。
debug | 调试选项
host | 缺省主机名
init-command | 在连接MySQL服务器时，执行的命令。当重新连接时，将自动重新执行。
password | 缺省口令
pipe | 使用命名管道连接一个在NT上的MySQL服务器。
port | 缺省端口号
return-found-rows | 告诉mysql_info()返回找到的行，而不是在使用UPDATE时，返回更新的行。
socket | 缺省套接字号
timeout | 以秒计的连接超时。
user | 缺省用户

对于选项文件的更多信息，见4.15.4 选项文件。

20.4.37.2 返回值

成功，零。如果你使用了未知的选项，非零。

20.4.37.3 范例

MYSQL mysql;

mysql_init(&mysql);
mysql_options(&mysql,MYSQL_OPT_COMPRESS,0);
mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"odbc");
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
{
    fprintf(stderr, "Failed to connect to database: Error: %s\n",
          mysql_error(&mysql));
}

上例请求客户使用压缩的客户机/服务器协议并且从my.cnf文件的odbc小节读取额外的选项。

20.4.38 mysql_ping()

int mysql_ping(MYSQL *mysql)

20.4.38.1 说明

检查到服务器的连接是否正在工作。如果它关闭了，自动尝试一个再连接。

这个函数可被已经空闲很长时间的客户使用，来检查服务器是否关闭了连接并且如有必要重新连接。

20.4.38.2 返回值

如果服务器活着，零。如果出现一个错误，非零。

20.4.38.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.39 mysql_query()

int mysql_query(MYSQL *mysql, const char *query)

20.4.39.1 说明

执行指向空终止的字符串query的SQL查询，查询必须由一个单个的SQL语句组成。你不应该在语句后加上一个终止的分号(“；”)或\g。

mysql_query()不能被用于包含二进制数据的查询；相反你应该使用mysql_real_query()。（二进制数据可能包含“\0”字符，而mysql_query()将解释为查询字符串的结束。）

20.4.39.2 返回值

如果查询成功，零。如果出现一个错误，非零。

20.4.39.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
到服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.40 mysql_real_connect()

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned int client_flag)

20.4.40.1 说明

mysql_real_connect()试图建立到运行host的一个MySQL数据库引擎的一个连接。 mysql_real_connect()在你可以执行任何其他API函数之前必须成功地完成，除了mysql_get_client_info()。

参数指定如下：

  • 第一个参数应该是一个现存MYSQL结构的地址。在调用mysql_real_connect()之前，你必须调用mysql_init()初始化MYSQL结构。见下面的例子。
  • host值可以是一个主机名或一个IP地址。如果host是NULL或字符串"localhost"，假定是到本地主机的一个连接。如果OS支持套接字(Unix)或命名管道(Win32)，使用他们而不是TCP/IP与服务器连接。
  • user参数包含用户的MySQL登录ID。如果user是NULL，假定是当前用户。在Unix下，它是当前登录名。在Windows ODBC下，必须明确地指定当前用户名字。见16.4 怎样填写ODBC管理程序中各种域。
  • passwd参数为user包含口令。如果passwd是NULL，只有在user表中对于有一个空白口令字段的用户的条目将被检查一个匹配。这允许数据库主管设置MySQL权限，使用户获得不同的口令，取决于他们是否已经指定一个口令。注意：不要试图在调用mysql_real_connect()前加密口令；口令加密自动被客户API处理。
  • db是数据库名。如果db不是NULL，连接将缺省数据库设置为这个值。
  • 如果port不是0，值对于TCP/IP连接将用作端口号。注意host参数决定连接的类型。
  • 如果unix_socket不是NULL，字符串指定套接字或应该被使用的命名管道。注意host参数决定连接的类型。
  • client_flag值通常是0，但是在很特殊的情况下可以被设置为下列标志的组合：
    标志名字 | 意味着的标志
    CLIENT_FOUND_ROWS | 返回找到的(匹配的)行数，不是受到影响的行数。
    CLIENT_NO_SCHEMA | 不允许db_name.tbl_name.col_name语法。这是为了ODBC；如果你使用该语法，导致语法分析器产生一个错误，它是为在一些ODBC程序捕捉错误是有用的。
    CLIENT_COMPRESS | 使用压缩协议。
    CLIENT_ODBC | 客户是一个ODBC客户。这使mysqld变得对ODBC更友好。

20.4.40.2 返回值

如果连接成功，一个 MYSQL*连接句柄。如果连接失败，NULL。对一个成功的连接，返回值与第一个参数值相同，除非你传递NULL给该参数。

20.4.40.3 错误

CR_CONN_HOST_ERROR
不能连接MySQL服务器。
CR_CONNECTION_ERROR
不能连接本地MySQL服务器。
CR_IPSOCK_ERROR
不能创建一个IP套接字。
CR_OUT_OF_MEMORY
内存溢出。
CR_SOCKET_CREATE_ERROR
不能创建一个Unix套接字。
CR_UNKNOWN_HOST
不能找到主机名的IP地址。
CR_VERSION_ERROR
由于试图使用一个不同协议版本的一个客户库与一个服务器连接导致的一个协议失配。如果你使用一个非常老的客户库连接一个没有使用--old-protocol选项启动的新服务器，这就能发生。
CR_NAMEDPIPEOPEN_ERROR;
不能在 Win32 上创建一个命名管道。
CR_NAMEDPIPEWAIT_ERROR;
不能在 Win32 上等待一个命名管道。
CR_NAMEDPIPESETSTATE_ERROR;
不能在 Win32 上得到一个管道处理器。

20.4.40.4 范例

MYSQL mysql;

mysql_init(&mysql);
if (!mysql_real_connect(&mysql,"host","user","passwd","database",0,NULL,0))
{
    fprintf(stderr, "Failed to connect to database: Error: %s\n",
          mysql_error(&mysql));
}

20.4.41 mysql_real_query()

int mysql_real_query(MYSQL *mysql, const char *query, unsigned int length)

20.4.41.1 说明

执行由query指向的SQL查询，它应该是一个length个字节的字符串。查询必须由一个单个的SQL语句组成。你不应该在语句后增加一个终止的分号(“;”)或\g。

对于包含二进制数据的查询，你必须使用mysql_real_query()而不是mysql_query()，因为二进制代码数据可能包含“\0”字符，而且，mysql_real_query()比mysql_query()更快，因为它对查询字符串调用strlen()。

20.4.41.2 返回值

如果查询成功，零。如果发生一个错误，非零。

20.4.41.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.42 mysql_reload()

int mysql_reload(MYSQL *mysql)

20.4.42.1 说明

要求MySQL服务器再次装载授权表。连接的用户必须拥有reload权限。

不推荐这个函数。最好使用mysql_query()发出一条SQL FLUSH PRIVILEGES语句。

20.4.42.2 返回值

成功，零。如果发生一个错误，非零。

20.4.42.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.43 mysql_row_seek()

MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset)

20.4.43.1 说明

设置行光标为在结果集合中的任意行。这要求结果集合结构包含查询的全部结果，这样mysql_row_seek()只能与mysql_store_result()一起使用，而不与mysql_use_result()。

偏移量应该是调用mysql_row_tell()或mysql_row_seek()返回的值。这个值不是简单地一个行号；如果你想要在结果集合内用行号来寻找行，使用mysql_data_seek()。

20.4.43.2 返回值

行光标先前的值。该值可以被传递给随后的mysql_row_seek()调用。

20.4.43.3 错误

无。

20.4.44 mysql_row_tell()

MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result)

20.4.44.1 说明

返回为了mysql_fetch_row()的行光标的当前位置。这个值可以作为一个参数用于mysql_row_seek()。

你应该仅在mysql_store_result()后使用mysql_row_tell()，而不是在mysql_use_result()后。

20.4.44.2 返回值

行光标当前的偏移量。

20.4.44.3 错误

无。

20.4.45 mysql_select_db()

int mysql_select_db(MYSQL *mysql, const char *db)

20.4.45.1 说明

使得由db指定的数据库成为 在由mysql指定的连接上的缺省(当前)数据库。在随后的查询中，这个数据库对于不包括一个显式的数据库指定符的表的引用是缺省数据库。

除非连接的用户能被认证允许使用数据库，否则mysql_select_db()失败。

20.4.45.2 返回值

成功，零。如果发生一个错误，非零。

20.4.45.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.46 mysql_shutdown()

int mysql_shutdown(MYSQL *mysql)

20.4.46.1 说明

让数据库服务器关闭。连接的用户必须有shutdown权限。

20.4.46.2 返回值

成功，零。如果出现一个错误，非零

20.4.46.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.47 mysql_stat()

char *mysql_stat(MYSQL *mysql)

20.4.47.1 说明

返回包含类似于由mysqladmin status命令提供的信息的一个字符串。它包括正常运行的秒数和正在运行线程、问题、再次装载和打开的表的数目。

20.4.47.2 返回值

描述服务器状态的一个字符串。如果出现一个错误，NULL。

20.4.47.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.48 mysql_store_result()

MYSQL_RES *mysql_store_result(MYSQL *mysql)

20.4.48.1 说明

对于成功地检索数据的每个询问(SELECT、SHOW、DESCRIBE、EXPLAIN)，你必须调用mysql_store_result()或mysql_use_result()。

mysql_store_result()读取一个到客户的查询的全部结果，分配一个MYSQL_RES结构，并且把结果放进这个结构中。

如果没有行返回，返回一个空集合集合。（空结果集合不同于一个NULL返回值。）

一旦你调用了mysql_store_result()，你可以调用mysql_num_rows()找出结果集合中有多少行。

你能调用mysql_fetch_row()从结果集合中取出行，或mysql_row_seek()和mysql_row_tell()结果集合中获得或设置当前的行位置。

一旦你用完结果集合，你必须调用mysql_free_result()。

见20.4.51 为什么mysql_query()返回成功后，mysql_store_result()有时返回NULL?。

20.4.48.2 返回值

一个保存结果的MYSQL_RES结构。如果出现一个错误，NULL。

20.4.48.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_OUT_OF_MEMORY
内存溢出。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.49 mysql_thread_id()

unsigned long mysql_thread_id(MYSQL *mysql)

20.4.49.1 说明

返回当前连接的线程ID。这个值可用作mysql_kill()的一个参数以杀死线程。

如果失去连接并且你用mysql_ping()重新连接，线程ID将改变。这意味着你不应该为以后使用获得线程ID并且存储它，当你需要它时，你应该获得它。

20.4.49.2 返回值

当前连接的线程 ID 。

20.4.49.3 错误

无。

20.4.50 mysql_use_result()

MYSQL_RES *mysql_use_result(MYSQL *mysql)

20.4.50.1 说明

对于成功地检索数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN)，你必须调用mysql_store_result()或mysql_use_result()。

mysql_use_result()初始化一个结果集合的检索，但不真正将结果集合读入客户，就象mysql_store_result()那样。相反，必须通过调用mysql_fetch_row()单独检索出每一行，这直接从服务器读出结果而不在一个临时表或本地缓冲区中存储它，它比mysql_store_result()更快一点并且使用较少的内存。客户将只为当前行和一个可能最大max_allowed_packet字节的通信缓冲区分配内存。

在另一方面，如果你在客户端对每一行正在做很多的处理，或如果输出被送到屏幕，用户可以打一个^S（停止滚动)，你不应该使用mysql_use_result()。这将阻塞服务器并且阻止另外的线程从数据被取出的任何表中更新数据。

当使用mysql_use_result()时，你必须执行mysql_fetch_row()直到返回一个NULL值，否则未取出的行将作为下一个查询的结果集合一部分被返回。如果你忘记做这个，C API将给出错误Commands out of sync; You can't run this command now！

你不能在一个从mysql_use_result()返回的结果集合上使用mysql_data_seek()、mysql_row_seek()、mysql_row_tell()、mysql_num_rows()或mysql_affected_rows()，你也不能发出另外的查询直到mysql_use_result()完成。（然而，在你取出所有的行以后，mysql_num_rows()将精确地返回取出的行数。）

一旦你用完结果集合，你必须调用mysql_free_result()。

20.4.50.2 返回值

一个MYSQL_RES结果结构。 如果发生一个错误发生，NULL。

20.4.50.3 错误

CR_COMMANDS_OUT_OF_SYNC
命令以一个不适当的次序被执行。
CR_OUT_OF_MEMORY
内存溢出。
CR_SERVER_GONE_ERROR
MySQL服务器关闭了。
CR_SERVER_LOST
对服务器的连接在查询期间失去。
CR_UNKNOWN_ERROR
发生一个未知的错误。

20.4.51 为什么在mysql_query()返回成功后，mysql_store_result()有时返回NULL?

有可能在一个对mysql_query()成功的调用后，mysql_store_result()返回NULL。当这发生时，它意味着出现了下列条件之一：

  • 有一个malloc()失败(例如，如果结果集合太大)。
  • 数据不能被读取(发生在连接上的一个错误)。
  • 查询没有返回数据(例如，它是一个INSERT、UPDATE或DELETE)。

你总是可以通过调用mysql_field_count()检查语句是否应该产生非空的结果。如果mysql_field_count()返回零，结果是空的并且最后一个查询是不回值的一条语句(例如，一条INSERT或DELETE)。如果mysql_field_count()返回非零值，语句应该产生非空的结果。见对mysql_field_count()描述的一个例子。

你可以调用mysql_error()或mysql_errno()测试一个错误。

20.4.52 我能从查询中得到什么结果？

除了由查询返回的结果集合外，你也能得到下列信息：

  • 当执行一条INSERT、UPDATE或DELETE时，mysql_affected_rows()返回受到最后一个查询影响的行数。一个例外是如果使用一条没有WHERE子句的DELETE，表被截断，它更快！在这种情况下，mysql_affected_rows()对于影响的记录数量返回零。
  • mysql_num_rows()返回结果集合中的行数。用mysql_store_result()，一旦mysql_store_result()返回，就可以调用mysql_num_rows()。用mysql_use_result()，只有在你已经用mysql_fetch_row()取出了所有行后，才能调用mysql_num_rows()。
  • mysql_insert_id()返回由将一行插入一个具有AUTO_INCREMENT索引的表中的最后查询生成的ID。见20.4.29 mysql_insert_id()。
  • 某些查询(LOAD DATA INFILE ...、INSERT INTO ... SELECT ...、UPDATE)返回附加的信息。结果由返mysql_info()返回。对其返回字符串的格式，见mysql_info()的描述。如果没有附加的信息，mysql_info()返回一个NULL指针。

20.4.53 我怎样能得到最后插入的行的唯一ID？

如果你往包含一个具有AUTO_INCREMENT属性的列的一张表中插入一个记录，你能通过mysql_insert_id()函数获得最近生成的ID。

你也可以通过在你传递给mysql_query()的一个查询字符串中使用LAST_INSERT_ID()函数检索出ID。

你可以执行下列代码检查是否使用一个AUTO_INCREMENT索引。这也检查查询是否是有一个AUTO_INCREMENT索引的一条INSERT：

if (mysql_error(&mysql)[0] == 0 &&
    mysql_num_fields(result) == 0 &&
    mysql_insert_id(&mysql) != 0)
{
    used_id = mysql_insert_id(&mysql);
}

最近产生的ID是在一个按连接的基础上在服务器上进行维护，它将不被其他客户改变。如果你更新另外一个有非奇特(non-magic)值(即一个既不是NULL也不是0的值)的AUTO_INCREMENT列，它甚至将不被改变。

如果你想要使用为一张表生成的ID并且把它插入到第2张表，你可以使用象这样的SQL语句：

INSERT INTO foo (auto,text)
    VALUES(NULL,'text');              # generate ID by inserting NULL
INSERT INTO foo2 (id,text)
    VALUES(LAST_INSERT_ID(),'text');  # use ID in second table

20.4.54 链接C API的问题

当与C API链接时，下列错误可能发生一些系统上：

gcc -g -o client test.o -L/usr/local/lib/mysql -lmysqlclient -lsocket -lnsl

Undefined        first referenced
 symbol          in file
floor            /usr/local/lib/mysql/libmysqlclient.a(password.o)
ld: fatal: Symbol referencing errors. No output written to client

如果它发生在你的系统上，你必须通过在编译/链接命令行的最后增加-lm以包括数学库。

20.4.55 怎样制作一个线程安全的客户

客户“几乎”是线程安全的。最大的问题是在从套接字读取的“net.c”中的子程序不是中断安全的(interruot-safe)。这样做是这样考虑的，即你可能想有你自己的报警来中断一个长时间的读取服务器。

标准客户库没有用线程选项来编译。

为了获得一个线程安全的客户，使用-lmysys, -lstring和-ldbug库和服务器使用的net_serv.o。

当使用一个线程化的客户时，你可以充分利用在“thr_alarm.c”文件中的函数。如果你正在使用来自mysys库的函数，你唯一必须记住的是首先调用my_init()！

所有函数除了mysql_real_connect()目前是线程安全的。下列注意事项描述怎样编译一个线程安全的客户库并且以一种线程安全的方式使用它。（下面对mysql_real_connect()的注意事项实际上也适用于mysql_connect()，但是因为mysql_connect()不提倡使用，无论如何你应该使用mysql_real_connect()。）

为了使mysql_real_connect()是线程安全的，你必须用这个命令重新编译客户库：

shell> CPPFLAGS=-DTHREAD_SAFE_CLIENT ./configure ...

当链接标准客户时，你可能得到的某些因为未定义符号的错误，因为pthread库没有被缺省地包括。

最终的“libmysqlclient.a”库现在是线程安全的。它的含义是只要2个线程不同时查询mysql_real_connect()返回的同一个连接句柄，客户代码是线程安全的；客户机/服务器协议在一个给定的连接上一次只允许一个请求。如果你想在同一个的连接上使用多个线程，你必须在mysql_query()和mysql_store_result()调用组合附近有一个mutex锁定。一旦mysql_store_result()就绪，锁可以被释放并且其他线程可以查询同一个连接。（换句话说，不同的线程能使用不同被mysql_store_result()创建的MYSQL_RES指针，只要他们使用适当的锁定协议) 如果你用POSIX线程编程，你能使用pthread_mutex_lock()和pthread_mutex_unlock()建立并且释放一个mutex锁定。

如果你使用mysql_use_result()而不是mysql_store_result()，锁定将需要包围mysql_use_result()和mysql_fetch_row()的调用，然而，它确实对不使用mysql_use_result()线程客户是最好的。

20.5 MySQL Perl API

本节记载了Perl DBI接口。以前的接口被称为mysqlperl。因为DBI/DBD现在是推荐的Perl接口，mysqlperl是过时的并且不在这里记载。

20.5.1 DBI与DBD::mysql

DBI是对于很多数据库的一个通用接口。这意味着你能编写一个脚本，不用改变就能工作于很多数据库引擎。你需要为每种数据库类型定义了的一个数据库驱动程序(DBD)。对于MySQL，该驱动程序称为DBD::mysql。

有关Perl5 DBI的更多信息，请访问DBI网页并且阅读文档：

http://www.symbolstone.org/technology/perl/DBI/index.html

关于在Perl5定义的面向对象的编程(OOP)的更多信息，参见Perl OOP页：

http://language.perl.com/info/documentation.html

对于MySQL Perl支持的安装指令在4.10 Perl安装说明中给出。

20.5.2 DBI接口

可移植的DBI方法

connect | 建立到一个数据库服务器的连接
disconnect | 断开数据库服务器的连接
prepare | 准备执行一个SQL语句
execute | 执行准备好的语句
do | 准备并执行一个SQL语句
quote | 加引号于要插入的字符串或BLOB值
fetchrow_array | 作为一个字段数组取出下一行
fetchrow_arrayref | 作为一个字段的引用数组取出下一行
fetchrow_hashref | 作为一个哈希表的引用取出下一行
fetchall_arrayref | 作为一个字段数组取出所有数据
finish | 完成一条语句并且让系统释放资源
rows | 返回受影响的行数
data_sources | 返回可在localhost上得到的数据库的数组
ChopBlanks | 控制fetchrow_*方法是否剥去空格
NUM_OF_PARAMS | 在准备的语句中的占位（placeholder-参数）的数目
NULLABLE | 其列可以是NULL
trace | 执行调试跟踪

MySQL特定的方法

insertid | 最后一个AUTO_INCREMENT值
is_blob | 该列是BLOB值
is_key | 该列是键
is_num | 该列是数字的
is_pri_key | 该列是主键
is_not_null | 该列不能是NULL，见NULLABLE。
length | 最大可能的列大小
max_length | 结果中实际上存在的最大列大小
NAME | 列名字
NUM_OF_FIELDS | 返回的字段数目
table | 在返回的集合中的表名
type | 所有的列类型

Perl方法在下一节更详细地描述。用于方法返回值的变量有这些含义：

$dbh
数据库句柄
$sth
语句句柄
$rc
返回代码 (经常是一个状态）
$rv
返回值 (经常是一个行数）

可移植DBI方法

connect($data_source, $username, $password)
使用connect方法使得一个数据库连接到数据源。$data_source值应该以DBI:driver_name:开始。以DBD::mysql驱动程序使用connect的例子：
$dbh = DBI->connect("DBI:mysql:$database", $user, $password);
$dbh = DBI->connect("DBI:mysql:$database:$hostname",
                    $user, $password);
$dbh = DBI->connect("DBI:mysql:$database:$hostname:$port",
                    $user, $password);

如果用户名或口令未定义，DBI分别使用DBI_USER和DBI_PASS环境变量的值。如果你不指定主机名，它缺省为'localhost'。如果你不指定一个端口号，它缺省为MySQL的缺省端口(3306)。对Msql-Mysql-modules版本1.2009，$data_source值允许某些修饰词：

mysql_read_default_file=file_name
读取作为一个选项文件的“filename”。有关选项文件的信息，见4.15.4 选项文件。
mysql_read_default_group=group_name
当读取选项文件时的缺省组通常是[client]组。通过指定mysql_read_default_group选项，缺省组变成[group_name]组。
mysql_compression=1
在客户和服务器之间使用压缩通信(MySQL 3.22.3或以后)。
mysql_socket=/path/to/socket
指定用于与服务器连接的Unix套接字的路径名(MySQL 3.21.15或以后)。

可以给出多个修饰词；每一个必须前置一个分号。例如，如果你想要避免在一个DBI脚本中硬编码用户名和口令，你可以从用户的“~/.my.cnf”选项文件中取出它们，而不是这样编写你的connect调用：

$dbh = DBI->connect("DBI:mysql:$database"
                . ";mysql_read_default_file=$ENV{HOME}/.my.cnf",
                $user, $password);

这个调用将读取在选项文件中为[client]组而定义的选项。如果你想做同样的事情，但是也使用未[perl]组指定的选项，你可以使用：

$dbh = DBI->connect("DBI:mysql:$database"
                . ";mysql_read_default_file=$ENV{HOME}/.my.cnf"
                . ";mysql_read_default_group=perl",
                $user, $password);
disconnect
disconnect方法从数据库断开数据库句柄。它一般就在你从程序退出之前被调用。范例：
$rc = $dbh->disconnect;
prepare($statement)
准备一条由数据库引擎执行的SQL语句并且返回语句句柄($sth)，你可以使用它调用execute方法。一般地你借助于prepare和execute来处理SELECT语句(和类SELECT语句，例如SHOW、DESCRIBE和EXPLAIN)。范例：
$sth = $dbh->prepare($statement)
    or die "Can't prepare $statement: $dbh->errstr\n";
execute
execute方法执行一个准备好的语句。对非SELECT语句，execute返回受影响的行数。如果没有行受影响，execute返回"0E0"，Perl将它视作零而不是真。对于SELECT语句，execute只是在数据库中启动SQL查询；你需要使用在下面描述的fetch_*方法之一检索数据。范例：
$rv = $sth->execute
          or die "can't execute the query: $sth->errstr;
do($statement)
do方法准备并且执行一条SQL语句并且返回受影响的行数。如果没有行受到影响，do返回"0E0"，Perl将它视为零而不是真。这个方法通常用于事先无法准备好(由于驱动程序的限制)或不需要执行多次(插入、删除等等)的非SELECT语句。范例：
$rv = $dbh->do($statement)
        or die "Can't execute $statement: $dbh- >errstr\n";
quote($string)
quote方法被用来“转义”包含在string中的任何特殊字符并增加所需的外部的引号。范例：
$sql = $dbh->quote($string)
fetchrow_array
这个方法取下一行数据并且作为一个字段值数组返回它。范例：
while(@row = $sth->fetchrow_array) {
        print qw($row[0]\t$row[1]\t$row[2]\n);
}
fetchrow_arrayref
这个方法取下一行数据并且作为一个对一个字段值数组的引用返回它。范例：
while($row_ref = $sth->fetchrow_arrayref) {
        print qw($row_ref->[0]\t$row_ref->[1]\t$row_ref->[2]\n);
}
fetchrow_hashref
这个方法取一行数据并且返回包含字段名/值对的一个哈希表的一个引用。这个方法不如使用上述数组引用那样有效。范例：
while($hash_ref = $sth->fetchrow_hashref) {
        print qw($hash_ref->{firstname}\t$hash_ref->{lastname}\t\
                $hash_ref- > title}\n);
}
fetchall_arrayref
这个方法被用来获得从SQL语句被返回的所有数据(行)。它返回一个数组的引用，该数组包含对每行的数组的引用。你用一个嵌套循环来存取或打印数据。范例：
my $table = $sth->fetchall_arrayref
                or die "$sth->errstr\n";
my($i, $j);
for $i ( 0 .. $#{$table} ) {
        for $j ( 0 .. $#{$table->[$i]} ) {
                print "$table->[$i][$j]\t";
        }
        print "\n";
}
finish
便名没有更多的数据将从这个语句句柄取出。你调用这个方法释放语句句柄和任何与它相关的系统资源。范例：
$rc = $sth->finish;
rows
返回由最后一条命令改变(更新、删除等)的行数。这通常用在非SELECT的execute语句之后。范例：
$rv = $sth->rows;
NULLABLE
返回一个对一个布尔值数组的引用；对数组的每个成员，一个TRUE值表示该列可以包含NULL值。范例：
$null_possible = $sth->{NULLABLE};
NUM_OF_FIELDS
这个属性表明由一条SELECT或SHOW FIELDS语句返回的字段数目。你可以用它检查一条语句是否返回了结果：一个零值表明一个象INSERT、DELETE或UPDATE的非SELECT语句。范例：
$nr_of_fields = $sth->{NUM_OF_FIELDS};
data_sources($driver_name)
这个方法返回一个数组，它包含在主机'localhost'上的MySQL服务器可得到的数据库名。范例：
@dbs = DBI->data_sources("mysql");
ChopBlanks
这个属性确定fetchrow_*方法是否将去掉返回值的头和尾的空白。范例：
$sth->{'ChopBlanks'} =1;
trace($trace_level)

trace($trace_level, $trace_filename)
trace方法开启或关闭跟踪。当作为一个DBI类方法调用时，它影响对所有句柄的跟踪。当作为一个数据库或语句句柄方法调用时，它影响对给定句柄的跟踪(和句柄的未来子孙)。设置$trace_level为2以提供详细的踪迹信息，设置$trace_level为0以关闭跟踪。踪迹输出缺省地输出到标准错误输出。如果指定$trace_filename，文件以添加模式打开并且所有跟踪的句柄的手被写入该文件。范例：
DBI->trace(2);                # trace everything
DBI->trace(2,"/tmp/dbi.out"); # trace everything to /tmp/dbi.out
$dth->trace(2);               # trace this database handle
$sth->trace(2);               # trace this statement handle

你也可以通过设置DBI_TRACE环境变量开启DBI跟踪。将它设置为等价于调用DBI->(value)的数字值，将它设置为等价于调用DBI->(2,value)的路径名。

MySQL特定的方法

下面显示的方法是MySQL特定的并且不是DBI标准的部分。他们中有几个现在不建议使用：is_blob、is_key、is_num、is_pri_key、is_not_null、length、max_length和table。这些已有DBI标准的另一种方法存在，他们在下面说明。

insertid
如果你使用MySQL的AUTO_INCREMENT功能，新的自动加1的值将存储在这里。范例：
$new_id = $sth->{insertid};

作为另一种选择，你可以使用$dbh->{'mysql_insertid'}。

is_blob
返回一个对一个布尔值数组的引用；对数组的每个单元，一个TRUE值表明相应的列是一个BLOB。范例：
$keys = $sth->{is_blob};
is_key
返回一个对一个布尔值数组的引用；对数组的每个单元，一个TRUE值表明相应的列是键。范例：
$keys = $sth->{is_key};
is_num
返回一个对一个布尔值数组的引用；对数组的每个单元，一个TRUE值表明相应的列包含数字值。范例：
$keys = $sth->{is_key};
is_pri_key
返回一个对一个布尔值数组的引用；对数组的每个单元，一个TRUE值表明相应的列是主键。范例：
pri_keys = $sth->{is_pri_key};
is_not_null
返回一个对一个布尔值数组的引用；对数组的每个单元，一个FALSEE值表明该列可以包含NULL值。范例：
$not_nulls = $sth->{is_not_null};

is_not_null不建议使用；最好使用NULLABLE属性(在上面描述了)，因为那是一个 DBI 标准。

length

max_length
这些方法的每个返回一个对列大小数组的引用。length数组指出每列可以有的最大可能的尺寸 (如在表描述中声明的)。max_length数组指出在结果表中实际存在的最大尺寸。范例：
$lengths = $sth->{length};
$max_lengths = $sth->{max_length};
NAME
返回一个对一个列名数组的引用。范例：
$names = $sth->{NAME};
table
返回一个对一个表名数组的引用。范例：
$tables = $sth->{table};
type
返回一个对一个列类型数组的引用。范例：
$types = $sth->{type};

20.5.3 更多的DBI/DBD信息

你可以使用perldoc命令得到更多的关于DBI的信息。

perldoc DBI
perldoc DBI::FAQ
perldoc DBD::mysql

你也可以使用pod2man、pod2html等工具转换到其他格式。

而且你当然可以在DBI网页中找到最新的DBI信息：

http://www.symbolstone.org/technology/perl/DBI/index.html

20.6 MySQL Eiffel包装

MySQL Contrib目录包含Michael Ravits编写的一个Eiffel包装程序。

你也能在这里找到：http://www.netpedia.net/hosting/newplayer/

20.7 MySQL Java连接(JDBC)

有2个为MySQL支持的JDBC驱动程序(twz和mm驱动程序)。你可以在http://www.mysql.com/Contrib找到这些的一个拷贝。对于文档，请教任何JDBC文档和驱动程序本身拥有的针对MySQL特定功能的文档。

20.8 MySQL PHP API

PHP是一个服务器端、HTML嵌入式脚本语言，可以用来创建动态网页。它包含对存取若干数据库的支持，包括MySQL。PHP可以作为一个单独的程序运行，或编译为与Apache服务器一起使用的一个模块。

分发和文档可在PHP网站得到。

20.9 MySQL C++ APIs

在MySQL Contrib 目录中可得到两个API。

20.10 MySQL Python API

MySQL Contrib 目录包含Joseph Skinner编写的一个Python接口。

你也可以使用对iODBC的Python接口来存取一个MySQL服务器。mxODBC

20.11 MySQL TCL API

TCL at binevolve。Contrib 目录包含一个基于msqltcl 1.50的一个TCL接口。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL中文参考手册-21 如何比较MySQL与其他数据库

翻译：晏子(yanzi) 主页：http://linuxdb.yeah.net

21 怎样对比MySQL与其他数据库

21.1 怎样对比MySQL与mSQL

这一节由MySQL开发者编写，因此应该理智地阅读它，但是没有我们听说的事实错误。

对于所有支持的限制、函数和类型的一个列表，看crash-me网页。

性能
对于速度的真实比较，请教不断成熟的MySQL基准套件。见10.8 使用你自己的基准。因为没有线程创建开销、一个较小的语法分析器、较少功能和简单的安全性，mSQL应该在下列方面更快些：
  • 执行重复的连接和断开的测试，在每个连接期间运行一个非常简单的查询。
  • 有很少的列和键的插入很简单的表的INSERT操作。
  • CREATE TABLE和DROP TABLE。
  • 在不是一个索引的一些东西上SELECT。（一个表扫描是很容易的。）

因为这些操作是如此简单，当你有更高的启动开销时，很难在这些方面变得更好。在连接被建立以后，MySQL应该性能好一些。在另一方面，MySQL比mSQL（以及大多数其他的SQL实现)在下列方面更好些：

  • 复杂的SELECT操作。
  • 检索较大的结果(MySQL有一个更好、更快并且更安全的协议)。
  • 有变长字符串的表，因为MySQL有更有效的并可在VARCHAR列上索引。
  • 有很多列的表的处理。
  • 由长记录的表的处理。
  • 有很多许多表达式的SELECT。
  • 在大表上的SELECT。
  • 同时处理很多连接。MySQL充分是完全多线程化的，每个连接有它自己的线程，这意味着没有线程必须等待另一个线程(除非一个线程正在修改一张表，另外的线程想要存取)在mSQL中，一旦一个连接被建立了，所有其它线程必须等到第一个线程完成，不管连接正在运行的查询是短的或是长的。当第一个连接终止时，下一个才能工作，而此时所有其它线程再次等待，等等。
  • 联结。如果你改变一个SELECT中的表的顺序，mSQL可能变得异常地慢。在基准套件中，比MySQL要慢超过15000倍的时间。这是由于mSQL缺乏一个联结优化器以便以最佳的顺序排定表。然而，如果你把表按完全正确的顺序放在mSQL2中并且WHERE是很简单的并使用索引列，联结将相对快些！见10.8 使用你自己的基准。
  • ORDER BY和GROUP BY。
  • DISTINCT。
  • 使用TEXT或BLOB列。
SQL功能
  • GROUP BY和HAVING。mSQL根本不支持GROUP BY。MySQL支持一个有两个HAVING和下列函数： COUNT()、AVG()、MIN()、MAX()、SUM()和STD()的完整的GROUP BY。如果SELECT从一张表中检索，没有其他列被检索并且没有WHERE子句，COUNT(*)被优化以很快地返回。 MIN()和MAX()可以取字符串参数。
  • 带计算的INSERT和UPDATE。MySQL能在一个INSERT或UPDATE中做计算。例如：
    mysql> UPDATE SET x=x*10+y WHERE x<20;
  • 别名。MySQL有列的别名。
  • 限制列名。在MySQL中，如果一个列名在用于查询的表之间唯一的，你不必须使用完整的 合格者。
  • 带函数的SELECT。MySQL有很多函数(太多不能在这里列出；见7.4 用在SELECT和WHERE子句中的函数)。
磁盘空间效率
即，你能使你的表有多小？MySQL有很精确的类型，因此你可以创建占据很小空间的表。一个有用的MySQL数据类型的例子是MEDIUMINT，它是3个字节长。如果你有100,000,000个记录，每个记录节省甚至一个字节也是很重要的。mSQL2有一个较有限的列类型集合，因此更难于使表更小。
稳定性
这较难客观地评价。对于MySQL稳定性的讨论，见1.5 MySQL有多么稳定？。我们没有mSQL稳定性的经验，因此我们对此不能说任何东西。
价格
另一个重要的问题是许可证。MySQL有一个比mSQL更灵活的许可证，并且也不比mSQL昂贵。无论你选择使用哪个产品，记得要至少考虑支付一个许可证或电子邮件支持的费用。（当然如果你把你出售的一个产品包括在MySQL中，你将被要求获得一个许可证。）
Perl接口
MySQL有与mSQL基本相同Perl接口，当有一些增加的功能。
JDBC ( Java ）
MySQL目前有4个JDBC驱动程序：
  • gwe 驱动程序：由GWE technologies 开发的一个Java接口(不再支持)。
  • jms 驱动程序：由Xiaokun Kelvin ZHU的开发的一个改进的gwe驱动程序。
  • twz 驱动程序：由Terrence W. Zellers 开发的一个type 4 JDBC驱动程序并用于学习目的。
  • mm 驱动程序：由Mark Matthews 开发的一个type 4 JDBC驱动程序。

推荐的驱动程序是twz或mm驱动程序。两者均被报导工作出色。我们知道mSQL有一个 JDBC 驱动程序，但是我们对它有太少的经验不能进行比较。

开发速度
MySQL有一个非常小的开发者队伍，但是我们是非常习惯于用C和C++编码，非常快速。因为线程、函数、GROUP BY等在mSQL中仍未实现，它有很多追赶工作要做。要想得到关于它的一些前景，你可以查看mSQL最后一年的 “HISTIRY”文件，并将它与MySQL参考书手册的新功能小节比较(见D MySQL变迁历史)。哪个快开发得最快应该是相当明显的。
实用程序
mSQL和MySQL都有许多有趣的第三方工具。因为向上移植(从mSQL到MySQL)是很容易的，几乎所有mSQL可用的有趣的应用程序也可被MySQL使用。MySQL带有一个简单的msql2mysql程序修正在mSQL和MySQL使用的大多数C API函数之间拼写差别。例如，它将msqlConnect()实例改变为mysql_connect()。变换一个客户程序从mSQL到MySQL通常花几分钟时间。

21.1.1 怎样将mSQL的工具转换到MySQL

根据我们的经验，转换诸如使用mSQL C API的msql-tcl和msqljava工具将只花不大一小时时间，使得他们用MySQL C API工作。

转换过程是：

  1. 在源代码上运行外壳脚本msql2mysql。这需要replace程序，它与MySQL一起散发。
  2. 编译。
  3. 修正所有编译器错误。

mSQL C API与MySQL C API 之间差别是：

  • MySQL使用一个MYSQL结构作为一种连接类型(mSQL使用一个int)。
  • mysql_connect()取一个指向一个MYSQL结构的指针作为一个参数。很容易定义全局性定义一个或使用malloc()获得一个。mysql_connect()也取两个参数指定用户和口令。你可以为了缺省使用将这些设置为NULL,NULL。
  • mysql_error()取MYSQL结构作为一个参数。如果你正在移植老的代码，只是把参数加到你的老的msql_error()编码中。
  • MySQL对所有错误返回一个错误号和一条文本错误消息。mSQL仅返回一条文字错误消息。
  • 存在某些不兼容性，因为MySQL支持从同一个进程的到服务器多个连接。

21.1.2 mSQL和MySQL的客户机/服务器通讯协议有何不同

有足够的差别使得不可能(或至少不容易)支持两者。

它MySQL协议不同于mSQL协议的最重要的方面列在下面：

  • 一个消息缓冲区可以包含很多结果行。
  • 如果查询或结果比当前缓冲区大，消息缓冲区动态地被扩大，直到一个可配置的服务器和客户上限。
  • 所有的包被编号以捕捉重复或丢失的包。
  • 所有的列值以ASCII码发送。列和行的长度以紧凑的二进制编码(1、2或3个字节)发送。
  • MySQL能在未缓冲得结果中读取(不必在客户端存储完整的集合)。
  • 如果一个单独写/读花了超过30秒时间，服务器关闭连接。
  • 如果一个连接空闲8个小时，服务器关闭连接。

21.1.3 mSQL 2.0的SQL句法与MySQL有何不同

列类型

MySQL
有下列额外的类型(比较其他的；见7.7 CREATE TABLE句法)： 、
  • 对于一个字符串集中之一的ENUM类型。
  • 对于一个字符串集中多个的SET类型。
  • 对于64位整数的BIGINT类型。
MySQL也支持下列额外的类型属性：
  • UNSIGNED选项。
  • 对于整数列的ZEROFILL选项。
  • 对于是一个PRIMARY KEY的整数列的AUTO_INCREMENT选项。见20.4.29 mysql_insert_id()。
  • 对所有列的DEFAULT值。
mSQL2
mSQL列类型对应于MySQL类型显示在下面：
mSQL 类型 | 相应的MySQL类型
CHAR(len) | CHAR(len)
TEXT(len) | TEXT(len)，len是最大长度。并且LIKE可运用。
INT | INT，有很多的选项！
REAL | REAL，或FLOAT。有4和8字节版本。
UINT | INT UNSIGNED
DATE | DATE，使用 ANSI SQL 格式而非mSQL自己的。
TIME | TIME
MONEY | DECIMAL(12,2)，有2个小数位的定点值。

索引创建

MySQL
索引可以在表创建时用CREATE TABLE语句指定。
mSQL
在表被创建了以后，索引必须被创建，用单独的CREATE INDEX语句。

把一个唯一标识符插入到一张表中

MySQL
使用AUTO_INCREMENT作为列类型修饰符。见20.4.29 mysql_insert_id()。
mSQL
在一张表上创建一个SEQUENCE并且选择_seq列。

为行获得一个唯一标识符

MySQL
向表中增加一个PRIMARY KEY或UNIQUE键。
mSQL
使用_rowid列。注意_rowid可以将来改变，取决于很多因素。

得到列最后被修改的时间

MySQL
在表中增加一个TIMESTAMP列。如果你不给出列值或如果你给它一个NULL值，该列自动为INSERT或UPDATE语句设置为当前的日期和时间。
mSQL
使用_timestamp列。

NULL值的比较

MySQL
MySQL遵从ANSI SQL且与NULL的比较总是NULL。
mSQL
在mSQL中，NULL = NULL是TRUE（真）。当从mSQL到MySQL移植老的代码时，你必须将=NULL改委IS NULL，并将<>NULL改为IS NOT NULL。

字符串的比较

MySQL
通常，字符串比较以大小写无关方式按当前字符集(缺省为ISO-8859-1 Latin1)决定的排序次序实施。如果你不喜欢这样，声明你的列有BINARY属性，它使得比较根据用在MySQL服务器主机上的ASCII顺序进行。
mSQL
所有的字符串比较以大小写敏感的方式以ASCII顺序排序来进行。

大小写不敏感的搜索

MySQL
LIKE是一个大小写不敏感或大小写敏感的运算符，这取决于涉及的列。如果LIKE参数不以一个通配符字符开始，如有可能，MySQL则使用索引。
mSQL
使用CLIKE。

尾部空格的处理

MySQL
剥去CHAR和VARCHAR列尾部的空格。如果不希望这种行为，使用一个TEXT行列。
mSQL
保留尾部的空格。

WHERE子句

MySQL
MySQL正确地优先化任何东西(AND在OR前计算)。要想在MySQL里得到mSQL的行为，使用括号(如下所示)。
mSQL
从左到右计算任何东西。这意味着超过3个参数的一些逻辑运算不能以任何方式表示，它也意味着当你升级到MySQL时，你必须改变一些查询。你通过增加括号很容易做到这点。假定你有下列mSQL查询：
mysql> SELECT * FROM table WHERE a=1 AND b=2 OR a=3 AND b=4;

为了使MySQL像mSQL那样计算它，你必须增加括号：

mysql> SELECT * FROM table WHERE (a=1 AND (b=2 OR (a=3 AND (b=4))));

存取控制

MySQL
有表来存储对每个用户、主机和数据库的授权(许可)选项。见6.6 权限系统如何工作。
mSQL
有一个文件“mSQL.acl”，在哪里你能为用户授权读/写权限。

21.2 怎样对比MySQL与PostgreSQL

PostgreSQL有一些更高级的功能如定义用户类型、触发器、规则和一些事务支持。然而，PostgreSQL 缺乏很多来自 ANSI SQL和ODBC的很多标准类型和函数。对于一个完整的限制列表及其支持或不支持哪一个类型和函数，见crash-me网页。

通常，PostgreSQL是比MySQL慢很多。见10.8 使用你自己的基准。这大部分是由于他们的事务系统。如果你确实需要事务或PostgreSQL提供的丰富的类型体系并且你能承受速度的损失，你应该看看 PostgreSQL。

第一章, 前一章, 下一章, 最后一章，目录.


MySQL Reference Manual for version 3.23.7-alpha. - E Known errors and design deficiencies in MySQL

Go to the first, previous, next, last section, table of contents.

E Known errors and design deficiencies in MySQL

  • You cannot build in another directory when using MIT-pthreads. Since this requires changes to MIT-pthreads, we are not likely to fix this.
  • BLOB values can't ``reliably'' be used in GROUP BY or ORDER BY or DISTINCT. Only the first max_sort_length bytes (default 1024) are used when comparing BLOBbs in these cases. This can be changed with the -O max_sort_length option to mysqld. A workaround for most cases is to use a substring: SELECT DISTINCT LEFT(blob,2048) FROM tbl_name.
  • Calculation is done with BIGINT or DOUBLE (both are normally 64 bits long). It depends on the function which precision one gets. The general rule is that bit functions are done with BIGINT precision, IF, and ELT() with BIGINT or DOUBLE precision and the rest with DOUBLE precision. One should try to avoid using bigger unsigned long long values than 63 bits (9223372036854775807) for anything else than bit fields!
  • All string columns, except BLOB and TEXT columns, automatically have all trailing spaces removed when retrieved. For CHAR types this is okay, and may be regarded as a feature according to ANSI SQL92. The bug is that in MySQL, VARCHAR columns are treated the same way.
  • You can only have up to 255 ENUM and SET columns in one table.
  • safe_mysqld re-directs all messages from mysqld to the mysqld log. One problem with this is that if you execute mysqladmin refresh to close and reopen the log, stdout and stderr are still redirected to the old log. If you use --log extensively, you should edit safe_mysqld to log to `'hostname'.err' instead of `'hostname'.log' so you can easily reclaim the space for the old log by deleting the old one and executing mysqladmin refresh.
  • In the UPDATE statement, columns are updated from left to right. If you refer to a updated column, you will get the updated value instead of the original value. For example:
    mysql> UPDATE tbl_name SET KEY=KEY+1,KEY=KEY+1

    will update KEY with 2 instead of with 1.

  • You can't use temporary tables more than once in the same query.
    select * from temporary_table, temporary_table as t2;

The following is known bugs in earlier versions of MySQL:

  • Before MySQL 3.23.2 an UPDATE that updated a key with a WHERE on the same key may have failed because the key was used to search for records and the same row may have been found multiple times:
    UPDATE tbl_name SET KEY=KEY+1 WHERE KEY > 100;

    A workaround is to use:

    mysql> UPDATE tbl_name SET KEY=KEY+1 WHERE KEY+0 > 100;

    This will work because MySQL will not use index on expressions in the WHERE clause.

  • Before MySQL 3.23 all numeric types where treated as fixed-point fields. That means you had to specify how many decimals a floating-point field shall have. All results was returned with the correct number of decimals.

For platform-specific bugs, see the sections about compiling and porting.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - Concept Index

Go to the first, previous, next, last section, table of contents.

Concept Index

A

  • Adding native functions
  • Adding user-definable functions
  • Alias names, case sensitivity
  • Aliases, for expressions
  • Aliases, for tables
  • Aliases, in GROUP BY clauses
  • Aliases, in ORDER BY clauses
  • Aliases, on expressions
  • Anonymous user, Anonymous user, Anonymous user
  • ANSI SQL, differences from
  • Arithmetic expressions
  • AUTO_INCREMENT, and NULL values

    • B

  • Backups
  • Big5 Chinese character encoding
  • BLOB columns, default values
  • BLOB columns, indexing
  • BLOB, inserting binary data
  • Bug reports

    • C

  • C++ compiler cannot create executables
  • Case sensitivity, in access checking
  • Case sensitivity, in searches
  • Case sensitivity, in string comparisons
  • Case sensitivity, of alias names
  • Case sensitivity, of column names
  • Case sensitivity, of database names, Case sensitivity, of database names
  • Case sensitivity, of table names, Case sensitivity, of table names
  • Casts
  • cc1plus problems
  • Checking tables for errors
  • Chinese
  • Choosing table types
  • Choosing types
  • Choosing version
  • Client programs, building
  • Column names, case sensitivity
  • Command line history
  • Commands out of sync
  • Compatibility, between MySQL versions, Compatibility, between MySQL versions
  • Compatibility, with ANSI SQL
  • Compatibility, with mSQL
  • Compatibility, with ODBC, Compatibility, with ODBC, Compatibility, with ODBC, Compatibility, with ODBC, Compatibility, with ODBC, Compatibility, with ODBC
  • Compatibility, with Oracle, Compatibility, with Oracle, Compatibility, with Oracle
  • Compatibility, with PostgreSQL
  • Compatibility, with Sybase
  • Configuration files
  • configure, running after prior invocation
  • Constant table, Constant table
  • Contact information
  • Copyright
  • Costs, licensing and support

    • D

  • Database mirroring
  • Database names, case sensitivity, Database names, case sensitivity
  • Database replication, Database replication
  • Date and Time types
  • db table, sorting
  • DBI Perl module
  • Default options
  • Default values, BLOB and TEXT columns
  • Disk full
  • Downloading

    • E

  • Environment variables, Environment variables, Environment variables, Environment variables
  • Expression aliases
  • Expressions, aliases for

    • F

  • fatal signal 11
  • Foreign keys
  • FreeBSD troubleshooting
  • Full disk
  • Functions for SELECT and WHERE clauses
  • Functions, native, adding
  • Functions, user-definable, adding

    • G

  • Getting MySQL
  • Grant tables, sorting, Grant tables, sorting
  • GROUP BY, aliases in
  • Grouping of expressions

    • H

  • HEAP table type
  • History file
  • host table, sorting
  • How to pronounce MySQL

    • I

  • In memory tables
  • Indexes, Indexes
  • Indexes, and BLOB columns
  • Indexes, and IS NULL
  • Indexes, and LIKE
  • Indexes, and NULL values
  • Indexes, and TEXT columns
  • Indexes, leftmost prefix of
  • Indexes, multi-part
  • Internal compiler errors
  • ISAM table type

    • K

  • Keys
  • Keywords

    • L

  • Language support
  • Leftmost prefix of indexes
  • Licensing costs
  • Licensing policy
  • Licensing terms
  • Linking
  • Log file, names

    • M

  • make_binary_release
  • Manual information
  • Memory use
  • Mirroring, database
  • mSQL compatibility
  • msql2mysql
  • Multi-byte characters
  • Multi-part index
  • Multiple servers
  • MyISAM table type
  • myisamchk, myisamchk
  • myisampack, myisampack, myisampack, myisampack, myisampack
  • MyODBC
  • mysql
  • MySQL binary distribution
  • MySQL mailing lists
  • MySQL source distribution
  • MySQL version, MySQL version
  • MySQL, how to pronounce
  • MySQL, what it is
  • mysql_fix_privilege_tables
  • mysql_install_db
  • mysqlaccess
  • mysqladmin, mysqladmin, mysqladmin, mysqladmin, mysqladmin, mysqladmin
  • mysqlbug
  • mysqld
  • mysqldump, mysqldump
  • mysqlimport, mysqlimport, mysqlimport
  • mysqlshow

    • N

  • Native functions, adding
  • Net etiquette, Net etiquette
  • NULL values vs. empty values
  • NULL values, and indexes
  • NULL values, and AUTO_INCREMENT columns
  • NULL values, and TIMESTAMP columns

    • O

  • ODBC
  • ODBC compatibility, ODBC compatibility, ODBC compatibility, ODBC compatibility, ODBC compatibility, ODBC compatibility
  • Optimization
  • Optimizations
  • Option files
  • Oracle compatibility, Oracle compatibility, Oracle compatibility
  • ORDER BY, aliases in

    • P

  • pack_isam
  • Password encryption, reversibility of
  • Passwords, setting, Passwords, setting, Passwords, setting, Passwords, setting
  • Payment information
  • Performance
  • PostgreSQL compatibility
  • Protocol mismatch

    • Q

  • Quoting
  • Quoting binary data
  • Quoting strings

    • R

  • RedHat Package Manager, RedHat Package Manager
  • References
  • Release numbers
  • replace
  • Replication
  • Replication, database, Replication, database
  • Reporting bugs
  • Reporting errors
  • Reserved words
  • Reserved words, exceptions
  • Row-level locking
  • RPM, RPM
  • Running configure after prior invocation

    • S

  • safe_mysqld
  • Scripts
  • Sequence emulation
  • Server functions
  • Size of tables
  • Solaris troubleshooting
  • Sorting, grant tables, Sorting, grant tables
  • sql_yacc.cc problems
  • Stability
  • Startup parameters
  • Storage requirements
  • String comparisons, case sensitivity
  • Strings
  • Strings, escaping characters
  • Strings, quoting
  • Support costs
  • Support terms
  • Support, types
  • Sybase compatibility
  • System table

    • T

  • Table aliases
  • Table cache
  • Table names, case sensitivity, Table names, case sensitivity
  • Table size
  • Table types
  • Table types, Choosing
  • Table, constant, Table, constant
  • Table, system
  • Tables, In memory
  • TEXT columns, default values
  • TEXT columns, indexing
  • The table is full, The table is full
  • TIMESTAMP, and NULL values
  • Timezone problems, Timezone problems, Timezone problems
  • TODO
  • Troubleshooting, FreeBSD
  • Troubleshooting, Solaris
  • Type conversions
  • Type portability
  • Types of support
  • Types, choosing
  • Types, Date and Time

    • U

  • Update log
  • user table, sorting
  • User-definable functions, adding

    • V

  • Version, choosing
  • Version, latest
  • Virtual memory problems while compiling

    • W

  • Which languages MySQL supports
  • Wildcards, and LIKE
  • Wildcards, in mysql.columns_priv table
  • Wildcards, in mysql.db table
  • Wildcards, in mysql.host table
  • Wildcards, in mysql.tables_priv table
  • Wildcards, in mysql.user table
  • Windows

    • Y

  • Year 2000 compliance
  • Year 2000 issues

    • Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - B Contributed programs

Go to the first, previous, next, last section, table of contents.

B Contributed programs

Many users of MySQL have contributed very useful support tools and addons.

A list of what is available at http://www.mysql.com/Contrib (or any mirror) is shown below. If you want to build MySQL support for the Perl DBI/DBD interface, you should fetch the Data-Dumper, DBI, and Msql-Mysql-modules files and install them. See section 4.10 Perl installation comments.

00-README This listing.

B.1 API's

  • Perl modules
    • Data-Dumper-2.09.tar.gz Perl Data-Dumper module. Useful with DBI/DBD support.
    • DBI-1.11.tar.gz Perl DBI module.
    • KAMXbase1.0.tar.gz Convert between `.dbf' files and MySQL tables. Perl module written by Pratap Pereira pereira@ee.eng.ohio-state.edu, extened by Kevin A. McGrail kmcgrail@digital1.peregrinehw.com. This converter can handle MEMO fields.
    • Msql-Mysql-modules-1.2209.tar.gz Perl DBD module to access mSQL and MySQL databases..
    • Data-ShowTable-3.3.tar.gz Perl Data-ShowTable module. Useful with DBI/DBD support.
  • JDBC
    • mm.mysql.jdbc-1.2b.tar.gz The mm JDBC driver for MySQL. This is a production release and is actively developed. By Mark Matthews (mmatthew@ecn.purdue.edu). This driver has a LGPL license. Please check http://www.worldserver.com/mm.mysql/ for the latest drivers (and other JDBC information) since this driver is not updated as frequently.
    • twz1jdbcForMysql-1.0.4-GA.tar.gz The twz driver: A type 4 JDBC driver by Terrence W. Zellers private and educational use.
  • mysql-c++-0.02.tar.gz MySQL C++ wrapper library. By Roland Haenel,
  • mysql++ MySQL C++ API (More than just a wrapper library). Originally by
  • mysql-ruby-2.1.6.tar.gz MySQL Ruby module. By TOMITA Masahiro tommy@tmtm.org Ruby is Object-Oriented Interpreter Language.
  • delphi-interface.gz Delphi interface to libmysql.dll, by Blestan Tabakov,
  • DelphiMySQL2.zip Delphi interface to libmysql.dll, by bsilva@umesd.k12.or.us
  • JdmMysqlDriver-0.1.0.tar.gz A VisualWorks 3.0 Smalltalk driver for MySQL. By
  • Db.py Python module with caching. By gandalf@rosmail.com.
  • MySQLmodule-1.4.tar.gz Python interface for the MySQL. By Joseph Skinner joe@earthlight.co.nz; Modified by Joerg Senekowitsch senekow@ibm.net
  • mysql_mex.tar.gz An interface program for the Matlab program by MathWorks.
  • mysqltcl-1.53.tar.gz Tcl interface for MySQL. Based on `msqltcl-1.50.tar.gz'. Updated by Tobias Ritzau, tobri@ida.liu.se.
  • MyC-0.1.tar.gz A Visual Basic-like API, by Ed Carp.
  • sqlscreens-1.0.1.tar.gz TCL/TK code to generate database screens. By Jean-Francois Dockes.
  • Vdb-dflts-2.1.tar.gz This is a new version of a set of library utilities intended to provide a generic interface to SQL database engines such that your application becomes a 3-tiered application. The advantage is that you can easily switch between and move to other database engines by implementing one file for the new backend without needing to make any changes to your applications. By damian@cablenet.net.
  • DbFramework-1.10.tar.gz DbFramework is a collection of classes for manipulating MySQL databases. The classes are loosely based on the CDIF Data Model Subject Area. By Paul Sharpe paul@miraclefish.com.
  • pike-mysql-1.4.tar.gz MySQL module for pike. For use with the Roxen web server.
  • squile.tar.gz Module for guile that allows guile to interact with SQL databases. By Hal Roberts.
  • stk-mysql.tar.gz Interface for Stk. Stk is the Tk widgets with Scheme underneath instead of Tcl. By Terry Jones
  • eiffel-wrapper-1.0.tar.gz. Eiffel wrapper by Michael Ravits.

B.2 Clients

  • Graphical clients
    • mysqlgui homepage The MySQL GUI client homepage. By Sinisa at TCX.
    • kmysqladmin-0.4.1.tar.gz
    • kmysqladmin-0.4.1-1.src.rpm
    • kmysqladmin-0.4.1-1.i386.rpm An administration tool for the MySQL server using QT / KDE. Tested only on Linux.
    • Java client using Swing By Fredy Fischer, se-afs@dial.eunet.ch. You can always find the latest version here.
    • mysqlwinadmn.zip Win32 GUI (binary only) to administrate a database, by David B. Mansel,
    • xmysqladmin-1.0.tar.gz A front end to the MySQL database engine. It allows reloads, status check, process control, myisamchk, grant/revoke privileges, creating databases, dropping databases, create, alter, browse and drop tables. Originally by Gilbert Therrien, gilbert@ican.net but now in public domain and supported by TcX.
    • xmysql-1.9.tar.gz
    • xmysql home page A front end to the MySQL database engine. It allows for simple queries and table maintenance, as well as batch queries. By Rick Mehalick, dblhack@wt.net. Requires xforms 0.88 to work.
    • dbMetrix An open source client for exploring databases and executing SQL. Supports MySQL, Oracle, PostgreSQL and mSQL.
    • GtkSQL A query tool for MySQL and PostgreSQL.
    • dbMan A query tool written in Perl. Uses DBI and Tk.
    • Atronic's MySQL client for Win32
  • Web clients
    • mysqladmin-atif-1.0.tar.gz WWW MySQL administrator for the user, db and host tables. By Tim Sailer, modified by Atif Ghaffar
    • mysql-webadmin-1.0a8-rz.tar.gz A tool written in PHP-FI to administrate MySQL databases remotely over the web within a Web-Browser. By Peter Kuppelwieser, Not maintained anymore!
    • mysqladm.tar.gz MySQL Web Database Administration written in Perl. By Tim Sailer.
    • mysqladm-2.tar.gz Updated version of `mysqladm.tar.gz', by High Tide.
    • billowmysql.zip Updated version of `mysqladm.tar.gz', by Ying Gao. You can get the newest version from the home site.
    • myadmin-0.4.tar.gz
    • MyAdmin home page A web based mysql administrator by Mike Machado.
    • phpMyAdmin_2.0.1.tar.gz A set of PHP3-scripts to adminstrate MySQL over the WWW.
    • phpMyAdmin home page A PHP3 tool in the spirit of mysql-webadmin, by Tobias Ratschiller, tobias@dnet.it
    • useradm.tar.gz MySQL administrator in PHP. By Ofni Thomas

B.3 Web tools

  • http://www.odbsoft.com/cook/sources.htm This package has various functions for generating html code from an SQL table structure and for generating SQL statements (Select, Insert, Update, Delete) from an html form. You can build a complete forms interface to an SQL database (query, add, update, delete) without any programming! By Marc Beneteau, marc@odbsoft.com.
  • sqlhtml.tar.gz SQL/HTML is an HTML database manager for MySQL using DBI 1.06.
  • udmsearch-2.2.1.tar.gz A MySQL- and PHP- based search engine over HTTP. By Alexander I. Barkov bar@izhcom.ru.
  • wmtcl.doc
  • wmtcl.lex With this you can write HTML files with inclusions of TCL code. By
  • www-sql-0.5.7.lsm
  • www-sql-0.5.7.tar.gz A CGI program that parses an HTML file containing special tags, parses them and inserts data from a MySQL database.
  • genquery.zip Perl SQL database interface package for html.
  • cgi++-0.2.tar.gz A CGI wrapper by Sasha Pachev.
  • WebBoard 1.0 EU-Industries Internet-Message-Board.
  • DBIx-TextIndex-0.02.tar.gz Full-text searching with Perl on BLOB/TEXT columns by Daniel Koch.

B.4 Authentication tools

  • ascend-radius-mysql-0.6.1.patch.gz This is authentication and logging patch using MySQL for Ascend-Radius. By takeshi@SoftAgency.co.jp.
  • icradius 0.10 icradius readme file
  • checkpassword-0.81-mysql-0.5.1.patch.gz MySQL authentication patch for QMAIL and checkpassword. These are useful for management user(mail,pop account) by MySQL. By takeshi@SoftAgency.co.jp
  • jradius-diff.gz MySQL support for Livingston's Radius 2.01. Authentication and Accounting. By Jose de Leon, jdl@thevision.net
  • mod_auth_mysql-2.20.tar.gz Apache authentication module for MySQL. By Zeev Suraski, Please register this module at: http://bourbon.netvision.net.il/mysql/mod_auth_mysql/register.html. The registering information is only used for statistical purposes and will encourage further development of this module!
  • mod_log_mysql-1.05.tar.gz MySQL logging module for Apache. By Zeev Suraski,
  • mypasswd-2.0.tar.gz Extra for mod_auth_mysql. This is a little tool that allows you to add/change user records storing group and/or password entries in MySQL tables. By Harry Brueckner, brueckner@respublica.de.
  • mysql-passwd.README
  • mysql-passwd-1.2.tar.gz Extra for mod_auth_mysql. This is a two-part system for use with mod_auth_mysql.
  • pam_mysql.tar.gz This module authenticates users via pam, using MySQL.
  • nsapi_auth_mysql.tar Netscape Web Server API (NSAPI) functions to authenticate (BASIC) users against MySQL tables. By Yuan John Jiang.
  • qmail-1.03-mysql-0.4.1.patch.gz Patch for qmail to authenticate users from a MySQL table.
  • pwcheck_mysql-0.1.tar.gz An authentication module for the Cyrus IMAP server. By Aaron Newsome.

B.5 Converters

  • dbf2mysql-1.13.tgz Convert between `.dbf' files and MySQL tables. By Maarten Boekhold, boekhold@cindy.et.tudelft.nl, and Michael Widenius. This converter can't handle MEMO fields.
  • dbf2mysql.zip Convert between FoxPro `.dbf' files and MySQL tables on Win32. By Alexander Eltsyn, ae@nica.ru or ae@usa.net.
  • dump2h-1.20.gz Convert from mysqldump output to a C header file. By Harry Brueckner,
  • exportsql.txt A script that is similar to access_to_mysql.txt, except that this one is fully configurable, has better type conversion (including detection of TIMESTAMP fields), provides warnings and suggestions while converting, quotes all special characters in text and binary data, and so on. It will also convert to mSQL v1 and v2, and is free of charge for anyone. See http://www.cynergi.net/prod/exportsql/ for latest version. By Pedro Freire, support@cynergi.net. Note: Doesn't work with Access2!
  • access_to_mysql.txt Paste this function into an Access module of a database which has the tables you want to export. See also exportsql. By Brian Andrews. Note: Doesn't work with Access2!
  • importsql.txt A script that does the exact reverse of exportsql.txt. That is, it imports data from MySQL into an Access database via ODBC. This is very handy when combined with exportSQL, since it lets you use Access for all DB design and administration, and synchronize with your actual MySQL server either way. Free of charge. See http://www.netdive.com/freebies/importsql/ for any updates. Created by Laurent Bossavit of NetDIVE. Note: Doesn't work with Access2!
  • /msql2mysqlWrapper 1.0 A C wrapper from mSQL to MySQL. By alfred@sb.net
  • sqlconv.pl A simple script that can be used to copy fields from one MySQL table to another in bulk. Basically, you can run mysqldump and pipe it to the sqlconv.pl script and the script will parse through the mysqldump output and will rearrange the fields so they can be inserted into a new table. An example is when you want to create a new table for a different site you are working on, but the table is just a bit different (ie - fields in different order, etc.). By Steve Shreeve.

B.6 Using MySQL with other products

  • emacs-sql-mode.tar.gz Raw port of a SQL mode for XEmacs. Supports completion. Original by Peter D. Pezaris pez@atlantic2.sbi.com and partial MySQL port by David Axmark.
  • MyAccess.mda MyAccess is an AddIn for Access 97 and handles a lot of maintanance work for MySQL databases. MyAccess-readme. By Hubertus Hiden.
  • radius-0.3.tar.gz Patches for radiusd to make it support MySQL. By Wim Bonis,

B.7 Useful tools

  • mysql_watchdog.pl Monitor the MySQL daemon for possible lockups. By Yermo Lamers,
  • mysqltop.tar.gz Sends a query in a fixed time interval to the server and shows the resulting table. By Thomas Wana.
  • mysql_structure_dumper.tar.gz Prints out the structure of the all tables in a database. By Thomas Wana.
  • structure_dumper.tgz Prints the structure of every table in a database. By Thomas Wana.
  • mysqlsync-1.0-alpha.tar.gz. A perl script to keep remote copies of a MySQL database in sync with a central master copy. By Mark Jeftovic. markjr@easydns.com
  • MySQLTutor. MySQLTutor. A tutor of MySQL for beginners
  • MySQLDB.zip A COM library for MySQL by Alok Singh.
  • MySQLDB-readme.html
  • mysql_replicate.pl Perl program that handles replication. By mjs@atnet.net.au
  • DBIx-TextIndex-0.02.tar.gz Perl program that uses reverse indexing to handle text searching. By Daniel Koch.

B.8 Uncategorized

  • findres.pl Find reserved words in tables. By Nem W Schlecht.
  • handicap.tar.gz Performance handicapping system for yachts. Uses PHP. By
  • hylalog-1.0.tar.gz Store hylafax outgoing faxes in a MySQL database. By Sinisa Milivojevic, sinisa@coresinc.com.
  • mrtg-mysql-1.0.tar.gz MySQL status plotting with MRTG, by Luuk de Boer, luuk@wxs.nl.
  • wuftpd-2.4.2.18-mysql_support.2.tar.gz Patches to add logging to MySQL for WU-ftpd. By Zeev Suraski,
  • Old-Versions Previous versions of things found here that you probably won't be interested in.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - C Contributors to MySQL

Go to the first, previous, next, last section, table of contents.

C Contributors to MySQL

Contributors to the MySQL distribution are listed below, in somewhat random order:

Michael (Monty) Widenius
Has written the following parts of MySQL:
  • All the main code in mysqld.
  • New functions for the string library.
  • Most of the mysys library.
  • The ISAM and MyISAM libraries (B-tree index file handlers with index compression and different record formats).
  • The heap library. A memory table system with our superior full dynamic hashing. In use since 1981 and published around 1984.
  • The replace program (look into it, it's COOL!).
  • MyODBC, the ODBC driver for Windows95.
  • Fixing bugs in MIT-pthreads to get it to work for MySQL. And also Unireg, a curses-based application tool with many utilities.
  • Porting of mSQL tools like msqlperl, DBD/DBI and DB2mysql.
  • Most parts of crash-me and the MySQL benchmarks.
David Axmark
  • Coordinator and main writer for the Reference Manual, including enhancements to texi2html. Also automatic website updating from this manual.
  • Autoconf, Automake and libtool support.
  • The licensing stuff.
  • Parts of all the text files. (Nowadays only the `README' is left. The rest ended up in the manual.)
  • Our Mail master.
  • Lots of testing of new features.
  • Our in-house ``free'' software lawyer.
  • Mailing list maintainer (who never has the time to do it right...)
  • Our original portability code (more than 10 years old now). Nowadays only some parts of mysys are left.
  • Someone for Monty to call in the middle of the night when he just got that new feature to work. :-)
Paul DuBois
Help with making the Reference Manual correct and understandable.
Gianmassimo Vigazzola qwerg@mbox.vol.it or qwerg@tin.it
The initial port to Win32/NT.
Kim Aldale
Rewriting Monty's and David's attempts at English into English.
Allan Larsson (The BOSS at TcX)
For all the time he has allowed Monty to spend on this ``maybe useful'' tool (MySQL). Dedicated user (and bug finder) of Unireg & MySQL.
Per Eric Olsson
For more or less constructive criticism and real testing of the dynamic record format.
Irena Pancirov irena@mail.yacc.it
Win32 port with Borland compiler.
David J. Hughes
For the effort to make a shareware SQL database. We at TcX started with mSQL, but found that it couldn't satisfy our purposes so instead we wrote a SQL interface to our application builder Unireg. mysqladmin and mysql are programs that were largely influenced by their mSQL counterparts. We have put a lot of effort into making the MySQL syntax a superset of mSQL. Many of the APIs ideas are borrowed from mSQL to make it easy to port free mSQL programs to MySQL. MySQL doesn't contain any code from mSQL. Two files in the distribution (`client/insert_test.c' and `client/select_test.c') are based on the corresponding (non-copyrighted) files in the mSQL distribution, but are modified as examples showing the changes necessary to convert code from mSQL to MySQL. (mSQL is copyrighted David J. Hughes.)
Fred Fish
For his excellent C debugging and trace library. Monty has made a number of smaller improvements to the library (speed and additional options).
Richard A. O'Keefe
For his public domain string library.
Henry Spencer
For his regex library, used in WHERE column REGEXP regexp.
Free Software Foundation
From whom we got an excellent compiler (gcc), the libc library (from which we have borrowed `strto.c' to get some code working in Linux) and the readline library (for the mysql client).
Free Software Foundation & The XEmacs development team
For a really great editor/environment used by almost everybody at TcX/detron.
Igor Romanenko igor@frog.kiev.ua
mysqldump (previously msqldump, but ported and enhanced by Monty).
Tim Bunce, Alligator Descartes
For the DBD (Perl) interface.
Andreas Koenig a.koenig@mind.de
For the Perl interface to MySQL.
Eugene Chan eugene@acenet.com.sg
For porting PHP to MySQL.
Michael J. Miller Jr. mke@terrapin.turbolift.com
For the first MySQL manual. And a lot of spelling/language fixes for the FAQ (that turned into the MySQL manual a long time ago).
Giovanni Maruzzelli maruzz@matrice.it
For porting iODBC (Unix ODBC).
Chris Provenzano
Portable user level pthreads. From the copyright: This product includes software developed by Chris Provenzano, the University of California, Berkeley, and contributors. We are currently using version 1_60_beta6 patched by Monty (see `mit-pthreads/Changes-mysql').
Xavier Leroy Xavier.Leroy@inria.fr
The author of LinuxThreads (used by MySQL on Linux).
Zarko Mocnik zarko.mocnik@dem.si
Sorting for Slovenian language and the `cset.tar.gz' module that makes it easier to add other character sets.
"TAMITO" tommy@valley.ne.jp
The _MB character set macros and the ujis and sjis character sets.
Yves Carlier Yves.Carlier@rug.ac.be
mysqlaccess, a program to show the access rights for a user.
Rhys Jones rhys@wales.com (And GWE Technologies Limited)
For the JDBC, a module to extract data from MySQL with a Java client.
Dr Xiaokun Kelvin ZHU X.Zhu@brad.ac.uk
Further development of the JDBC driver and other MySQL-related Java tools.
James Cooper pixel@organic.com
For setting up a searchable mailing list archive at his site.
Rick Mehalick Rick_Mehalick@i-o.com
For xmysql, a graphical X client for MySQL.
Doug Sisk sisk@wix.com
For providing RPM packages of MySQL for RedHat Linux.
Diemand Alexander V. axeld@vial.ethz.ch
For providing RPM packages of MySQL for RedHat Linux/Alpha.
Antoni Pamies Olive toni@readysoft.es
For providing RPM versions of a lot of MySQL clients for Intel and SPARC.
Jay Bloodworth jay@pathways.sde.state.sc.us
For providing RPM versions for MySQL 3.21 versions.
Jochen Wiedmann wiedmann@neckar-alb.de
For maintaining the Perl DBD::mysql module.
Therrien Gilbert gilbert@ican.net, Jean-Marc Pouyot jmp@scalaire.fr
French error messages.
Petr snajdr, snajdr@pvt.net
Czech error messages.
Jaroslaw Lewandowski jotel@itnet.com.pl
Polish error messages.
Miguel Angel Fernandez Roiz
Spanish error messages.
Roy-Magne Mo rmo@www.hivolda.no
Norwegian error messages and testing of 3.21.#.
Timur I. Bakeyev root@timur.tatarstan.ru
Russian error messages.
brenno@dewinter.com && Filippo Grassilli phil@hyppo.com
Italian error messages.
Dirk Munzinger dirk@trinity.saar.de
German error messages.
Billik Stefan billik@sun.uniag.sk
Slovak error messages.
David Sacerdote davids@secnet.com
Ideas for secure checking of DNS hostnames.
Wei-Jou Chen jou@nematic.ieo.nctu.edu.tw
Some support for Chinese(BIG5) characters.
Wei He hewei@mail.ied.ac.cn
A lot of functionality for the Chinese(GBK) character set.
Zeev Suraski bourbon@netvision.net.il
FROM_UNIXTIME() time formatting, ENCRYPT() functions, and bison adviser. Active mailing list member.
Luuk de Boer luuk@wxs.nl
Ported (and extended) the benchmark suite to DBI/DBD. Have been of great help with crash-me and running benchmarks. Some new date functions. The mysql_setpermissions script.
Jay Flaherty fty@utk.edu
Big parts of the Perl DBI/DBD section in the manual.
Paul Southworth pauls@etext.org, Ray Loyzaga yar@cs.su.oz.au
Proof-reading of the Reference Manual.
Alexis Mikhailov root@medinf.chuvashia.su
User definable functions (UDFs); CREATE FUNCTION and DROP FUNCTION.
Andreas F. Bobak bobak@relog.ch
The AGGREGATE extension to UDF functions.
Ross Wakelin R.Wakelin@march.co.uk
Help to set up InstallShield for MySQL-Win32.
Jethro Wright III jetman@li.net
The `libmysql.dll' library.
James Pereria jpereira@iafrica.com
Mysqlmanager, a Win32 GUI tool for administrating MySQL.
Curt Sampson cjs@portal.ca
Porting of MIT-pthreads to NetBSD/Alpha and NetBSD 1.3/i386.
Sinisa Milivojevic sinisa@coresinc.com
Compression (with zlib) to the client/server protocol. Perfect hashing for the lexical analyzer phase.
Antony T. Curtis antony.curtis@olcs.net
Porting of MySQL to OS/2.
Martin Ramsch m.ramsch@computer.org
Examples in the MySQL Tutorial.

Other contributors, bugfinders and testers: James H. Thompson, Maurizio Menghini, Wojciech Tryc, Luca Berra, Zarko Mocnik, Wim Bonis, Elmar Haneke, jehamby@lightside, psmith@BayNetworks.COM, Mike Simons, Jaakko Hyv@"atti.

And lots of bug report/patches from the folks on the mailing list.

And a big tribute to those that help us answer questions on the mysql@lists.mysql.com mailing list:

Daniel Koch dkoch@amcity.com
Irix setup.
Luuk de Boer luuk@wxs.nl
Benchmark questions.
Tim Sailer tps@users.buoy.com
DBD-mysql questions.
Boyd Lynn Gerber gerberb@zenez.com
SCO related questions.
Richard Mehalick RM186061@shellus.com
xmysql-releated questions and basic installation questions.
Zeev Suraski bourbon@netvision.net.il
Apache module configuration questions (log & auth), PHP-related questions, SQL syntax related questions and other general questions.
Francesc Guasch frankie@citel.upc.es
General questions.
Jonathan J Smith jsmith@wtp.net
Questions pertaining to OS-specifics with Linux, SQL syntax, and other things that might be needing some work.
David Sklar sklar@student.net
Using MySQL from PHP and Perl.
Alistair MacDonald A.MacDonald@uel.ac.uk
Not yet specified, but is flexible and can handle Linux and maybe HP-UX. Will try to get user to use mysqlbug.
John Lyon jlyon@imag.net
Questions about installing MySQL on Linux systems, using either `.rpm' files, or compiling from source.
Lorvid Ltd. lorvid@WOLFENET.com
Simple billing/license/support/copyright issues.
Patrick Sherrill patrick@coconet.com
ODBC and VisualC++ interface questions.
Randy Harmon rjharmon@uptimecomputers.com
DBD, Linux, some SQL syntax questions.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - SQL command, type and function index

Go to the first, previous, next, last section, table of contents.

SQL command, type and function index

  • ! (logical NOT)
  • != (not equal)
  • "
  • % (modulo)
  • % (wildcard character)
  • & (bitwise AND)
  • && (logical AND)
  • () (parentheses)
  • * (multiplication)
  • + (addition)
  • - (subtraction)
  • - (unary minus)
  • .my.cnf file, .my.cnf file, .my.cnf file, .my.cnf file, .my.cnf file, .my.cnf file, .my.cnf file
  • .mysql_history file
  • .pid (process ID) file
  • / (division)
  • /etc/passwd, /etc/passwd
  • < (less than)
  • << (left shift)
  • <= (less than or equal)
  • <=> (Equal to)
  • <> (not equal)
  • = (equal)
  • > (greater than)
  • >= (greater than or equal)
  • >> (right shift)
  • \" (double quote)
  • \' (single quote)
  • \0 (ASCII 0)
  • \\ (escape)
  • \b (backspace)
  • \n (newline)
  • \r (carriage return)
  • \t (tab)
  • _ (wildcard character)
  • `

    • A

  • ABS()
  • ACOS()
  • ADDDATE()
  • addition (+)
  • alias
  • ALTER TABLE
  • AND, bitwise
  • AND, logical
  • Arithmetic functions
  • ASCII()
  • ASIN()
  • ATAN()
  • ATAN2()
  • AUTO_INCREMENT, using with DBI
  • AVG()

    • B

  • backspace (\b)
  • BENCHMARK()
  • BETWEEN ... AND
  • BIGINT
  • BIN()
  • BINARY
  • Bit functions
  • BIT_AND()
  • BIT_COUNT()
  • BIT_OR()
  • BLOB, BLOB

    • C

  • carriage return (\r)
  • CASE
  • Casts
  • CC environment variable, CC environment variable
  • CEILING()
  • CFLAGS environment variable
  • CHAR, CHAR
  • CHAR VARYING
  • CHAR()
  • CHAR_LENGTH()
  • CHARACTER
  • CHARACTER VARYING
  • CHARACTER_LENGTH()
  • ChopBlanks DBI method
  • COALESCE()
  • Comment syntax
  • Comparison operators
  • CONCAT()
  • connect() DBI method
  • Control flow functions
  • CONV()
  • COS()
  • COT()
  • COUNT()
  • COUNT(DISTINCT)
  • CREATE DATABASE
  • CREATE FUNCTION
  • CREATE INDEX
  • CREATE TABLE
  • CROSS JOIN
  • CURDATE()
  • CURRENT_DATE
  • CURRENT_TIME
  • CURRENT_TIMESTAMP
  • CURTIME()
  • CXX environment variable, CXX environment variable, CXX environment variable, CXX environment variable
  • CXXFLAGS environment variable, CXXFLAGS environment variable

    • D

  • data_sources() DBI method
  • DATABASE()
  • DATE, DATE
  • Date and time functions
  • DATE_ADD()
  • DATE_FORMAT()
  • DATE_SUB()
  • DATETIME, DATETIME
  • DAYNAME()
  • DAYOFMONTH()
  • DAYOFWEEK()
  • DAYOFYEAR()
  • DBI->connect()
  • DBI->data_sources()
  • DBI->disconnect
  • DBI->do()
  • DBI->execute
  • DBI->fetchall_arrayref
  • DBI->fetchrow_array
  • DBI->fetchrow_arrayref
  • DBI->fetchrow_hashref
  • DBI->finish
  • DBI->prepare()
  • DBI->quote
  • DBI->quote()
  • DBI->rows
  • DBI->trace, DBI->trace
  • DBI->{ChopBlanks}
  • DBI->{insertid}
  • DBI->{is_blob}
  • DBI->{is_key}
  • DBI->{is_not_null}
  • DBI->{is_num}
  • DBI->{is_pri_key}
  • DBI->{length}
  • DBI->{max_length}
  • DBI->{NAME}
  • DBI->{NULLABLE}
  • DBI->{NUM_OF_FIELDS}
  • DBI->{table}
  • DBI->{type}
  • DBI_TRACE environment variable, DBI_TRACE environment variable
  • DECIMAL
  • DECODE()
  • DEGREES()
  • DELAYED
  • DELETE
  • DESC
  • DESCRIBE
  • disconnect DBI method
  • DISTINCT, DISTINCT
  • division (/)
  • do() DBI method
  • DOUBLE
  • DOUBLE PRECISION
  • double quote (\")
  • DROP DATABASE
  • DROP FUNCTION
  • DROP INDEX
  • DROP TABLE
  • DUMPFILE

    • E

  • ELT()
  • ENCODE()
  • ENCRYPT()
  • ENUM, ENUM
  • Environment variable, CC, Environment variable, CC
  • Environment variable, CFLAGS
  • Environment variable, CXX, Environment variable, CXX, Environment variable, CXX
  • Environment variable, CXXFLAGS, Environment variable, CXXFLAGS
  • Environment variable, DBI_TRACE, Environment variable, DBI_TRACE
  • Environment variable, HOME
  • Environment variable, LD_RUN_PATH, Environment variable, LD_RUN_PATH, Environment variable, LD_RUN_PATH
  • Environment variable, MYSQL_DEBUG, Environment variable, MYSQL_DEBUG
  • Environment variable, MYSQL_HISTFILE
  • Environment variable, MYSQL_HOST
  • Environment variable, MYSQL_PWD, Environment variable, MYSQL_PWD
  • Environment variable, MYSQL_TCP_PORT, Environment variable, MYSQL_TCP_PORT, Environment variable, MYSQL_TCP_PORT
  • Environment variable, MYSQL_UNIX_PORT, Environment variable, MYSQL_UNIX_PORT, Environment variable, MYSQL_UNIX_PORT, Environment variable, MYSQL_UNIX_PORT
  • Environment variable, PATH
  • Environment variable, TMPDIR
  • Environment variable, TZ, Environment variable, TZ, Environment variable, TZ
  • Environment variable, UMASK
  • Environment variable, USER
  • Environment variables, CXX
  • equal (=)
  • escape (\\)
  • execute DBI method
  • EXP()
  • EXPLAIN
  • EXPORT_SET()
  • EXTRACT(type FROM date)

    • F

  • fetchall_arrayref DBI method
  • fetchrow_array DBI method
  • fetchrow_arrayref DBI method
  • fetchrow_hashref DBI method
  • FIELD()
  • FILE
  • FIND_IN_SET()
  • finish DBI method
  • FLOAT, FLOAT
  • FLOAT(M,D)
  • FLOAT(precision), FLOAT(precision)
  • FLOAT(precision) [ZEROFILL]
  • FLOOR()
  • FLUSH
  • FORMAT()
  • FROM_DAYS()
  • FROM_UNIXTIME(), FROM_UNIXTIME()
  • Functions, arithmetic
  • Functions, bit
  • Functions, control flow
  • Functions, date and time
  • Functions, GROUP BY
  • Functions, logical
  • Functions, mathematical
  • Functions, miscellaneous
  • Functions, string
  • Functions, string comparison
  • Functions, user-defined

    • G

  • GET_LOCK()
  • GRANT
  • greater than (>)
  • greater than or equal (>=)
  • GREATEST()
  • GROUP BY functions

    • H

  • HEX()
  • Hexadecimal values
  • HOME environment variable
  • host.frm, problems finding
  • HOUR()

    • I

  • IF()
  • IFNULL()
  • IN
  • INNER JOIN
  • INSERT
  • INSERT DELAYED
  • INSERT()
  • insertid DBI method
  • INSTR()
  • INT
  • INTEGER
  • INTERVAL()
  • IS NOT NULL
  • IS NULL
  • IS NULL, and indexes
  • is_blob DBI method
  • is_key DBI method
  • is_not_null DBI method
  • is_num DBI method
  • is_pri_key DBI method
  • ISNULL()

    • J

  • JOIN

    • K

  • KILL

    • L

  • LAST_INSERT_ID()
  • LAST_INSERT_ID([expr])
  • LCASE()
  • LD_RUN_PATH environment variable, LD_RUN_PATH environment variable, LD_RUN_PATH environment variable
  • LEAST()
  • LEFT JOIN
  • LEFT OUTER JOIN
  • LEFT()
  • length DBI method
  • LENGTH()
  • less than (<)
  • less than or equal (<=)
  • LIKE
  • LIKE, and indexes
  • LIKE, and wildcards
  • LOAD DATA INFILE, LOAD DATA INFILE
  • LOCATE(), LOCATE()
  • LOCK TABLES
  • LOG()
  • LOG10()
  • Logical functions
  • LONGBLOB
  • LONGTEXT
  • LOWER()
  • LPAD()
  • LTRIM()

    • M

  • MAKE_SET()
  • Mathematical functions
  • MAX()
  • max_length DBI method
  • MD5()
  • MEDIUMBLOB
  • MEDIUMINT
  • MEDIUMTEXT
  • MID()
  • MIN()
  • minus, unary (-)
  • MINUTE()
  • Miscellaneous functions
  • MOD()
  • modulo (%)
  • MONTH()
  • MONTHNAME()
  • multiplication (*)
  • my_ulonglong C type
  • my_ulonglong values, printing
  • MYSQL C type
  • mysql_affected_rows()
  • mysql_change_user()
  • mysql_close()
  • mysql_connect()
  • mysql_create_db()
  • mysql_data_seek()
  • MYSQL_DEBUG environment variable, MYSQL_DEBUG environment variable
  • mysql_debug()
  • mysql_drop_db()
  • mysql_dump_debug_info()
  • mysql_eof()
  • mysql_errno()
  • mysql_error()
  • mysql_escape_string()
  • mysql_escape_string()
  • mysql_fetch_field()
  • mysql_fetch_field_direct()
  • mysql_fetch_fields()
  • mysql_fetch_lengths()
  • mysql_fetch_row()
  • MYSQL_FIELD C type
  • mysql_field_count(), mysql_field_count()
  • MYSQL_FIELD_OFFSET C type
  • mysql_field_seek()
  • mysql_field_tell()
  • mysql_free_result()
  • mysql_get_client_info()
  • mysql_get_host_info()
  • mysql_get_proto_info()
  • mysql_get_server_info()
  • MYSQL_HISTFILE environment variable
  • MYSQL_HOST environment variable
  • mysql_info(), mysql_info(), mysql_info(), mysql_info()
  • mysql_info()
  • mysql_init()
  • mysql_insert_id()
  • mysql_insert_id()
  • mysql_kill()
  • mysql_list_dbs()
  • mysql_list_fields()
  • mysql_list_processes()
  • mysql_list_tables()
  • mysql_num_fields()
  • mysql_num_rows()
  • mysql_options()
  • mysql_ping()
  • MYSQL_PWD environment variable, MYSQL_PWD environment variable
  • mysql_query()
  • mysql_real_connect()
  • mysql_real_query()
  • mysql_reload()
  • MYSQL_RES C type
  • MYSQL_ROW C type
  • mysql_row_seek()
  • mysql_row_tell()
  • mysql_select_db()
  • mysql_shutdown()
  • mysql_stat()
  • mysql_store_result()
  • MYSQL_TCP_PORT environment variable, MYSQL_TCP_PORT environment variable, MYSQL_TCP_PORT environment variable
  • mysql_thread_id()
  • MYSQL_UNIX_PORT environment variable, MYSQL_UNIX_PORT environment variable, MYSQL_UNIX_PORT environment variable, MYSQL_UNIX_PORT environment variable
  • mysql_use_result()

    • N

  • NAME DBI method
  • NATIONAL CHAR
  • NATURAL LEFT JOIN
  • NATURAL LEFT OUTER JOIN
  • NCHAR
  • newline (\n)
  • not equal (!=)
  • not equal (<>)
  • NOT IN
  • NOT LIKE
  • NOT REGEXP
  • NOT, logical
  • NOW()
  • NUL
  • NULL
  • NULL value
  • NULLABLE DBI method
  • NUM_OF_FIELDS DBI method
  • NUMERIC

    • O

  • OCT()
  • OCTET_LENGTH()
  • OPTIMIZE TABLE
  • OR, bitwise
  • OR, logical
  • ORD()

    • P

  • parentheses ( and )
  • PASSWORD(), PASSWORD(), PASSWORD(), PASSWORD()
  • PATH environment variable
  • PERIOD_ADD()
  • PERIOD_DIFF()
  • PI()
  • POSITION()
  • POW()
  • POWER()
  • prepare() DBI method
  • PROCESSLIST

    • Q

  • QUARTER()
  • quote() DBI method
  • Quoting of identifiers

    • R

  • RADIANS()
  • RAND()
  • REAL
  • REGEXP
  • RELEASE_LOCK()
  • REPEAT()
  • REPLACE
  • REPLACE()
  • return (\r)
  • REVERSE()
  • REVOKE
  • RIGHT()
  • RLIKE
  • ROUND(), ROUND()
  • rows DBI method
  • RPAD()
  • RTRIM()

    • S

  • SEC_TO_TIME()
  • SECOND()
  • SELECT
  • SELECT, optimizing
  • SESSION_USER()
  • SET, SET
  • SET OPTION
  • SHOW COLUMNS
  • SHOW DATABASES
  • SHOW FIELDS
  • SHOW GRANTS
  • SHOW INDEX
  • SHOW KEYS
  • SHOW PROCESSLIST
  • SHOW STATUS
  • SHOW TABLE STATUS
  • SHOW TABLES
  • SHOW VARIABLES
  • SIGN()
  • SIN()
  • single quote (\')
  • SMALLINT
  • SOUNDEX()
  • SPACE()
  • SQRT()
  • STD()
  • STDDEV()
  • STRAIGHT_JOIN
  • STRCMP()
  • String comparison functions
  • String functions
  • SUBDATE()
  • SUBSTRING(), SUBSTRING()
  • SUBSTRING_INDEX()
  • subtraction (-)
  • SUM()
  • SYSDATE()
  • SYSTEM_USER()

    • T

  • tab (\t)
  • table DBI method
  • table_cache
  • TAN()
  • TEXT, TEXT
  • Threads
  • TIME, TIME
  • TIME_FORMAT()
  • TIME_TO_SEC()
  • TIMESTAMP, TIMESTAMP
  • TINYBLOB
  • TINYINT
  • TINYTEXT
  • TMPDIR environment variable
  • TO_DAYS()
  • trace DBI method, trace DBI method
  • TRIM()
  • TRUNCATE()
  • type DBI method
  • Types
  • TZ environment variable, TZ environment variable, TZ environment variable

    • U

  • UCASE()
  • UDF functions
  • ulimit
  • UMASK environment variable
  • unary minus (-)
  • UNIX_TIMESTAMP()
  • UNLOCK TABLES
  • UPDATE
  • UPPER()
  • USE
  • USER environment variable
  • USER()
  • User-defined functions

    • V

  • VARCHAR, VARCHAR
  • VERSION()

    • W

  • WEEK()
  • WEEKDAY()
  • Wildcard character (%)
  • Wildcard character (_)

    • Y

  • YEAR, YEAR
  • YEAR()
  • | (bitwise OR)
  • || (logical OR)
  • ~

    • Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - D MySQL change history

Go to the first, previous, next, last section, table of contents.

D MySQL change history

Note that we tend to update the manual at the same time we implement new things to MySQL. If you find a version listed below that you can't find on the MySQL download page, this means that the version has not yet been released!

D.1 Changes in release 3.23.x (Released as alpha)

The major difference between release 3.23 and releases 3.22 and 3.21 is that 3.23 contains a new ISAM library (MyISAM), which is more tuned for SQL than the old ISAM was.

The 3.23 release is under development, and things will be added at a fast pace to it. For the moment we recommend this version only for users that desperately need a new feature that is found only in this release (like big file support and machine-independent tables). (Note that all new functionality in MySQL 3.23 is extensively tested, but as this release involves much new code, it's difficult to test everything). This version should start to stabilize as soon as we get subselects included in it.

D.1.1 Changes in release 3.23.7

  • Fixed workaround under Linux to avoid problems with pthread_mutex_timedwait, which is used with INSERT DELAYED. See section 4.11.5 Linux notes (all Linux versions)
  • Fixed tha one will get at 'disk full' error message if one gets disk full when doing sorting (instead of waiting until we got more disk space).
  • Fixed a bug in MyISAM with keys > 250 characters.
  • In MyISAM one can now do an INSERT at the same time as other threads are reading from the table.
  • Added variable max_write_lock_count to mysqld to force a READ lock after a certain number of WRITE locks.
  • Inverted flag delayed_key_write on show variables.
  • Renamed variable concurrency to thread_concurrency.
  • The following functions are now multi-byte-safe: LOCATE(substr,str), POSITION(substr
    IN str), LOCATE(substr,str,pos), INSTR(str,substr), LEFT(str,len),
    RIGHT(str,len), SUBSTRING(str,pos,len), SUBSTRING(str FROM
    pos FOR len), MID(str,pos,len), SUBSTRING(str,pos), SUBSTRING(str
    FROM pos), SUBSTRING_INDEX(str,delim,count), RTRIM(str), TRIM([[BOTH
    | TRAILING] [remstr] FROM] str), REPLACE(str,from_str,to_str), REVERSE(str),
    INSERT(str,pos,len,newstr), LCASE(str), LOWER(str),
    UCASE(str) and UPPER(str); Patch by Wei He.
  • Fix core dump when releasing a lock from a non existing table
  • Remove locks on tables before starting to remove duplicates.
  • Added option FULL to SHOW PROCESSLIST.
  • Added option --verbose to mysqladmin.
  • Fixed problem when automaticly converting HEAP to MyISAM.
  • Fixed bug in HEAP tables when doing insert + delete + insert + scan the table.
  • Fixed bugs on Alpha with REPLACE() and LOAD DATA INFILE.
  • Added mysqld variable interactive_timeout.
  • Changed the argument to mysql_data_seek() from ulong to ulonglong.

D.1.2 Changes in release 3.23.6

  • Added mysqld option -O lower_case_table_names={0|1} to allow users to force table names to lower case.
  • Added SELECT ... INTO DUMPFILE.
  • Added mysqld option --ansi to make some functions ANSI SQL compatible.
  • Temporary tables now starts with #sql.
  • Added quoting of identifiers with ` (" in --ansi mode).
  • Changed to use snprintf() when printing floats to avoid some buffer overflows on FREEBSD.
  • Made [floor() overflow safe on FREEBSD.
  • Added option --quote-names to mysqldump
  • Fixed bug that one could make a part of a PRIMARY KEY NOT NULL.
  • Fixed encrypt() to be thread safe and not reuse buffer.
  • Added mysql_odbc_escape_string() function to support big5 characters in MyOBC.
  • Rewrote the table handler to use classes. This introduces a lot of new code, but will make table handling faster and better...
  • Added patch by Sasha for user defined variables.
  • Changed that FLOAT and DOUBLE (without any length modifiers) are not anymore fixed decimal point numbers.
  • Changed the meaning of FLOAT(X): Now this is the same as FLOAT if X <= 24 and a DOUBLE if 24 < X <= 53.
  • DECIMAL(X) is now an alias for DECIMAL(X,0) and DECIMAL is now an alias for DECIMAL(10,0). The same goes for NUMERIC.
  • Added option ROW_FORMAT={default | dynamic | static | compressed} to CREATE_TABLE.
  • DELETE FROM table_name didn't work on temporary tables.
  • Changed function CHAR_LENGTH() to be multi-byte character safe.
  • Added function ORD(string).

D.1.3 Changes in release 3.23.5

  • Fixed some Y2K problems in the new date handling in 3.23.
  • Fixed problem with SELECT DISTINCT ... ORDER BY RAND().
  • Added patches by Sergei A. Golubchik for text searching on the MyISAM level.
  • Fixed cache overflow problem when using full joins without keys.
  • Fixed some configure issues.
  • Some small changes to make parsing faster.
  • ALTER TABLE + adding a column after the last field didn't work.
  • Fixed problem when using an auto_increment column in two keys
  • One can now with MyISAM have the auto_increment part as a sub part: CREATE TABLE foo (a int not null auto_increment, b char(5), primary key (b,a))
  • Fixed bug in MyISAM with packed char keys that could be NULL.
  • AS on fieldname with CREATE TABLE table_name SELECT ... didn't work.
  • Allow use of NATIONAL and NCHAR when defining character columns. This is the same as not using BINARY.
  • Don't allow NULL columns in a PRIMARY KEY (only in UNIQUE keys).
  • Clear LAST_INSERT_ID if in uses this in ODBC: WHERE auto_increment_column IS NULL. This seams to fix some problems with Access.
  • SET SQL_AUTO_IS_NULL=0|1 now turns off/on the handling of searching after the last inserted row with WHERE auto_increment_column IS NULL.
  • Added new mysqld variable concurrency for Solaris.
  • Added option --relative to mysqladmin to make extended-status more useful to monitor changes.
  • Fixed bug when using COUNT(DISTINCT..) on an empty table.
  • Added support for the Chinese character set GBK.
  • Fixed problem with LOAD DATA INFILE and BLOB columns.
  • Added bit operator ~ (negation).
  • Fixed problem with UDF functions.

D.1.4 Changes in release 3.23.4

  • Inserting a DATETIME into a TIME column will not anymore try to store 'days' in it.
  • Fixed problem with storage of float/double on low endian machines. (This affected SUM().)
  • Added connect timeout on TCP/IP connections.
  • Fixed problem with LIKE "%" on a index that may have NULL values.
  • REVOKE ALL PRIVILEGES didn't revoke all privileges.
  • Allow creation of temporary tables with same name as the original table.
  • When granting a user a grant option for a database, he couldn't grant privileges to other users.
  • New command: SHOW GRANTS FOR user (by Sinisa).
  • New date_add syntax: date/datetime + INTERVAL # interval_type. By Joshua Chamas.
  • Fixed privilege check for LOAD DATA REPLACE.
  • Automatic fixing of broken include files on Solaris 2.7
  • Some configure issues to fix problems with big file system detection.
  • REGEXP is now case insensitive if you use not binary strings.

D.1.5 Changes in release 3.23.3

    Added patches for MIT-pthreads on NetBSD.

  • Fixed range bug in MyISAM.
  • ASC is now the default again for ORDER BY.
  • Added LIMIT to UPDATE.
  • New client function: mysql_change_user().
  • Added character set to SHOW VARIABLES.
  • Added support of --[whitespace] comments.
  • Allow INSERT into tbl_name VALUES (), that is, you may now specify an empty value list to insert a row in which each column is set to its default value.
  • Changed SUBSTRING(text FROM pos) to conform to ANSI SQL. (Before this construct returned the rightmost 'pos' characters).
  • SUM(..) with GROUP BY returned 0 on some systems.
  • Changed output for SHOW TABLE STATUS.
  • Added DELAY_KEY_WRITE option to CREATE TABLE.
  • Allow AUTO_INCREMENT on any key part.
  • Fixed problem with YEAR(NOW()) and YEAR(CURDATE()).
  • Added CASE construct.
  • New function COALESCE().

D.1.6 Changes in release 3.23.2

  • Fixed range optimizer bug: SELECT * FROM table_name WHERE key_part1 >= const AND (key_part2 = const OR key_part2 = const). The bug was that some rows could be duplicated in the result.
  • Running myisamchk without -a updated the index distribution wrong.
  • SET SQL_LOW_PRIORITY_UPDATES=1 gave parse error before.
  • You can now update indexes columns that are used in the WHERE clause. UPDATE tbl_name SET KEY=KEY+1 WHERE KEY > 100
  • Date handling should now be a bit faster.
  • Added handling of fuzzy dates (dates where day or month is 0): (Like: 1999-01-00)
  • Fixed optimization of SELECT ... WHERE key_part1=const1 AND key_part_2=const2 AND key_part1=const4 AND key_part2=const4 ; Indextype should be range instead of ref.
  • Fixed egcs 1.1.2 optimizer bug (when using BLOBs) on Linux Alpha.
  • Fixed problem with LOCK TABLES combined with DELETE FROM table.
  • MyISAM tables now allow keys on NULL and BLOB/TEXT columns.
  • The following join is now much faster: SELECT ... FROM t1 LEFT JOIN t2 ON ... WHERE t2.not_null_column IS NULL.
  • ORDER BY and GROUP BY can be done on functions.
  • Changed handling of 'const_item' to allow handling of ORDER BY RAND().
  • Indexes are now used for WHERE key_column = function.
  • Indexes are now used for WHERE key_column = column_name even if the columns are not identically packed.
  • Indexes are now used for WHERE column_name IS NULL.
  • Changed heap tables to be stored in low_byte_first order (to make it easy to convert to MyISAM tables)
  • Automatic change of HEAP temporary tables to MyISAM tables in case of 'table is full' errors.
  • Added option --init-file=file_name to mysqld.
  • COUNT(DISTINCT value,[value,...])
  • CREATE TEMPORARY TABLE now creates a temporary table, in its own namespace, that is automatically deleted if connection is dropped.
  • New keywords (required for CASE): CASE, THEN, WHEN, ELSE and END.
  • New functions EXPORT_SET() and MD5().
  • Support for the GB2312 Chinese character set.

D.1.7 Changes in release 3.23.1

  • Fixed some compilation problems.

D.1.8 Changes in release 3.23.0

    A new table handler library (MyISAM) with a lot of new features. See section 9.4 MySQL table types.

  • You can create in-memory HEAP tables which are extremely fast for lookups.
  • Support for big files (63 bit) on OSes that support big files.
  • New function LOAD_FILE(filename) to get the contents of a file as a string value.
  • New operator <=> which will act as = but will return TRUE if both arguments are NULL. This is useful for comparing changes between tables.
  • Added the ODBC 3.0 EXTRACT(interval FROM datetime) function.
  • Columns defined as FLOAT(X) is not rounded on storage and may be in scientific notation (1.0 E+10) when retrieved.
  • REPLACE is now faster than before.
  • Changed LIKE character comparison to behave as =; This means that 'e' LIKE ''e' is now true.
  • SHOW TABLE STATUS returns a lot of information about the tables.
  • Added LIKE to the SHOW STATUS command.
  • Added privilege column to SHOW COLUMNS.
  • Added columns packed and comment to SHOW INDEX.
  • Added comments to tables (with CREATE TABLE ... COMMENT "xxx").
  • Added UNIQUE, as in CREATE TABLE table_name (col int not null UNIQUE)
  • New create syntax: CREATE TABLE table_name SELECT ....
  • New create syntax: CREATE TABLE IF NOT EXISTS ...
  • Allow creation of CHAR(0) columns.
  • DATE_FORMAT() now requires `%' before any format character.
  • DELAYED is now a reserved word (sorry about that :( ).
  • An example procedure is added: analyse, file: `sql_analyse.c'. This will describe the data in your query. Try the following:
    SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])

    This procedure is extremely useful when you want to check the data in your table!

  • BINARY cast to force a string to be compared case sensitively.
  • Added option --skip-show-database to mysqld.
  • Check if a row has changed in an UPDATE now also works with BLOB/TEXT columns.
  • Added the INNER join syntax. NOTE: This made INNER an reserved word!
  • Added support for netmasks to the hostname in the MySQL tables. You can specify a netmask using the IP/NETMASK syntax.
  • If you compare a NOT NULL DATE/DATETIME column with IS NULL, this is changed to a compare against 0 to satisfy some ODBC applications. (By shreeve@uci.edu).
  • NULL IN (...) now returns NULL instead of 0. This will ensure that null_column NOT IN (...) doesn't match NULL values.
  • Fix storage of floating point values in TIME columns.
  • Changed parsing of TIME strings to be more strict. Now the fractional second part is detected (and currently skipped). The following formats are supported:
    [[DAYS] [H]H:]MM:]SS[.fraction]

    [[[[[H]H]H]H]MM]SS[.fraction]

  • Detect (and ignore) second fraction part from DATETIME.
  • Added the LOW_PRIORITY attribute to LOAD DATA INFILE.
  • The default index name now uses the same case as the used column name.
  • Changed default number of connections to 100.
  • Use bigger buffers when using LOAD DATA INFILE.
  • DECIMAL(x,y) now works according to ANSI SQL.
  • Added aggregate UDF functions. Thanks to Andreas F. Bobak
  • LAST_INSERT_ID() is now updated for INSERT INTO ... SELECT.
  • Some small changes to the join table optimizer to make some joins faster.
  • SELECT DISTINCT is much faster; It uses the new UNIQUE functionality in MyISAM. One difference compared to MySQL 3.22 is that the output of DISTINCT is not sorted anymore.
  • All C client API macros are now functions to make shared libraries more reliable. Because of this, you can no longer call mysql_num_fields() on a MYSQL object, you must use mysql_field_count() instead.
  • Added use of LIBEWRAP; Patch by Henning P . Schmiedehausen.
  • Don't allow AUTO_INCREMENT for other than numerical columns.
  • Using AUTO_INCREMENT will now automatically make the column NOT NULL.
  • Show NULL as the default value for AUTO_INCREMENT columns.
  • Added SQL_BIG_RESULT; SQL_SMALL_RESULT is now default.
  • Added a shared library RPM. This enchancement was contributed by David Fox (dsfox@cogsci.ucsd.edu).
  • Added a --enable-large-files/--disable-large-files switch to configure. See `configure.in' for some systems where this is automatically turned off because of broken implementations.
  • Upgraded readline to 4.0.
  • New CREATE TABLE options: PACK_KEYS and CHECKSUM.
  • Added mysqld option --default-table-type.

D.2 Changes in release 3.22.x

The 3.22 version has faster and safer connect code and a lot of new nice enhancements. The reason for not including these changes in the 3.21 version is mainly that we are trying to avoid big changes to 3.21 to keep it as stable as possible. As there aren't really any MAJOR changes, upgrading to 3.22 should be very easy and painless. See section 4.16.2 Upgrading from a 3.21 version to 3.22.

3.22 should also be used with the new DBD-mysql (1.20xx) driver that can use the new connect protocol!

D.2.1 Changes in release 3.22.28

  • Fixed problem with LEFT JOIN and COUNT() on a column which was declared NULL + and it had a DEFAULT value.
  • Fixed core dump problem when using CONCAT() in a WHERE clause.
  • Fixed problem with AVG() and STD() with NULL values.

D.2.2 Changes in release 3.22.27

  • Fixed prototype in `my_ctype.h' when using other character sets.
  • Some configure issues to fix problems with big file system detection.
  • Fixed problem when sorting on big blob columns.
  • ROUND() will now work on Win32.

D.2.3 Changes in release 3.22.26

  • Fixed core dump with empty BLOB/TEXT column to REVERSE().
  • Extended /*! */ with version numbers.
  • Changed SUBSTRING(text FROM pos) to conform to ANSI SQL. (Before this construct returned the rightmost 'pos' characters).
  • Fixed problem with LOCK TABLES combined with DELETE FROM table
  • Fixed problem that INSERT ... SELECT didn't use SQL_BIG_TABLES.
  • SET SQL_LOW_PRIORITY_UPDATES=# didn't work.
  • Password wasn't updated correctly if privileges didn't change on: GRANT ... IDENTIFIED BY
  • Fixed range optimizer bug in SELECT * FROM table_name WHERE key_part1 >= const AND (key_part2 = const OR key_part2 = const)
  • Fixed bug in compression key handling in ISAM.

D.2.4 Changes in release 3.22.25

  • Fixed some small problems with the installation.

D.2.5 Changes in release 3.22.24

  • DATA is not a reserved word anymore.
  • Fixed optimizer bug with tables with only one row.
  • Fixed bug when using LOCK TABLES table_name READ; FLUSH TABLES;
  • Applied some patches for HP-UX.
  • isamchk should now work on Win32.
  • Changed `configure' to not use big file handling on Linux as this crashes some RedHat 6.0 systems

D.2.6 Changes in release 3.22.23

  • Upgraded to use Autoconf 2.13, Automake 1.4 and libtool 1.3.2.
  • Better support for SCO in configure.
  • Added option --defaults-file=### to option file handling to force use of only one specific option file.
  • Extended CREATE syntax to ignore MySQL 3.23 keywords.
  • Fixed deadlock problem when using INSERT DELAYED on a table locked with LOCK TABLES.
  • Fixed deadlock problem when using DROP TABLE on a table that was locked by another thread.
  • Add logging of GRANT/REVOKE commands in the update log.
  • Fixed isamchk to detect a new error condition.
  • Fixed bug in NATURAL LEFT JOIN.

D.2.7 Changes in release 3.22.22

  • Fixed problem in the C API when you called mysql_close() directly after mysql_init().
  • Better client error message when you can't open socket.
  • Fixed delayed_insert_thread counting when you couldn't create a new delayed_insert thread.
  • Fixed bug in CONCAT() with many arguments.
  • Added patches for DEC 3.2 and SCO.
  • Fixed path-bug when installing MySQL as a service on NT.
  • The MySQL-Win32 version is now compiled with VC++ 6.0 instead of with VC++ 5.0.
  • New installation setup for MySQL-Win32.

D.2.8 Changes in release 3.22.21

  • Fixed problem with DELETE FROM TABLE when table was locked by another thread.
  • Fixed bug in LEFT JOIN involving empty tables.
  • Changed the mysql.db column from char(32) to char(60).
  • MODIFY and DELAYED are not reserved words anymore.
  • Fixed a bug when storing days in a TIME column.
  • Fixed a problem with Host '..' is not allowed to connect to this MySQL server after one had inserted a new MySQL user with a GRANT command.
  • Changed to use TCP_NODELAY also on Linux (Should give faster TCP/IP connections).

D.2.9 Changes in release 3.22.20

  • Fixed STD() for big tables when result should be 0.
  • The update log didn't have newlines on some operating systems.
  • INSERT DELAYED had some garbage at end in the update log.

D.2.10 Changes in release 3.22.19

  • Fixed bug in mysql_install_db (from 3.22.17).
  • Changed default key cache size to 8M.
  • Fixed problem with queries that needed temporary tables with BLOB columns.

D.2.11 Changes in release 3.22.18

  • Fixes a fatal problem in 3.22.17 on Linux; After shutdown all threads didn't die properly.
  • Added option -O flush-time=# to mysqld. This is mostly useful on Win32 and tells how often MySQL should close all unused tables and flush all updated tables to disk.
  • Fixed problem that a VARCHAR column compared with CHAR column didn't use keys efficiently.

D.2.12 Changes in release 3.22.17

  • Fixed a core dump problem when using --log-update and connecting without a default database.
  • Fixed some configure and portability problems.
  • Using LEFT JOIN on tables that had circular dependencies caused mysqld to hang forever.

D.2.13 Changes in release 3.22.16

  • mysqladmin processlist could kill the server if a new user logged in.
  • DELETE FROM tbl_name WHERE key_column=col_name didn't find any matching rows. Fixed.
  • DATE_ADD(column,...) didn't work.
  • INSERT DELAYED could deadlock with status 'upgrading lock'
  • Extended ENCRYPT() to take longer salt strings than 2 characters.
  • longlong2str is now much faster than before. For Intel x86 platforms, this function is written in optimized assembler.
  • Added the MODIFY keyword to ALTER TABLE.

D.2.14 Changes in release 3.22.15

  • GRANT used with IDENTIFIED BY didn't take effect until privileges were flushed.
  • Name change of some variables in SHOW STATUS.
  • Fixed problem with ORDER BY with 'only index' optimzation when there were multiple key definitions for a used column.
  • DATE and DATETIME columns are now up to 5 times faster than before.
  • INSERT DELAYED can be used to let the client do other things while the server inserts rows into a table.
  • LEFT JOIN USING (col1,col2) didn't work if one used it with tables from 2 different databases.
  • LOAD DATA LOCAL INFILE didn't work in the Unix version because of a missing file.
  • Fixed problems with VARCHAR/BLOB on very short rows (< 4 bytes); error 127 could occur when deleting rows.
  • Updating BLOB/TEXT through formulas didn't work for short (< 256 char) strings.
  • When you did a GRANT on a new host, mysqld could die on the first connect from this host.
  • Fixed bug when one used ORDER BY on column name that was the same name as an alias.
  • Added BENCHMARK(loop_count,expression) function to time expressions.

D.2.15 Changes in release 3.22.14

  • Allow empty arguments to mysqld to make it easier to start from shell scripts.
  • Setting a TIMESTAMP column to NULL didn't record the timestamp value in the update log.
  • Fixed lock handler bug when one did INSERT INTO TABLE ... SELECT ... GROUP BY.
  • Added a patch for localtime_r() on Win32 so that it will not crash anymore if your date is > 2039, but instead will return a time of all zero.
  • Names for user-defined functions are no longer case sensitive.
  • Added escape of ^Z (ASCII 26) to \Z as ^Z doesn't work with pipes on Win32.
  • mysql_fix_privileges adds a new column to the mysql.func to support aggregate UDF functions in future MySQL releases.

D.2.16 Changes in release 3.22.13

  • Saving NOW(), CURDATE() or CURTIME() directly in a column didn't work.
  • SELECT COUNT(*) ... LEFT JOIN ... didn't work with no WHERE part.
  • Updated `config.guess' to allow MySQL to configure on UnixWare 7.0.x.
  • Changed the implementation of pthread_cond() on the Win32 version. get_lock() now correctly times out on Win32!

D.2.17 Changes in release 3.22.12

  • Fixed problem when using DATE_ADD() and DATE_SUB() in a WHERE clause.
  • You can now set the password for a user with the GRANT ... TO user IDENTIFIED BY 'password' syntax.
  • Fixed bug in GRANT checking with SELECT on many tables.
  • Added missing file mysql_fix_privilege_tables to the RPM distribution. This is not run by default since it relies on the client package.
  • Added option SQL_SMALL_RESULT to SELECT to force use of fast temporary tables when you know that the result set will be small.
  • Allow use of negative real numbers without a decimal point.
  • Day number is now adjusted to maximum days in month if the resulting month after DATE_ADD/DATE_SUB() doesn't have enough days.
  • Fix that GRANT compares columns in case-insensitive fashion.
  • Fixed a bug in `sql_list.h' that made ALTER TABLE dump core in some contexts.
  • The hostname in user@hostname can now include `.' and `-' without quotes in the context of the GRANT, REVOKE and SET PASSWORD FOR ... statements.
  • Fix for isamchk for tables which need big temporary files.

D.2.18 Changes in release 3.22.11

  • IMPORTANT: You must run the mysql_fix_privilege_tables script when you upgrade to this version! This is needed because of the new GRANT system. If you don't do this, you will get Access denied when you try to use ALTER TABLE, CREATE INDEX or DROP INDEX.
  • GRANT to allow/deny users table and column access.
  • Changed USER() to return user@host
  • Changed the syntax for how to set PASSWORD for another user.
  • New command FLUSH STATUS that sets most status variables to zero.
  • New status variables: aborted_threads, aborted_connects.
  • New option variable: connection_timeout.
  • Added support for Thai sorting (by Pruet Boonma
  • Slovak and japanese error messages.
  • Configuration and portability fixes.
  • Added option SET SQL_WARNINGS=1 to get a warning count also for simple inserts.
  • MySQL now uses SIGTERM instead of SIGQUIT with shutdown to work better on FreeBSD.
  • Added option \G (print vertically) to mysql.
  • SELECT HIGH_PRIORITY ... killed mysqld.
  • IS NULL on a AUTO_INCREMENT column in a LEFT JOIN didn't work as expected.
  • New function MAKE_SET().

D.2.19 Changes in release 3.22.10

  • mysql_install_db no longer starts the MySQL server! You should start mysqld with safe_mysqld after installing it! The MySQL RPM will however start the server as before.
  • Added --bootstrap option to mysqld and recoded mysql_install_db to use it. This will make it easier to install MySQL with RPMs.
  • Changed +, - (sign and minus), *, /, %, ABS() and MOD() to be BIGINT aware (64-bit safe).
  • Fixed a bug in ALTER TABLE that caused mysqld to crash.
  • MySQL now always reports the conflicting key values when a duplicate key entry occurs. (Before this was only reported for INSERT).
  • New syntax: INSERT INTO tbl_name SET col_name=value,col_name=value,...
  • Most errors in the `.err' log are now prefixed with a time stamp.
  • Added option MYSQL_INIT_COMMAND to mysql_options() to make a query on connect or reconnect.
  • Added option MYSQL_READ_DEFAULT_FILE and MYSQL_READ_DEFAULT_GROUP to mysql_options() to read the following parameters from the MySQL option files: port, socket, compress, password, pipe, timeout, user, init-command, host and database.
  • Added maybe_null to the UDF structure.
  • Added option IGNORE to INSERT statemants with many rows.
  • Fixed some problems with sorting of the koi8 character sets; Users of koi8 MUST run isamchk -rq on each table that has an index on a CHAR or VARCHAR column.
  • New script mysql_setpermission, by Luuk de Boer, allows one to easily create new users with permissions for specific databases.
  • Allow use of hexadecimal strings (0x...) when specifying a constant string (like in the column separators with LOAD DATA INFILE).
  • Ported to OS/2 (thanks to Antony T. Curtis antony.curtis@olcs.net).
  • Added more variables to SHOW STATUS and changed format of output to be like SHOW VARIABLES.
  • Added extended-status command to mysqladmin which will show the new status variables.

D.2.20 Changes in release 3.22.9

  • SET SQL_LOG_UPDATE=0 caused a lockup of the server.
  • New SQL command: FLUSH [ TABLES | HOSTS | LOGS | PRIVILEGES ] [, ...]
  • New SQL command: KILL thread_id.
  • Added casts and changed include files to make MySQL easier to compile on AIX and DEC OSF1 4.x
  • Fixed conversion problem when using ALTER TABLE from a INT to a short CHAR() column.
  • Added SELECT HIGH_PRIORITY; This will get a lock for the SELECT even if there is a thread waiting for another SELECT to get a WRITE LOCK.
  • Moved wild_compare to string class to be able to use LIKE on BLOB/TEXT columns with \0.
  • Added ESCAPE option to LIKE.
  • Added a lot more output to mysqladmin debug.
  • You can now start mysqld on Win32 with the --flush option. This will flush all tables to disk after each update. This makes things much safer on NT/Win98 but also MUCH slower.

D.2.21 Changes in release 3.22.8

  • Czech character sets should now work much better. You must also install ftp://www.mysql.com/pub/mysql/Downloads/Patches/czech-3.22.8-patch. This patch should also be installed if you are using a character set with uses my_strcoll()! The patch should always be safe to install (for any system), but as this patch changes ISAM internals it's not yet in the default distribution.
  • DATE_ADD() and DATE_SUB() didn't work with group functions.
  • mysql will now also try to reconnect on USE DATABASE commands.
  • Fix problem with ORDER BY and LEFT JOIN and const tables.
  • Fixed problem with ORDER BY if the first ORDER BY column was a key and the rest of the ORDER BY columns wasn't part of the key.
  • Fixed a big problem with OPTIMIZE TABLE.
  • MySQL clients on NT will now by default first try to connect with named pipes and after this with TCP/IP.
  • Fixed a problem with DROP TABLE and mysqladmin shutdown on Win32 (a fatal bug from 3.22.6).
  • Fixed problems with TIME columns and negative strings.
  • Added an extra thread signal loop on shutdown to avoid some error messages from the client.
  • MySQL now uses the next available number as extension for the update log file.
  • Added patches for UNIXWARE 7.

D.2.22 Changes in release 3.22.7

  • Added LIMIT clause for the DELETE statement.
  • You can now use the /*! ... */ syntax to hide MySQL-specific keywords when you write portable code. MySQL will parse the code inside the comments as if the surrounding /*! and */ comment characters didn't exist.
  • OPTIMIZE TABLE tbl_name can now be used to reclaim disk space after many deletes. Currently, this uses ALTER TABLE to re-generate the table, but in the future it will use an integrated isamchk for more speed.
  • Upgraded libtool to get the configure more portable.
  • Fixed slow UPDATE and DELETE operations when using DATETIME or DATE keys.
  • Changed optimizer to make it better at deciding when to do a full join and when using keys.
  • You can now use mysqladmin proc to display information about your own threads. Only users with the Process_priv privilege can get information about all threads.
  • Added handling of formats YYMMDD, YYYYMMDD, YYMMDDHHMMSS for numbers when using DATETIME and TIMESTAMP types. (Formerly these formats only worked with strings.)
  • Added connect option CLIENT_IGNORE_SPACE to allow use of spaces after function names and before `(' (Powerbuilder requires this). This will make all function names reserved words.
  • Added the --log-long-format option to mysqld to enable timestamps and INSERT_ID's in the update log.
  • Added --where option to mysqldump (patch by Jim Faucette).
  • The lexical analyzer now uses ``perfect hashing'' for faster parsing of SQL statements.

D.2.23 Changes in release 3.22.6

  • Faster mysqldump.
  • For the LOAD DATA INFILE statement, you can now use the new LOCAL keyword to read the file from the client. mysqlimport will automatically use LOCAL when importing with the TCP/IP protocol.
  • Fixed small optimize problem when updating keys.
  • Changed makefiles to support shared libraries.
  • MySQL-NT can now use named pipes, which means that you can now use MySQL-NT without having to install TCP/IP.

D.2.24 Changes in release 3.22.5

  • All table lock handing is changed to avoid some very subtle deadlocks when using DROP TABLE, ALTER TABLE, DELETE FROM TABLE and mysqladmin flush-tables under heavy usage. Changed locking code to get better handling of locks of different types.
  • Updated DBI to 1.00 and DBD to 1.2.0.
  • Added a check that the error message file contains error messages suitable for the current version of mysqld. (To avoid errors if you accidentally try to use an old error message file.)
  • All count structures in the client (affected_rows(), insert_id(),...) are now of type BIGINT to allow 64-bit values to be used. This required a minor change in the MySQL protocol which should affect only old clients when using tables with AUTO_INCREMENT values > 24M.
  • The return type of mysql_fetch_lengths() has changed from uint * to ulong *. This may give a warning for old clients but should work on most machines.
  • Change mysys and dbug libraries to allocate all thread variables in one struct. This makes it easier to make a threaded `libmysql.dll' library.
  • Use the result from gethostname() (instead of uname()) when constructing `.pid' file names.
  • New better compressed server/client protocol.
  • COUNT(), STD() and AVG() are extended to handle more than 4G rows.
  • You can now store values in the range -838:59:59 <= x <= 838:59:59 in a TIME column.
  • WARNING: INCOMPATIBLE CHANGE!! If you set a TIME column to too short a value, MySQL now assumes the value is given as: [[[D ]HH:]MM:]SS instead of HH[:MM[:SS]].
  • TIME_TO_SEC() and SEC_TO_TIME() can now handle negative times and hours up to 32767.
  • Added new option SET OPTION SQL_LOG_UPDATE={0|1} to allow users with the process privilege to bypass the update log. (Modified patch from Sergey A Mukhin violet@rosnet.net.)
  • Fixed fatal bug in LPAD().
  • Initialize line buffer in `mysql.cc' to make BLOB reading from pipes safer.
  • Added -O max_connect_errors=# option to mysqld. Connect errors are now reset for each correct connection.
  • Increased the default value of max_allowed_packet to 1M in mysqld.
  • Added --low-priority-updates option to mysqld, to give table-modifying operations (INSERT, REPLACE, UPDATE, DELETE) lower priority than retrievals. You can now use {INSERT | REPLACE | UPDATE | DELETE} LOW_PRIORITY ... You can also use SET OPTION SQL_LOW_PRIORITY_UPDATES={0|1} to change the priority for one thread. One side effect is that LOW_PRIORITY is now a reserved word. :(
  • Add support for INSERT INTO table ... VALUES(...),(...),(...), to allow inserting multiple rows with a single statement.
  • INSERT INTO tbl_name is now also cached when used with LOCK TABLES. (Previously only INSERT ... SELECT and LOAD DATA INFILE were cached.)
  • Allow GROUP BY functions with HAVING:
    mysql> SELECT col FROM table GROUP BY col HAVING COUNT(*)>0;
  • mysqld will now ignore trailing `;' characters in queries. This is to make it easier to migrate from some other SQL servers that require the trailing `;'.
  • Fix for corrupted fixed-format output generated by SELECT INTO OUTFILE.
  • WARNING: INCOMPATIBLE CHANGE!! Added Oracle GREATEST() and LEAST() functions. You must now use these instead of the MAX() and MIN() functions to get the largest/smallest value from a list of values. These can now handle REAL, BIGINT and string (CHAR or VARCHAR) values.
  • WARNING: INCOMPATIBLE CHANGE!! DAYOFWEEK() had offset 0 for Sunday. Changed the offset to 1.
  • Give an error for queries that mix GROUP BY columns and fields when there is no GROUP BY specification.
  • Added --vertical option to mysql, for printing results in vertical mode.
  • Index-only optimization; some queries are now resolved using only indexes. Until MySQL 4.0, this works only for numeric columns. See section 10.4 MySQL index use.
  • Lots of new benchmarks.
  • A new C API chapter and lots of other improvements in the manual.

D.2.25 Changes in release 3.22.4

  • Added --tmpdir option to mysqld, for specifying the location of the temporary file directory.
  • MySQL now automatically changes a query from an ODBC client:
    SELECT ... FROM table WHERE auto_increment_column IS NULL

    to:

    SELECT ... FROM table WHERE auto_increment_column == LAST_INSERT_ID()

    This allows some ODBC programs (Delphi, Access) to retrieve the newly inserted row to fetch the AUTO_INCREMENT id.

  • DROP TABLE now waits for all users to free a table before deleting it.
  • Fixed small memory leak in the new connect protocol.
  • New functions BIN(), OCT(), HEX() and CONV() for converting between different number bases.
  • Added function SUBSTRING() with 2 arguments.
  • If you created a table with a record length smaller than 5, you couldn't delete rows from the table.
  • Added optimization to remove const reference tables from ORDER BY and GROUP BY.
  • mysqld now automatically disables system locking on Linux and Win32, and for systems that use MIT-pthreads. You can force the use of locking with the --enable-locking option.
  • Added --console option to mysqld, to force a console window (for error messages) when using Win32.
  • Fixed table locks for Win32.
  • Allow `$' in identifiers.
  • Changed name of user-specific configuration file from `my.cnf' to `.my.cnf' (Unix only).
  • Added DATE_ADD() and DATE_SUB() functions.

D.2.26 Changes in release 3.22.3

  • Fixed a lock problem (bug in MySQL 3.22.1) when closing temporary tables.
  • Added missing mysql_ping() to the client library.
  • Added --compress option to all MySQL clients.
  • Changed byte to char in `mysql.h' and `mysql_com.h'.

D.2.27 Changes in release 3.22.2

  • Searching on multiple constant keys that matched more than 30% of the rows didn't always use the best possible key.
  • New functions <<, >>, RPAD() and LPAD().
  • You can now save default options (like passwords) in a configuration file (`my.cnf').
  • Lots of small changes to get ORDER BY to work when no records are found when using fields that are not in GROUP BY (MySQL extension).
  • Added --chroot option to mysqld, to start mysqld in a chroot environment (by Nikki Chumakov nikkic@cityline.ru).
  • Trailing spaces are now ignored when comparing case-sensitive strings; this should fix some problems with ODBC and flag 512!
  • Fixed a core-dump bug in the range optimizer.
  • Added --one-thread option to mysqld, for debugging with LinuxThreads (or glibc). (This replaces the -T32 flag)
  • Added DROP TABLE IF EXISTS to prevent an error from occurring if the table doesn't exist.
  • IF and EXISTS are now reserved words (they would have to be sooner or later).
  • Added lots of new options to mysqldump.
  • Server error messages are now in `mysqld_error.h'.
  • The server/client protocol now supports compression.
  • All bug fixes from MySQL 3.21.32.

D.2.28 Changes in release 3.22.1

  • Added new C API function mysql_ping().
  • Added new API functions mysql_init() and mysql_options(). You now MUST call mysql_init() before you call mysql_real_connect(). You don't have to call mysql_init() if you only use mysql_connect().
  • Added mysql_options(...,MYSQL_OPT_CONNECT_TIMEOUT,...) so you can set a timeout for connecting to a server.
  • Added --timeout option to mysqladmin, as a test of mysql_options().
  • Added AFTER column and FIRST options to ALTER TABLE ... ADD columns. This makes it possible to add a new column at some specific location within a row in an existing table.
  • WEEK() now takes an optional argument to allow handling of weeks when the week starts on Monday (some European countries). By default, WEEK() assumes the week starts on Sunday.
  • TIME columns weren't stored properly (bug in MySQL 3.22.0).
  • UPDATE now returns information about how many rows were matched and updated, and how many ``warnings'' occurred when doing the update.
  • Fixed incorrect result from FORMAT(-100,2).
  • ENUM and SET columns were compared in binary (case-sensitive) fashion; changed to be case insensitive.

D.2.29 Changes in release 3.22.0

  • New (backward compatible) connect protocol that allows you to specify the database to use when connecting, to get much faster connections to a specific database. The mysql_real_connect() call is changed to:
    mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
                   const char *passwd, const char *db, uint port,
                   const char *unix_socket, uint client_flag)
  • Each connection is handled by its own thread, rather than by the master accept() thread. This fixes permanently the telnet bug that was a topic on the mail list some time ago.
  • All TCP/IP connections are now checked with backward resolution of the hostname to get better security. mysqld now has a local hostname resolver cache so connections should actually be faster than before, even with this feature.
  • A site automatically will be blocked from future connections if someone repeatedly connects with an ``improper header'' (like when one uses telnet).
  • You can now refer to tables in different databases with references of the form tbl_name@db_name or db_name.tbl_name. This makes it possible to give a user read access to some tables and write access to others simply by keeping them in different databases!
  • Added --user option to mysqld, to allow it to run as another Unix user (if it is started as the Unix root user).
  • Added caching of users and access rights (for faster access rights checking)
  • Normal users (not anonymous ones) can change their password with mysqladmin password 'new_password'. This uses encrypted passwords that are not logged in the normal MySQL log!
  • All important string functions are now coded in assembler for x86 Linux machines. This gives a speedup of 10% in many cases.
  • For tables that have many columns, the column names are now hashed for much faster column name lookup (this will speed up some benchmark tests a lot!)
  • Some benchmarks are changed to get better individual timing. (Some loops were so short that a specific test took < 2 seconds. The loops have been changed to take about 20 seconds to make it easier to compare different databases. A test that took 1-2 seconds before now takes 11-24 seconds, which is much better)
  • Re-arranged SELECT code to handle some very specific queries involving group functions (like COUNT(*)) without a GROUP BY but with HAVING. The following now works:
    mysql> SELECT count(*) as C FROM table HAVING C > 1;
  • Changed the protocol for field functions to be faster and avoid some calls to malloc().
  • Added -T32 option to mysqld, for running all queries under the main thread. This makes it possible to debug mysqld under Linux with gdb!
  • Added optimization of not_null_column IS NULL (needed for some Access queries).
  • Allow STRAIGHT_JOIN to be used between two tables to force the optimizer to join them in a specific order.
  • String functions now return VARCHAR rather than CHAR and the column type is now VARCHAR for fields saved as VARCHAR. This should make the MyODBC driver better, but may break some old MySQL clients that don't handle FIELD_TYPE_VARCHAR the same way as FIELD_TYPE_CHAR.
  • CREATE INDEX and DROP INDEX are now implemented through ALTER TABLE. CREATE TABLE is still the recommended (fast) way to create indexes.
  • Added --set-variable option wait_timeout to mysqld.
  • Added time column to mysqladmin processlist to show how long a query has taken or how long a thread has slept.
  • Added lots of new variables to show variables and some new to show status.
  • Added new type YEAR. YEAR is stored in 1 byte with allowable values of 0, and 1901 to 2155.
  • Added new DATE type that is stored in 3 bytes rather than 4 bytes. All new tables are created with the new date type if you don't use the --old-protocol option to mysqld.
  • Fixed bug in record caches; for some queries, you could get Error from table handler: # on some operating systems.
  • Added --enable-assembler option to configure, for x86 machines (tested on Linux + gcc). This will enable assembler functions for the most important string functions for more speed!

D.3 Changes in release 3.21.x

D.3.1 Changes in release 3.21.33

  • Fixed problem when sending SIGHUP to mysqld; mysqld core dumped when starting from boot on some systems.
  • Fixed problem with losing a little memory for some connections.
  • DELETE FROM tbl_name without a WHERE condition is now done the long way when you use LOCK TABLES or if the table is in use, to avoid race conditions.
  • INSERT INTO TABLE (timestamp_column) VALUES (NULL); didn't set timestamp.

D.3.2 Changes in release 3.21.32

  • Fixed some possible race conditions when doing many reopen/close on the same tables under heavy load! This can happen if you execute mysqladmin refresh often. This could in some very rare cases corrupt the header of the index file and cause error 126 or 138.
  • Fixed fatal bug in refresh() when running with the --skip-locking option. There was a ``very small'' time gap after a mysqladmin refresh when a table could be corrupted if one thread updated a table while another thread did mysqladmin refresh and another thread started a new update ont the same table before the first thread had finished. A refresh (or --flush-tables) will now not return until all used tables are closed!
  • SELECT DISTINCT with a WHERE clause that didn't match any rows returned a row in some contexts (bug only in 3.21.31).
  • GROUP BY + ORDER BY returned one empty row when no rows where found.
  • Fixed a bug in the range optimizer that wrote Use_count: Wrong count for ... in the error log file.

D.3.3 Changes in release 3.21.31

  • Fixed a sign extension problem for the TINYINT type on Irix.
  • Fixed problem with LEFT("constant_string",function).
  • Fixed problem with FIND_IN_SET().
  • LEFT JOIN core dumped if the second table is used with a constant WHERE/ON expression that uniquely identifies one record.
  • Fixed problems with DATE_FORMAT() and incorrect dates. DATE_FORMAT() now ignores '%' to make it possible to extend it more easily in the future.

D.3.4 Changes in release 3.21.30

  • mysql now returns an exit code > 0 if the query returned an error.
  • Saving of command line history to file in mysql client. By Tommy Larsen tommy@mix.hive.no.
  • Fixed problem with empty lines that were ignored in `mysql.cc'.
  • Save the pid of the signal handler thread in the pid file instead of the pid of the main thread.
  • Added patch by tommy@valley.ne.jp to support Japanese characters SJIS and UJIS.
  • Changed safe_mysqld to redirect startup messages to 'hostname'.err instead of 'hostname'.log to reclaim file space on mysqladmin refresh.
  • ENUM always had the first entry as default value.
  • ALTER TABLE wrote two entries to the update log.
  • sql_acc() now closes the mysql grant tables after a reload to save table space and memory.
  • Changed LOAD DATA to use less memory with tables and BLOB columns.
  • Sorting on a function which made a division / 0 produced a wrong set in some cases.
  • Fixed SELECT problem with LEFT() when using the czech character set.
  • Fixed problem in isamchk; it couldn't repair a packed table in a very unusual case.
  • SELECT statements with & or | (bit functions) failed on columns with NULL values.
  • When comparing a field = field, where one of the fields was a part key, only the length of the part key was compared.

D.3.5 Changes in release 3.21.29

  • LOCK TABLES + DELETE from tbl_name never removed locks properly.
  • Fixed problem when grouping on an OR function.
  • Fixed permission problem with umask() and creating new databases.
  • Fixed permission problem on result file with SELECT ... INTO OUTFILE ...
  • Fixed problem in range optimizer (core dump) for a very complex query.
  • Fixed problem when using MIN(integer) or MAX(integer) in GROUP BY.
  • Fixed bug on Alpha when using integer keys. (Other keys worked on Alpha).
  • Fixed bug in WEEK("XXXX-xx-01").

D.3.6 Changes in release 3.21.28

  • Fixed socket permission (clients couldn't connect to Unix socket on Linux).
  • Fixed bug in record caches; for some queries, you could get Error from table handler: # on some operating systems.

D.3.7 Changes in release 3.21.27

  • Added user level lock functions GET_LOCK(string,timeout), RELEASE_LOCK(string).
  • Added opened_tables to show status.
  • Changed connect timeout to 3 seconds to make it somewhat harder for crackers to kill mysqld through telnet + TCP/IP.
  • Fixed bug in range optimizer when using WHERE key_part_1 >= something AND key_part_2 <= something_else.
  • Changed configure for detection of FreeBSD 3.0 9803xx and above
  • WHERE with string_column_key = constant_string didn't always find all rows if the column had many values differing only with characters of the same sort value (like e and 'e).
  • Strings keys looked up with 'ref' were not compared in case-sensitive fashion.
  • Added umask() to make log files non-readable for normal users.
  • Ignore users with old (8-byte) password on startup if not using --old-protocol option to mysqld.
  • SELECT which matched all key fields returned the values in the case of the matched values, not of the found values. (Minor problem.)

D.3.8 Changes in release 3.21.26

  • FROM_DAYS(0) now returns "0000-00-00".
  • In DATE_FORMAT(), PM and AM were swapped for hours 00 and 12.
  • Extended the default maximum key size to 256.
  • Fixed bug when using BLOB/TEXT in GROUP BY with many tables.
  • An ENUM field that is not declared NOT NULL has NULL as the default value. (Previously, the default value was the first enumeration value.)
  • Fixed bug in the join optimizer code when using many part keys on the same key: INDEX (Organization,Surname(35),Initials(35)).
  • Added some tests to the table order optimizer to get some cases with SELECT ... FROM many_tables much faster.
  • Added a retry loop around accept() to possibly fix some problems on some Linux machines.

D.3.9 Changes in release 3.21.25

  • Changed typedef 'string' to typedef 'my_string' for better portability.
  • You can now kill threads that are waiting on a disk full condition.
  • Fixed some problems with UDF functions.
  • Added long options to isamchk. Try isamchk --help.
  • Fixed a bug when using 8 bytes long (alpha); filesort() didn't work. Affects DISTINCT, ORDER BY and GROUP BY on 64-bit processors.

D.3.10 Changes in release 3.21.24

  • Dynamic loadable functions. Based on source from Alexis Mikhailov.
  • You couldn't delete from a table if no one had done a SELECT on the table.
  • Fixed problem with range optimizer with many OR operators on key parts inside each other.
  • Recoded MIN() and MAX() to work properly with strings and HAVING.
  • Changed default umask value for new files from 0664 to 0660.
  • Fixed problem with LEFT JOIN and constant expressions in the ON part.
  • Added Italian error messages from brenno@dewinter.com.
  • configure now works better on OSF1 (tested on 4.0D).
  • Added hooks to allow LIKE optimization with international character support.
  • Upgraded DBI to 0.93.

D.3.11 Changes in release 3.21.23

  • The following symbols are now reserved words: TIME, DATE, TIMESTAMP, TEXT, BIT, ENUM, NO, ACTION, CHECK, YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, STATUS, VARIABLES.
  • Setting a TIMESTAMP to NULL in LOAD DATA INFILE ... didn't set the current time for the TIMESTAMP.
  • Fix BETWEEN to recognize binary strings. Now BETWEEN is case sensitive.
  • Added --skip-thread-priority option to mysqld, for systems where mysqld's thread scheduling doesn't work properly (BSDI 3.1).
  • Added ODBC functions DAYNAME() and MONTHNAME().
  • Added function TIME_FORMAT(). This works like DATE_FORMAT(), but takes a time string ('HH:MM:DD') as argument.
  • Fixed unlikely(?) key optimizer bug when using ORs of key parts inside ANDs.
  • Added command variables to mysqladmin.
  • A lot of small changes to the binary releases.
  • Fixed a bug in the new protocol from MySQL 3.21.20.
  • Changed ALTER TABLE to work with Win32 (Win32 can't rename open files). Also fixed a couple of small bugs in the Win32 version.
  • All standard MySQL clients are now ported to MySQL-Win32.
  • MySQL can now be started as a service on NT.

D.3.12 Changes in release 3.21.22

  • Starting with this version, all MySQL distributions will be configured, compiled and tested with crash-me and the benchmarks on the following platforms: SunOS 5.6 sun4u, SunOS 5.5.1 sun4u, SunOS 4.14 sun4c, SunOS 5.6 i86pc, Irix 6.3 mips5k, HP-UX 10.20 hppa, AIX 4.2.1 ppc, OSF1 V4.0 alpha, FreeBSD 2.2.2 i86pc and BSDI 3.1 i386.
  • Fix COUNT(*) problems when the WHERE clause didn't match any records. (Bug from 3.21.17.)
  • Removed that NULL = NULL is true. Now you must use IS NULL or IS NOT NULL to test whether or not a value is NULL. (This is according to ANSI SQL but may break old applications that are ported from mSQL.) You can get the old behavior by compiling with -DmSQL_COMPLIANT.
  • Fixed bug that core dumped when using many LEFT OUTER JOIN clauses.
  • Fixed bug in ORDER BY on string formula with possible NULL values.
  • Fixed problem in range optimizer when using <= on sub index.
  • Added functions DAYOFYEAR(), DAYOFMONTH(), MONTH(),
    YEAR(), WEEK(), QUARTER(), HOUR(), MINUTE(),
    SECOND() and FIND_IN_SET().
  • Added command SHOW VARIABLES.
  • Added support of ``long constant strings'' from ANSI SQL:
    mysql> SELECT 'first ' 'second';       -> 'first second'
  • Upgraded mSQL-Mysql-modules to 1.1825.
  • Upgraded mysqlaccess to 2.02.
  • Fixed problem with Russian character set and LIKE.
  • Ported to OpenBSD 2.1.
  • New Dutch error messages.

D.3.13 Changes in release 3.21.21a

  • Configure changes for some operating systems.

D.3.14 Changes in release 3.21.21

  • Fixed optimizer bug when using WHERE data_field = date_field2 AND date_field2 = constant.
  • Added command SHOW STATUS.
  • Removed `manual.ps' from the source distribution to make it smaller.

D.3.15 Changes in release 3.21.20

  • Changed the maximum table name and column name lengths from 32 to 64.
  • Aliases can now be of ``any'' length.
  • Fixed mysqladmin stat to return the right number of queries.
  • Changed protocol (downward compatible) to mark if a column has the AUTO_INCREMENT attribute or is a TIMESTAMP. This is needed for the new Java driver.
  • Added Hebrew sorting order by Zeev Suraski.
  • Solaris 2.6: Fixed configure bugs and increased maximum table size from 2G to 4G.

D.3.16 Changes in release 3.21.19

  • Upgraded DBD to 1823. This version implements mysql_use_result in DBD-Mysql.
  • Benchmarks updated for empress (by Luuk).
  • Fixed a case of slow range searching.
  • Configure fixes (`Docs' directory).
  • Added function REVERSE() (by Zeev Suraski).

D.3.17 Changes in release 3.21.18

  • Issue error message if client C functions are called in wrong order.
  • Added automatic reconnect to the `libmysql.c' library. If a write command fails, an automatic reconnect is done.
  • Small sort sets no longer use temporary files.
  • Upgraded DBI to 0.91.
  • Fixed a couple of problems with LEFT OUTER JOIN.
  • Added CROSS JOIN syntax. CROSS is now a reserved word.
  • Recoded yacc/bison stack allocation to be even safer and to allow MySQL to handle even bigger expressions.
  • Fixed a couple of problems with the update log.
  • ORDER BY was slow when used with key ranges.

D.3.18 Changes in release 3.21.17

  • Changed documentation string of --with-unix-socket-path to avoid confusion.
  • Added ODBC and ANSI SQL style LEFT OUTER JOIN.
  • The following are new reserved words: LEFT, NATURAL, USING.
  • The client library now uses the value of the environment variable MYSQL_HOST as the default host if it's defined.
  • SELECT col_name, SUM(expr) now returns NULL for col_name when there are matching rows.
  • Fixed problem with comparing binary strings and BLOBs with ASCII characters over 127.
  • Fixed lock problem: when freeing a read lock on a table with multiple read locks, a thread waiting for a write lock would have been given the lock. This shouldn't affect data integrity, but could possibly make mysqld restart if one thread was reading data that another thread modified.
  • LIMIT offset,count didn't work in INSERT ... SELECT.
  • Optimized key block caching. This will be quicker than the old algorithm when using bigger key caches.

D.3.19 Changes in release 3.21.16

  • Added ODBC 2.0 & 3.0 functions POWER(), SPACE(), COT(), DEGREES(), RADIANS(), ROUND(2 arg) and TRUNCATE().
  • WARNING: INCOMPATIBLE CHANGE!! LOCATE() parameters were swapped according to ODBC standard. Fixed.
  • Added function TIME_TO_SEC().
  • In some cases, default values were not used for NOT NULL fields.
  • Timestamp wasn't always updated properly in UPDATE SET ... statements.
  • Allow empty strings as default values for BLOB and TEXT, to be compatible with mysqldump.

D.3.20 Changes in release 3.21.15

  • WARNING: INCOMPATIBLE CHANGE!! mysqlperl is now from Msql-Mysql-modules. This means that connect() now takes host, database, user, password arguments! The old version took host, database, password, user.
  • Allow DATE '1997-01-01', TIME '12:10:10' and TIMESTAMP '1997-01-01 12:10:10' formats required by ANSI SQL. WARNING: INCOMPATIBLE CHANGE!! This has the unfortunate side-effect that you no longer can have columns named DATE, TIME or TIMESTAMP. :( Old columns can still be accessed through tablename.columnname!)
  • Changed Makefiles to hopefully work better with BSD systems. Also, `manual.dvi' is now included in the distribution to avoid having stupid make programs trying to rebuild it.
  • readline library upgraded to version 2.1.
  • A new sortorder german-1. That is a normal ISO-Latin1 with a german sort order.
  • Perl DBI/DBD is now included in the distribution. DBI is now the recommended way to connect to MySQL from Perl.
  • New portable benchmark suite with DBD, with test results from mSQL 2.0.3, MySQL, PostgreSQL 6.2.1 and Solid server 2.2.
  • crash-me is now included with the benchmarks; This is a Perl program designed to find as many limits as possible in a SQL server. Tested with mSQL, PostgreSQL, Solid and MySQL.
  • Fixed bug in range-optimizer that crashed MySQL on some queries.
  • Table and column name completion for mysql command line tool, by Zeev Suraski and Andi Gutmans.
  • Added new command REPLACE that works like INSERT but replaces conflicting records with the new record. REPLACE INTO TABLE ... SELECT ... works also.
  • Added new commands CREATE DATABASE db_name and DROP DATABASE db_name.
  • Added RENAME option to ALTER TABLE: ALTER TABLE name RENAME AS new_name.
  • make_binary_distribution now includes `libgcc.a' in `libmysqlclient.a'. This should make linking work for people who don't have gcc.
  • Changed net_write() to my_net_write() because of a name conflict with Sybase.
  • New function DAYOFWEEK() compatible with ODBC.
  • Stack checking and bison memory overrun checking to make MySQL safer with weird queries.

D.3.21 Changes in release 3.21.14b

  • Fixed a couple of small configure problems on some platforms.

D.3.22 Changes in release 3.21.14a

  • Ported to SCO Openserver 5.0.4 with FSU Pthreads.
  • HP-UX 10.20 should work.
  • Added new function DATE_FORMAT().
  • Added NOT IN.
  • Added automatic removal of 'ODBC function conversions': {fn now() }
  • Handle ODBC 2.50.3 option flags.
  • Fixed comparison of DATE and TIME values with NULL.
  • Changed language name from germany to german to be consistent with the other language names.
  • Fixed sorting problem on functions returning a FLOAT. Previously, the values were converted to INTs before sorting.
  • Fixed slow sorting when sorting on key field when using key_column=constant.
  • Sorting on calculated DOUBLE values sorted on integer results instead.
  • mysql no longer needs a database argument.
  • Changed the place where HAVING should be. According to ANSI, it should be after GROUP BY but before ORDER BY. MySQL 3.20 incorrectly had it last.
  • Added Sybase command USE DATABASE to start using another database.
  • Added automatic adjusting of number of connections and table cache size if the maximum number of files that can be opened is less than needed. This should fix that mysqld doesn't crash even if you haven't done a ulimit -n 256 before starting mysqld.
  • Added lots of limit checks to make it safer when running with too little memory or when doing weird queries.

D.3.23 Changes in release 3.21.13

  • Added retry of interrupted reads and clearing of errno. This makes Linux systems much safer!
  • Fixed locking bug when using many aliases on the same table in the same SELECT.
  • Fixed bug with LIKE on number key.
  • New error message so you can check whether the connection was lost while the command was running or whether the connection was down from the start.
  • Added --table option to mysql to print in table format. Moved time and row information after query result. Added automatic reconnect of lost connections.
  • Added != as a synonym for <>.
  • Added function VERSION() to make easier logs.
  • New multi-user test `tests/fork_test.pl' to put some strain on the thread library.

D.3.24 Changes in release 3.21.12

  • Fixed ftruncate() call in MIT-pthreads. This made isamchk destroy the `.ISM' files on (Free)BSD 2.x systems.
  • Fixed broken __P_ patch in MIT-pthreads.
  • Many memory overrun checks. All string functions now return NULL if the returned string should be longer than max_allowed_packet bytes.
  • Changed the name of the INTERVAL type to ENUM, because INTERVAL is used in ANSI SQL.
  • In some cases, doing a JOIN + GROUP + INTO OUTFILE, the result wasn't grouped.
  • LIKE with '_' as last character didn't work. Fixed.
  • Added extended ANSI SQL TRIM() function.
  • Added CURTIME().
  • Added ENCRYPT() function by Zeev Suraski.
  • Fixed better FOREIGN KEY syntax skipping. New reserved words: MATCH, FULL, PARTIAL.
  • mysqld now allows IP number and hostname to the --bind-address option.
  • Added SET OPTION CHARACTER SET cp1251_koi8 to enable conversions of data to/from cp1251_koi8.
  • Lots of changes for Win95 port. In theory, this version should now be easily portable to Win95.
  • Changed the CREATE COLUMN syntax of NOT NULL columns to be after the DEFAULT value, as specified in the ANSI SQL standard. This will make mysqldump with NOT NULL and default values incompatible with MySQL 3.20.
  • Added many function name aliases so the functions can be used with ODBC or ANSI SQL92 syntax.
  • Fixed syntax of ALTER TABLE tbl_name ALTER COLUMN col_name SET DEFAULT NULL.
  • Added CHAR and BIT as synonyms for CHAR(1).
  • Fixed core dump when updating as a user who has only select privilege.
  • INSERT ... SELECT ... GROUP BY didn't work in some cases. An Invalid use of group function error occurred.
  • When using LIMIT, SELECT now always uses keys instead of record scan. This will give better performance on SELECT and a WHERE that matches many rows.
  • Added Russian error messages.

D.3.25 Changes in release 3.21.11

  • Configure changes.
  • MySQL now works with the new thread library on BSD/OS 3.0.
  • Added new group functions BIT_OR() and BIT_AND().
  • Added compatibility functions CHECK and REFERENCES. CHECK is now a reserved word.
  • Added ALL option to GRANT for better compatibility. (GRANT is still a dummy function.)
  • Added partly-translated dutch messages.
  • Fixed bug in ORDER BY and GROUP BY with NULL columns.
  • Added function last_insert_id() to retrieve last AUTO_INCREMENT value. This is intended for clients to ODBC that can't use the mysql_insert_id() API function, but can be used by any client.
  • Added --flush-logs option to mysqladmin.
  • Added command STATUS to mysql.
  • Fixed problem with ORDER BY/GROUP BY because of bug in gcc.
  • Fixed problem with INSERT ... SELECT ... GROUP BY.

D.3.26 Changes in release 3.21.10

  • New mysqlaccess.
  • CREATE now supports all ODBC types and the mSQL TEXT type. All ODBC 2.5 functions are also supported (added REPEAT). This provides better portability.
  • Added text types TINYTEXT, TEXT, MEDIUMTEXT and LONGTEXT. These are actually BLOBtypes, but all searching is done in case-insensitive fashion.
  • All old BLOB fields are now TEXT fields. This only changes that all searching on strings is done in case-sensitive fashion. You must do an ALTER TABLE and change the field type to BLOB if you want to have tests done in case-sensitive fashion.
  • Fixed some configure issues.
  • Made the locking code a bit safer. Fixed very unlikely deadlock situation.
  • Fixed a couple of bugs in the range optimizer. Now the new range benchmark test-select works.

D.3.27 Changes in release 3.21.9

  • Added --enable-unix-socket=pathname option to configure.
  • Fixed a couple of portability problems with include files.
  • Fixed bug in range calculation that could return empty set when searching on multiple key with only one entry (very rare).
  • Most things ported to FSU Pthreads, which should allow MySQL to run on SCO. See section 4.11.13 SCO notes.

D.3.28 Changes in release 3.21.8

  • Works now in Solaris 2.6.
  • Added handling of calculation of SUM() functions. For example, you can now use SUM(column)/COUNT(column).
  • Added handling of trigometric functions: PI(), ACOS(), ASIN(), ATAN(), COS(), SIN() and TAN().
  • New languages: norwegian, norwegian-ny and portuguese.
  • Fixed parameter bug in net_print() in `procedure.cc'.
  • Fixed a couple of memory leaks.
  • Now allow also the old SELECT ... INTO OUTFILE syntax.
  • Fixed bug with GROUP BY and SELECT on key with many values.
  • mysql_fetch_lengths() sometimes returned incorrect lengths when you used mysql_use_result(). This affected at least some cases of mysqldump --quick.
  • Fixed bug in optimization of WHERE const op field.
  • Fixed problem when sorting on NULL fields.
  • Fixed a couple of 64-bit (Alpha) problems.
  • Added --pid-file=# option to mysqld.
  • Added date formatting to FROM_UNIXTIME(), originally by Zeev Suraski.
  • Fixed bug in BETWEEN in range optimizer (Did only test = of the first argument).
  • Added machine-dependent files for MIT-pthreads i386-SCO. There is probably more to do to get this to work on SCO 3.5.

D.3.29 Changes in release 3.21.7

  • Changed `Makefile.am' to take advantage of Automake 1.2.
  • Added the beginnings of a benchmark suite.
  • Added more secure password handling.
  • Added new client function mysql_errno(), to get the error number of the error message. This makes error checking in the client much easier. This makes the new server incompatible with the 3.20.x server when running without --old-protocol. The client code is backward compatible. More information can be found in the `README' file!
  • Fixed some problems when using very long, illegal names.

D.3.30 Changes in release 3.21.6

  • Fixed more portability issues (incorrect sigwait and sigset defines).
  • configure should now be able to detect the last argument to accept().

D.3.31 Changes in release 3.21.5

  • Should now work with FreeBSD 3.0 if used with `FreeBSD-3.0-libc_r-1.0.diff', which can be found at http://www.mysql.com/Download/Patches.
  • Added new option -O tmp_table_size=# to mysqld.
  • New function FROM_UNIXTIME(timestamp) which returns a date string in 'YYYY-MM-DD HH:MM:DD' format.
  • New function SEC_TO_TIME(seconds) which returns a string in 'HH:MM:SS' format.
  • New function SUBSTRING_INDEX(), originally by Zeev Suraski.

D.3.32 Changes in release 3.21.4

  • Should now configure and compile on OSF1 4.0 with the DEC compiler.
  • Configuration and compilation on BSD/OS 3.0 works, but due to some bugs in BSD/OS 3.0, mysqld doesn't work on it yet.
  • Configuration and compilation on FreeBSD 3.0 works, but I couldn't get pthread_create to work.

D.3.33 Changes in release 3.21.3

  • Added reverse check lookup of hostnames to get better security.
  • Fixed some possible buffer overflows if filenames that are too long are used.
  • mysqld doesn't accept hostnames that start with digits followed by a '.', because the hostname may look like an IP number.
  • Added --skip-networking option to mysqld, to only allow socket connections. (This will not work with MIT-pthreads!)
  • Added check of too long table names for alias.
  • Added check if database name is okay.
  • Added check if too long table names.
  • Removed incorrect free() that killed the server on CREATE DATABASE or DROP DATABASE.
  • Changed some mysqld -O options to better names.
  • Added -O join_cache_size=# option to mysqld.
  • Added -O max_join_size=# option to mysqld, to be able to set a limit how big queries (in this case big = slow) one should be able to handle without specifying SET OPTION SQL_BIG_SELECTS=1. A # = is about 10 examined records. The default is ``unlimited''.
  • When comparing a TIME, DATE, DATETIME or TIMESTAMP column to a constant, the constant is converted to a time value before performing the comparison. This will make it easier to get ODBC (particularly Access97) to work with the above types. It should also make dates easier to use and the comparisons should be quicker than before.
  • Applied patch from Jochen Wiedmann that allows query() in mysqlperl to take a query with \0 in it.
  • Storing a timestamp with a 2-digit year (YYMMDD) didn't work.
  • Fix that timestamp wasn't automatically updated if set in an UPDATE clause.
  • Now the automatic timestamp field is the FIRST timestamp field.
  • SELECT * INTO OUTFILE, which didn't correctly if the outfile already existed.
  • mysql now shows the thread ID when starting or doing a reconnect.
  • Changed the default sort buffer size from 2M to 1M.

D.3.34 Changes in release 3.21.2

  • The range optimizer is coded, but only 85% tested. It can be enabled with --new, but it crashes core a lot yet...
  • More portable. Should compile on AIX and alpha-digital. At least the isam library should be relatively 64-bit clean.
  • New isamchk which can detect and fix more problems.
  • New options for isamlog.
  • Using new version of Automake.
  • Many small portability changes (from the AIX and alpha-digital port) Better checking of pthread(s) library.
  • czech error messages by snajdr@pvt.net.
  • Decreased size of some buffers to get fewer problems on systems with little memory. Also added more checks to handle ``out of memory'' problems.
  • mysqladmin: you can now do mysqladmin kill 5,6,7,8 to kill multiple threads.
  • When the maximum connection limit is reached, one extra connection by a user with the PROCESS_ACL privilege is granted.
  • Added -O backlog=# option to mysqld.
  • Increased maximum packet size from 512K to 1024K for client.
  • Almost all of the function code is now tested in the internal test suite.
  • ALTER TABLE now returns warnings from field conversions.
  • Port changed to 3306 (got it reserved from ISI).
  • Added a fix for Visual FoxBase so that any schema name from a table specification is automatically removed.
  • New function ASCII().
  • Removed function BETWEEN(a,b,c). Use the standard ANSI synax instead: expr BETWEEN expr AND expr.
  • MySQL no longer has to use an extra temporary table when sorting on functions or SUM() functions.
  • Fixed bug that you couldn't use tbl_name.field_name in UPDATE.
  • Fixed SELECT DISTINCT when using 'hidden group'. For example:
    mysql> SELECT DISTINCT MOD(some_field,10) FROM test
           GROUP BY some_field;

    Note: some_field is normally in the SELECT part. ANSI SQL should require it.

D.3.35 Changes in release 3.21.0

  • New keywords used: INTERVAL, EXPLAIN, READ, WRITE, BINARY.
  • Added ODBC function CHAR(num,...).
  • New operator IN. This uses a binary search to find a match.
  • New command LOCK TABLES tbl_name [AS alias] {READ|WRITE} ...
  • Added --log-update option to mysqld, to get a log suitable for incremental updates.
  • New command EXPLAIN SELECT ... to get information about how the optimizer will do the join.
  • For easier client code, the client should no longer use FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB or FIELD_TYPE_VAR_STRING (as previously returned by mysql_list_fields). You should instead only use FIELD_TYPE_BLOB or FIELD_TYPE_STRING. If you want exact types, you should use the command SHOW FIELDS.
  • Added varbinary syntax: 0x###### which can be used as a string (default) or a number.
  • FIELD_TYPE_CHAR is renamed to FIELD_TYPE_TINY.
  • Changed all fields to C++ classes.
  • Removed FORM struct.
  • Fields with DEFAULT values no longer need to be NOT NULL.
  • New field types:
    ENUM
    A string which can take only a couple of defined values. The value is stored as a 1-3 byte number that is mapped automatically to a string. This is sorted according to string positions!
    SET
    A string which may have one or many string values separated with ','. The string is stored as a 1-, 2-, 3-, 4- or 8-byte number where each bit stands for a specific set member. This is sorted according to the unsigned value of the stored packed number.
  • Now all function calculation is done with double or long long. This will provide the full 64-bit range with bit functions and fix some conversions that previously could result in precision losses. One should avoid using unsigned long long columns with full 64-bit range (numbers bigger than 9223372036854775807) because calculations are done with signed long long.
  • ORDER BY will now put NULL field values first. GROUP BY will also work with NULL values.
  • Full WHERE with expressions.
  • New range optimizer that can resolve ranges when some keypart prefix is constant. Example:
    mysql> SELECT * FROM tbl_name
           WHERE key_part_1="customer"
           AND key_part_2>=10 AND key_part_2<=10;

21.3 Changes in release 3.20.x

Changes from 3.20.18 to 3.20.32b are not documented here since the 3.21 release branched here. And the relevant changes are also documented as changes to the 3.21 version.

D.3.36 Changes in release 3.20.18

  • Added -p# (remove # directories from path) to isamlog. All files are written with a relative path from the database directory Now mysqld shouldn't crash on shutdown when using the --log-isam option.
  • New mysqlperl version. It is now compatible with msqlperl-0.63.
  • New DBD module available at http://www.mysql.com/Contrib site.
  • Added group function STD() (standard deviation).
  • The mysqld server is now compiled by default without debugging information. This will make the daemon smaller and faster.
  • Now one usually only has to specify the --basedir option to mysqld. All other paths are relative in a normal installation.
  • BLOB columns sometimes contained garbage when used with a SELECT on more than one table and ORDER BY.
  • Fixed that calculations that are not in GROUP BY work as expected (ANSI SQL extension). Example:
    mysql> SELECT id,id+1 FROM table GROUP BY id;
  • The test of using MYSQL_PWD was reversed. Now MYSQL_PWD is enabled as default in the default release.
  • Fixed conversion bug which caused mysqld to core dump with Arithmetic error on Sparc-386.
  • Added --unbuffered option to mysql, for new mysqlaccess.
  • When using overlapping (unnecessary) keys and join over many tables, the optimizer could get confused and return 0 records.

D.3.37 Changes in release 3.20.17

  • You can now use BLOB columns and the functions IS NULL and IS NOT NULL in the WHERE clause.
  • All communication packets and row buffers are now allocated dynamically on demand. The default value of max_allowed_packet is now 64K for the server and 512K for the client. This is mainly used to catch incorrect packets that could trash all memory. The server limit may be changed when it is started.
  • Changed stack usage to use less memory.
  • Changed safe_mysqld to check for running daemon.
  • The ELT() function is renamed to FIELD(). The new ELT() function returns a value based on an index: FIELD() is the inverse of ELT() Example: ELT(2,"A","B","C") returns "B". FIELD("B","A","B","C") returns 2.
  • COUNT(field), where field could have a NULL value, now works.
  • A couple of bugs fixed in SELECT ... GROUP BY.
  • Fixed memory overrun bug in WHERE with many unoptimizable brace levels.
  • Fixed some small bugs in the grant code.
  • If hostname isn't found by get_hostname, only the IP is checked. Previously, you got Access denied.
  • Inserts of timestamps with values didn't always work.
  • INSERT INTO ... SELECT ... WHERE could give the error Duplicated field.
  • Added some tests to safe_mysqld to make it ``safer''.
  • LIKE was case sensitive in some places and case insensitive in others. Now LIKE is always case insensitive.
  • `mysql.cc': Allow '#' anywhere on the line.
  • New command SET OPTION SQL_SELECT_LIMIT=#. See the FAQ for more details.
  • New version of the mysqlaccess script.
  • Change FROM_DAYS() and WEEKDAY() to also take a full TIMESTAMP or DATETIME as argument. Before they only took a number of type YYYYMMDD or YYMMDD.
  • Added new function UNIX_TIMESTAMP(timestamp_column).

D.3.38 Changes in release 3.20.16

  • More changes in MIT-pthreads to get them safer. Fixed also some link bugs at least in SunOS.
  • Changed mysqld to work around a bug in MIT-pthreads. This makes multiple small SELECT operations 20 times faster. Now lock_test.pl should work.
  • Added mysql_FetchHash(handle) to mysqlperl.
  • The mysqlbug script is now distributed built to allow for reporting bugs that appear during the build with it.
  • Changed `libmysql.c' to prefer getpwuid() instead of cuserid().
  • Fixed bug in SELECT optimizer when using many tables with the same column used as key to different tables.
  • Added new latin2 and Russian KOI8 character tables.
  • Added support for a dummy GRANT command to satisfy Powerbuilder.

D.3.39 Changes in release 3.20.15

  • Fixed fatal bug packets out of order when using MIT-pthreads.
  • Removed possible loop when a thread waits for command from client and fcntl() fails. Thanks to Mike Bretz for finding this bug.
  • Changed alarm loop in `mysqld.cc' because shutdown didn't always succeed in Linux.
  • Removed use of termbits from `mysql.cc'. This conflicted with glibc 2.0.
  • Fixed some syntax errors for at least BSD and Linux.
  • Fixed bug when doing a SELECT as superuser without a database.
  • Fixed bug when doing SELECT with group calculation to outfile.

D.3.40 Changes in release 3.20.14

  • If one gives -p or --password option to mysql without an argument, the user is solicited for the password from the tty.
  • Added default password from MYSQL_PWD (by Elmar Haneke).
  • Added command kill to mysqladmin to kill a specific MySQL thread.
  • Sometimes when doing a reconnect on a down connection this succeeded first on second try.
  • Fixed adding an AUTO_INCREMENT key with ALTER_TABLE.
  • AVG() gave too small value on some SELECTs with GROUP BY and ORDER BY.
  • Added new DATETIME type (by Giovanni Maruzzelli
  • Fixed that define DONT_USE_DEFAULT_FIELDS works.
  • Changed to use a thread to handle alarms instead of signals on Solaris to avoid race conditions.
  • Fixed default length of signed numbers. (George Harvey
  • Allow anything for CREATE INDEX.
  • Add prezeros when packing numbers to DATE, TIME and TIMESTAMP.
  • Fixed a bug in OR of multiple tables (gave empty set).
  • Added many patches to MIT-pthreads. This fixes at least one lookup bug.

D.3.41 Changes in release 3.20.13

  • Added ANSI SQL94 DATE and TIME types.
  • Fixed bug in SELECT with AND-OR levels.
  • Added support for Slovenian characters. The `Contrib' directory contains source and instructions for adding other character sets.
  • Fixed bug with LIMIT and ORDER BY.
  • Allow ORDER BY and GROUP BY on items that aren't in the SELECT list. (Thanks to Wim Bonis bonis@kiss.de, for pointing this out.)
  • Allow setting of timestamp values in INSERT.
  • Fixed bug with SELECT ... WHERE ... = NULL.
  • Added changes for glibc 2.0. To get glibc to work, you should add the `gibc-2.0-sigwait-patch' before compiling glibc.
  • Fixed bug in ALTER TABLE when changing a NOT NULL field to allow NULL values.
  • Added some ANSI92 synonyms as field types to CREATE TABLE. CREATE TABLE now allows FLOAT(4) and FLOAT(8) to mean FLOAT and DOUBLE.
  • New utility program mysqlaccess by Yves.Carlier@rug.ac.be. This program shows the access rights for a specific user and the grant rows that determine this grant.
  • Added WHERE const op field (by bonis@kiss.de).

D.3.42 Changes in release 3.20.11

  • When using SELECT ... INTO OUTFILE, all temporary tables are ISAM instead of HEAP to allow big dumps.
  • Changed date functions to be string functions. This fixed some ``funny'' side effects when sorting on dates.
  • Extended ALTER TABLE according to SQL92.
  • Some minor compability changes.
  • Added --port and --socket options to all utility programs and mysqld.
  • Fixed MIT-pthreads readdir_r(). Now mysqladmin create database and mysqladmin drop database should work.
  • Changed MIT-pthreads to use our tempnam(). This should fix the ``sort aborted'' bug.
  • Added sync of records count in sql_update. This fixed slow updates on first connection. (Thanks to Vaclav Bittner for the test.)

D.3.43 Changes in release 3.20.10

  • New insert type: INSERT INTO ... SELECT ...
  • MEDIUMBLOB fixed.
  • Fixed bug in ALTER TABLE and BLOBs.
  • SELECT ... INTO OUTFILE now creates the file in the current database directory.
  • DROP TABLE now can take a list of tables.
  • Oracle synonym DESCRIBE (DESC).
  • Changes to make_binary_distribution.
  • Added some comments to installation instructions about configure's C++ link test.
  • Added --without-perl option to configure.
  • Lots of small portability changes.

D.3.44 Changes in release 3.20.9

  • ALTER TABLE didn't copy null bit. As a result, fields that were allowed to have NULL values were always NULL.
  • CREATE didn't take numbers as DEFAULT.
  • Some compatibility changes for SunOS.
  • Removed `config.cache' from old distribution.

D.3.45 Changes in release 3.20.8

  • Fixed bug with ALTER TABLE and multi-part keys.

D.3.46 Changes in release 3.20.7

  • New commands: ALTER TABLE, SELECT ... INTO OUTFILE and LOAD DATA INFILE.
  • New function: NOW().
  • Added new field file_priv to mysql/user table.
  • New script add_file_priv which adds the new field file_priv to the user table. This script must be executed if you want to use the new SELECT ... INTO and LOAD DATA INFILE ... commands with a version of MySQL earlier than 3.20.7.
  • Fixed bug in locking code, which made lock_test.pl test fail.
  • New files `NEW' and `BUGS'.
  • Changed `select_test.c' and `insert_test.c' to include `config.h'.
  • Added command status to mysqladmin for short logging.
  • Increased maximum number of keys to 16 and maximum number of key parts to 15.
  • Use of sub keys. A key may now be a prefix of a string field.
  • Added -k option to mysqlshow, to get key information for a table.
  • Added long options to mysqldump.

D.3.47 Changes in release 3.20.6

  • Portable to more systems because of MIT-pthreads, which will be used automatically if configure cannot find a -lpthreads library.
  • Added GNU-style long options to almost all programs. Test with program --help.
  • Some shared library support for Linux.
  • The FAQ is now in `.texi' format and is available in `.html', `.txt' and `.ps' formats.
  • Added new SQL function RAND([init]).
  • Changed sql_lex to handle \0 unquoted, but the client can't send the query through the C API, because it takes a str pointer. You must use mysql_real_query() to send the query.
  • Added API function mysql_get_client_info().
  • mysqld now uses the N_MAX_KEY_LENGTH from `nisam.h' as the maximum allowed key length.
  • The following now works:
    mysql> SELECT filter_nr,filter_nr FROM filter ORDER BY filter_nr;

    Previously, this resulted in the error: Column: 'filter_nr' in order clause is ambiguous.

  • mysql now outputs '\0', '\t', '\n' and '\\' when encountering ASCII 0, tab, newline or '\' while writing tab-separated output. This is to allow printing of binary data in a portable format. To get the old behavior, use -r (or --raw).
  • Added german error messages (60 of 80 error messages translated).
  • Added new API function mysql_fetch_lengths(MYSQL_RES *), which returns an array of of column lengths (of type uint).
  • Fixed bug with IS NULL in WHERE clause.
  • Changed the optimizer a little to get better results when searching on a key part.
  • Added SELECT option STRAIGHT_JOIN to tell the optimizer that it should join tables in the given order.
  • Added support for comments starting with '--' in `mysql.cc' (Postgres syntax).
  • You can have SELECT expressions and table columns in a SELECT which are not used in the group part. This makes it efficient to implement lookups. The column that is used should be a constant for each group because the value is calculated only once for the first row that is found for a group.
    mysql> SELECT id,lookup.text,sum(*) FROM test,lookup
         WHERE test.id=lookup.id GROUP BY id;
  • Fixed bug in SUM(function) (could cause a core dump).
  • Changed AUTO_INCREMENT placement in the SQL query:
    INSERT into table (auto_field) values (0);

    inserted 0, but it should insert an AUTO_INCREMENT value.

  • `mysqlshow.c': Added number of records in table. Had to change the client code a little to fix this.
  • mysql now allows doubled '' or "" within strings for embedded ' or ".
  • New math functions: EXP(), LOG(), SQRT(), ROUND(), CEILING().

D.3.48 Changes in release 3.20.3

  • The configure source now compiles a thread-free client library -lmysqlclient. This is the only library that needs to be linked with client applications. When using the binary releases, you must link with -lmysql -lmysys -ldbug -lstrings as before.
  • New readline library from bash-2.0.
  • LOTS of small changes to configure and makefiles (and related source).
  • It should now be possible to compile in another directory using VPATH. Tested with GNU Make 3.75.
  • safe_mysqld and mysql.server changed to be more compatible between the source and the binary releases.
  • LIMIT now takes one or two numeric arguments. If one argument is given, it indicates the maximum number of rows in a result. If two arguments are given, the first argument indicates the offset of the first row to return, the second is the maximum number of rows. With this it's easy to do a poor man's next page/previous page WWW application.
  • Changed name of SQL function FIELDS() to ELT(). Changed SQL function INTERVALL() to INTERVAL().
  • Made SHOW COLUMNS a synonym for SHOW FIELDS. Added compatibility syntax FRIEND KEY to CREATE TABLE. In MySQL, this creates a non-unique key on the given columns.
  • Added CREATE INDEX and DROP INDEX as compatibility functions. In MySQL, CREATE INDEX only checks if the index exists and issues an error if it doesn't exist. DROP INDEX always succeeds.
  • `mysqladmin.c': added client version to version information.
  • Fixed core dump bug in sql_acl (core on new connection).
  • Removed host, user and db tables from database test in the distribution.
  • FIELD_TYPE_CHAR can now be signed (-128 - 127) or unsigned (0 - 255) Previously, it was always unsigned.
  • Bug fixes in CONCAT() and WEEKDAY().
  • Changed a lot of source to get mysqld to be compiled with SunPro compiler.
  • SQL functions must now have a '(' immediately after the function name (no intervening space). For example, 'user(' is regarded as beginning a function call, and 'user (' is regarded as an identifier user followed by a '(', not as a function call.

D.3.49 Changes in release 3.20.0

  • The source distribution is done with configure and Automake. It will make porting much easier. The readline library is included in the distribution.
  • Separate client compilation: the client code should be very easy to compile on systems which don't have threads.
  • The old Perl interface code is automatically compiled and installed. Automatic compiling of DBD will follow when the new DBD code is ported.
  • Dynamic language support: mysqld can now be started with Swedish or English (default) error messages.
  • New functions: INSERT(), RTRIM(), LTRIM() and FORMAT().
  • mysqldump now works correctly for all field types (even AUTO_INCREMENT). The format for SHOW FIELDS FROM tbl_name is changed so the Type column contains information suitable for CREATE TABLE. In previous releases, some CREATE TABLE information had to be patched when recreating tables.
  • Some parser bugs from 3.19.5 (BLOB and TIMESTAMP) are corrected. TIMESTAMP now returns different date information depending on its create length.
  • Changed parser to allow a database, table or field name to start with a number or '_'.
  • All old C code from Unireg changed to C++ and cleaned up. This makes the daemon a little smaller and easier to understand.
  • A lot of small bug fixes done.
  • New `INSTALL' files (not final version) and some info regarding porting.

D.4 Changes in release 3.19.x

D.4.1 Changes in release 3.19.5

  • Some new functions, some more optimization on joins.
  • Should now compile clean on Linux (2.0.x).
  • Added functions DATABASE(), USER(), POW(), LOG10() (needed for ODBC).
  • In a WHERE with an ORDER BY on fields from only one table, the table is now preferred as first table in a multi-join.
  • HAVING and IS NULL or IS NOT NULL now works.
  • A group on one column and a sort on a group function (SUM(), AVG()...) didn't work together. Fixed.
  • mysqldump: Didn't send password to server.

D.4.2 Changes in release 3.19.4

  • Fixed horrible locking bug when inserting in one thread and reading in another thread.
  • Fixed one-off decimal bug. 1.00 was output as 1.0.
  • Added attribute 'Locked' to process list as info if a query is locked by another query.
  • Fixed full magic timestamp. Timestamp length may now be 14, 12, 10, 8, 6, 4 or 2 bytes.
  • Sort on some numeric functions could sort incorrectly on last number.
  • IF(arg,syntax_error,syntax_error) crashed.
  • Added functions CEILING(), ROUND(), EXP(), LOG() and SQRT().
  • Enhanced BETWEEN to handle strings.

D.4.3 Changes in release 3.19.3

  • Fixed SELECT with grouping on BLOB columns not to return incorrect BLOB info. Grouping, sorting and distinct on BLOB columns will not yet work as expected (probably it will group/sort by the first 7 characters in the BLOB). Grouping on formulas with a fixed string size (use MID() on a BLOB) should work.
  • When doing a full join (no direct keys) on multiple tables with BLOB fields, the BLOB was garbage on output.
  • Fixed DISTINCT with calculated columns.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - G Comments on porting to other systems

Go to the first, previous, next, last section, table of contents.

G Comments on porting to other systems

A working Posix thread library is needed for the server. On Solaris 2.5 we use SUN PThreads (the native thread support in 2.4 and earlier versions are not good enough) and on Linux we use LinuxThreads by Xavier Leroy, Xavier.Leroy@inria.fr.

The hard part of porting to a new Unix variant without good native thread support is probably to port MIT-pthreads. See `mit-pthreads/README' and Programming POSIX Threads.

The MySQL distribution includes a patched version of Provenzano's Pthreads from MIT (see MIT Pthreads web page). This can be used for some operating systems that do not have POSIX threads.

It is also possible to use another user level thread package named FSU Pthreads (see FSU Pthreads home page). This implementation is being used for the SCO port.

See the `thr_lock.c' and `thr_alarm.c' programs in the `mysys' directory for some tests/examples of these problems.

Both the server and the client need a working C++ compiler (we use gcc and have tried SparcWorks). Another compiler that is known to work is the Irix cc.

To compile only the client use ./configure --without-server.

There is currently no support for only compiling the server. Nor is it likly to be added unless someone has a good reason for it.

If you want/need to change any `Makefile' or the configure script you must get Automake and Autoconf. We have used the automake-1.2 and autoconf-2.12 distributions.

All steps needed to remake everything from the most basic files.

/bin/rm */.deps/*.P
/bin/rm -f config.cache
aclocal
autoheader
aclocal
automake
autoconf
./configure --with-debug --prefix='your installation directory'

# The makefiles generated above need GNU make 3.75 or newer.
# (called gmake below)
gmake clean all install init-db

If you run into problems with a new port, you may have to do some debugging of MySQL! See section G.1 Debugging a MySQL server.

Note: Before you start debugging mysqld, first get the test programs mysys/thr_alarm and mysys/thr_lock to work. This will ensure that your thread installation has even a remote chance to work!

G.1 Debugging a MySQL server

If you are using some functionality that is very new in MySQL, you can try to run mysqld with the --skip-new (which will disable all new, potentially unsafe functionality) or with --safe-mode which disables a lot of optimization that may cause problems. See section 18.1 What to do if MySQL keeps crashing.

If mysqld doesn't want to start, you should check that you don't have any my.cnf file that interferes with your setup! You can check your my.cnf arguments with mysqld --print-defaults and avoid using them by starting with mysqld --no-defaults ....

If you have some very specific problem, you can always try to debug MySQL. To do this you must configure MySQL with the option --with-debug. You can check whether or not MySQL was compiled with debugging by doing: mysqld --help. If the --debug flag is listed with the options then you have debugging enabled. mysqladmin ver also lists the mysqld version as mysql ... -debug in this case.

If you are using gcc or egcs, the recommended configure line is:

CC=gcc CFLAGS="-O6" CXX=gcc CXXFLAGS="-O6 -felide-constructors -fno-exceptions -fno-rtti" ./configure --prefix=/usr/local/mysql --with-debug

This will avoid problems with the libstdc++ library and with C++ exceptions.

If you can cause the mysqld server to crash quickly, you can try to create a trace file of this:

Start the mysqld server with a trace log in `/tmp/mysql.trace'. The log file will get very BIG.

mysqld --debug --log

or you can start it with

mysqld --debug=d,info,error,query,general,where:O,/tmp/mysql.trace

which only prints information with the most interesting tags.

When you configure MySQL for debugging you automatically enable a lot of extra safety check functions that monitor the health of mysqld. If they find something ``unexpected,'' an entry will be written to stderr, which safe_mysqld directs to the error log! This also means that if you are having some unexpected problems with MySQL and are using a source distribution, the first thing you should do is to configure MySQL for debugging! (The second thing, of course, is to send mail to mysql@lists.mysql.com and ask for help. Please use the mysqlbug script for all bug reports or questions regarding the MySQL version you are using!

On most system you can also start mysqld from gdb to get more information if mysqld crashes.

With some gdb versions on Linux you must use run --one-thread if you want to be able to debug mysqld threads. In this case you can only have one thread active at a time.

If you are using gdb 4.17.x on Linux, you should install a `.gdb' file, with the following information, in your current directory:

set print sevenbit off
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
handle SIGWAITING nostop noprint
handle SIGLWP nostop noprint
handle SIGPIPE nostop
handle SIGALRM nostop
handle SIGHUP nostop
handle SIGTERM nostop noprint

Here follows an example how to debug mysqld:

shell> gdb /usr/local/libexec/mysqld
gdb> run
...
back   # Do this when mysqld crashes
info locals
up
info locals
up
...
(until you get some information about local variables)

quit

Include the above output in a mail generated with mysqlbug and mail this to mysql@lists.mysql.com.

If mysqld hangs you can try to use some system tools like strace or /usr/proc/bin/pstack to examine where mysqld has hanged.

If mysqld starts to eat up CPU or memory or if it ``hangs'', you can use mysqladmin processlist status to find out if someone is executing some query that takes a long time. It may be a good idea to run mysqladmin -i10 processlist status in some window if you are experiencing performance problems or problems when new clients can't connect.

If mysqld dies or hangs, you should start mysqld with --log. When mysqld dies again, you can check in the log file for the query that killed mysqld. Note that before starting mysqld with --log you should check all your tables with myisamchk. See section 13 Maintaining a MySQL installation.

If you are using a log file, mysqld --log, you should check the 'hostname' log files, that you can find in the database directory, for any queries that could cause a problem. Try the command EXPLAIN on all SELECT statements that takes a long time to ensure that mysqld are using indexes properly. See section 7.22 EXPLAIN syntax (Get information about a SELECT). You should also test complicated queries that didn't complete within the mysql command line tool.

If you find the text mysqld restarted in the error log file (normally named `hostname.err') you have probably found a query that causes mysqld to fail. If this happens you should check all your tables with myisamchk (see section 13 Maintaining a MySQL installation), and test the queries in the MySQL log files if someone doesn't work. If you find such a query, try first upgrading to the newest MySQL version. If this doesn't help and you can't find anything in the mysql mail archive, you should report the bug to mysql@lists.mysql.com. Links to mail archives are available at the online MySQL documentation page.

If you get corrupted tables or if mysqld always fails after some update commands, you can test if this bug is reproducible by doing the following:

  • Stop the mysqld daemon (with mysqladmin shutdown)
  • Check all tables with myisamchk -s database/*.MYI. Repair any wrong tables with myisamchk -r database/table.MYI.
  • Start mysqld with --log-update
  • When you have got a crashed table, stop the mysqld server.
  • Restore the backup.
  • Restart the mysqld server without --log-update
  • Re-execute the commands with mysql < update-log. The update log is saved in the MySQL database directory with the name your-hostname.#.
  • If the tables are now again corrupted, you have found reproducible bug in the ISAM code! FTP the tables and the update log to ftp://www.mysql.com/pub/mysql/secret and we will fix this as soon as possible!

The command mysqladmin debug will dump some information about locks in use, used memory and query usage to the mysql log file. This may help solve some problems. This command also provides some useful information even if you haven't compiled MySQL for debugging!

If the problem is that some tables are getting slower and slower you should try to optimize the table with OPTIMIZE TABLE or myisamchk. See section 13 Maintaining a MySQL installation. You should also check the slow queries with EXPLAIN.

You should also read the OS-specific section in this manual for problems that may be unique to your environment. See section 4.11 System-specific issues.

If you are using the Perl DBI interface, you can turn on debugging information by using the trace method or by setting the DBI_TRACE environment variable. See section 20.5.2 The DBI interface.

G.2 Debugging a MySQL client

To be able to debug a MySQL client with the integrated debug package, you should configure MySQL with --with-debug. See section 4.7.3 Typical configure options.

Before running a client, you should set the MYSQL_DEBUG environment variable:

shell> MYSQL_DEBUG=d:t:O,/tmp/client.trace
shell> export MYSQL_DEBUG

This causes clients to generate a trace file in `/tmp/client.trace'.

If you have problems with your own client code, you should attempt to connect to the server and run your query using a client that is known to work. Do this by running mysql in debugging mode (assuming you have compiled MySQL with debugging on):

shell> mysql --debug=d:t:O,/tmp/client.trace

This will provide useful information in case you mail a bug report. See section 2.3 How to report bugs or problems.

If your client crashes at some 'legal' looking code, you should check that your `mysql.h' include file matches your mysql library file. A very common mistake is to use an old `mysql.h' file from an old MySQL installation with new MySQL library.

G.3 Comments about RTS threads

I have tried to use the RTS thread packages with MySQL but stumbled on the following problems:

They use old version of a lot of POSIX calls and it is very tedious to make wrappers for all functions. I am inclined to think that it would be easier to change the thread libraries to the newest POSIX specification.

Some wrappers are already written. See `mysys/my_pthread.c' for more info.

At least the following should be changed:

pthread_get_specific should use one argument. sigwait should take two arguments. A lot of functions (at least pthread_cond_wait, pthread_cond_timedwait) should return the error code on error. Now they return -1 and set errno.

Another problem is that user-level threads use the ALRM signal and this aborts a lot of functions (read, write, open...). MySQL should do a retry on interrupt on all of these but it is not that easy to verify it.

The biggest unsolved problem is the following:

To get thread-level alarms I changed `mysys/thr_alarm.c' to wait between alarms with pthread_cond_timedwait(), but this aborts with error EINTR. I tried to debug the thread library as to why this happens, but couldn't find any easy solution.

If someone wants to try MySQL with RTS threads I suggest the following:

  • Change functions MySQL uses from the thread library to POSIX. This shouldn't take that long.
  • Compile all libraries with the -DHAVE_rts_threads.
  • Compile thr_alarm.
  • If there are some small differences in the implementation, they may be fixed by changing `my_pthread.h' and `my_pthread.c'.
  • Run thr_alarm. If it runs without any ``warning'', ``error'' or aborted messages, you are on the right track. Here follows a successful run on Solaris:
    Main thread: 1
Tread 0 (5) started
Thread: 5  Waiting
process_alarm
Tread 1 (6) started
Thread: 6  Waiting
process_alarm
process_alarm
thread_alarm
Thread: 6  Slept for 1 (1) sec
Thread: 6  Waiting
process_alarm
process_alarm
thread_alarm
Thread: 6  Slept for 2 (2) sec
Thread: 6  Simulation of no alarm needed
Thread: 6  Slept for 0 (3) sec
Thread: 6  Waiting
process_alarm
process_alarm
thread_alarm
Thread: 6  Slept for 4 (4) sec
Thread: 6  Waiting
process_alarm
thread_alarm
Thread: 5  Slept for 10 (10) sec
Thread: 5  Waiting
process_alarm
process_alarm
thread_alarm
Thread: 6  Slept for 5 (5) sec
Thread: 6  Waiting
process_alarm
process_alarm

...
thread_alarm
Thread: 5  Slept for 0 (1) sec
end

G.4 Differences between different thread packages

MySQL is very dependent on the thread package used. So when choosing a good platform for MySQL, the thread package is very important.

There are at least three types of thread packages:

  • User threads in a single process. Thread switching is managed with alarms and the threads library manages all non-thread-safe functions with locks. Read, write and select operations are usually managed with a thread-specific select that switches to another thread if the running threads have to wait for data. If the user thread packages are integrated in the standard libs (FreeBSD and BSDI threads) the thread package requires less overhead than thread packages that have to map all unsafe calls (MIT-pthreads, FSU Pthreads and RTS threads). In some environments (for example, SCO), all system calls are thread-safe so the mapping can be done very easily (FSU Pthreads on SCO). Downside: All mapped calls take a little time and it's quite tricky to be able to handle all situations. There are usually also some system calls that are not handled by the thread package (like MIT-pthreads and sockets). Thread scheduling isn't always optimal.
  • User threads in separate processes. Thread switching is done by the kernel and all data are shared between threads. The thread package manages the standard thread calls to allow sharing data between threads. LinuxThreads is using this method. Downside: Lots of processes. Thread creating is slow. If one thread dies the rest are usually left hanging and you must kill them all before restarting. Thread switching is somewhat expensive.
  • Kernel threads. Thread switching is handled by the thread library or the kernel and is very fast. Everything is done in one process, but on some systems, ps may show the different threads. If one thread aborts the whole process aborts. Most system calls are thread-safe and should require very little overhead. Solaris, HP-UX, AIX and OSF1 have kernel threads.

In some systems kernel threads are managed by integrating user level threads in the system libraries. In such cases, the thread switching can only be done by the thread library and the kernel isn't really ``thread aware''.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - J The MySQL server license for non Microsoft operating systems

Go to the first, previous, next, last section, table of contents.

J The MySQL server license for non Microsoft operating systems

MySQL FREE PUBLIC LICENSE (Version 4, March 5, 1995)

Copyright (C) 1995, 1996 TcX AB & Monty Program KB & Detron HB Stockholm SWEDEN, Helsingfors FINLAND and Uppsala SWEDEN All rights reserved.

NOTE: This license is not the same as any of the GNU Licenses published by the Free Software Foundation. Its terms are substantially different from those of the GNU Licenses. If you are familiar with the GNU Licenses, please read this license with extra care.

This License applies to the computer program known as "MySQL". The "Program", below, refers to such program, and a "work based on the Program" means either the Program or any derivative work of the Program, as defined in the United States Copyright Act of 1976, such as a translation or a modification. The Program is a copyrighted work whose copyright is held by TcX Datakonsult AB and Monty Program KB and Detron HB.

This License does not apply when running "MySQL" on any Microsoft operating system. Microsoft operating systems include all versions of Microsoft Windows NT and Microsoft Windows.

BY MODIFYING OR DISTRIBUTING THE PROGRAM (OR ANY WORK BASED ON THE PROGRAM), YOU INDICATE YOUR ACCEPTANCE OF THIS LICENSE TO DO SO, AND ALL ITS TERMS AND CONDITIONS FOR COPYING, DISTRIBUTING OR MODIFYING THE PROGRAM OR WORKS BASED ON IT. NOTHING OTHER THAN THIS LICENSE GRANTS YOU PERMISSION TO MODIFY OR DISTRIBUTE THE PROGRAM OR ITS DERIVATIVE WORKS. THESE ACTIONS ARE PROHIBITED BY LAW. IF YOU DO NOT ACCEPT THESE TERMS AND CONDITIONS, DO NOT MODIFY OR DISTRIBUTE THE PROGRAM.

  1. Licenses. Licensor hereby grants you the following rights, provided that you comply with all of the restrictions set forth in this License and provided, further, that you distribute an unmodified copy of this License with the Program:
    1. You may copy and distribute literal (i.e., verbatim) copies of the Program's source code as you receive it throughout the world, in any medium.
    2. You may modify the Program, create works based on the Program and distribute copies of such throughout the world, in any medium.
  2. Restrictions. This license is subject to the following restrictions:
    1. Distribution of the Program or any work based on the Program by a commercial organization to any third party is prohibited if any payment is made in connection with such distribution, whether directly (as in payment for a copy of the Program) or indirectly (as in payment for some service related to the Program, or payment for some product or service that includes a copy of the Program "without charge"; these are only examples, and not an exhaustive enumeration of prohibited activities). However, the following methods of distribution involving payment shall not in and of themselves be a violation of this restriction:
      1. Posting the Program on a public access information storage and retrieval service for which a fee is received for retrieving information (such as an on-line service), provided that the fee is not content-dependent (i.e., the fee would be the same for retrieving the same volume of information consisting of random data).
      2. Distributing the Program on a CD-ROM, provided that the files containing the Program are reproduced entirely and verbatim on such CD-ROM, and provided further that all information on such CD-ROM be redistributable for non-commercial purposes without charge.
    2. Activities other than copying, distribution and modification of the Program are not subject to this License and they are outside its scope. Functional use (running) of the Program is not restricted, and any output produced through the use of the Program is subject to this license only if its contents constitute a work based on the Program (independent of having been made by running the Program).
    3. You must meet all of the following conditions with respect to the distribution of any work based on the Program:
      1. If you have modified the Program, you must cause your work to carry prominent notices stating that you have modified the Program's files and the date of any change;
      2. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole and at no charge to all third parties under the terms of this License;
      3. If the modified program normally reads commands interactively when run, you must cause it, at each time the modified program commences operation, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty). Such notice must also state that users may redistribute the Program only under the conditions of this License and tell the user how to view the copy of this License included with the Program. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.);
      4. You must accompany any such work based on the Program with the complete corresponding machine-readable source code, delivered on a medium customarily used for software interchange. The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable code. However, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable code;
      5. If you distribute any written or printed material at all with the Program or any work based on the Program, such material must include either a written copy of this License, or a prominent written indication that the Program or the work based on the Program is covered by this License and written instructions for printing and/or displaying the copy of the License on the distribution medium;
      6. You may not impose any further restrictions on the recipient's exercise of the rights granted herein. If distribution of executable or object code is made by offering the equivalent ability to copy from a designated place, then offering equivalent ability to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source code along with the object code.
  3. Reservation of Rights. No rights are granted to the Program except as expressly set forth herein. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
  4. Other Restrictions. If the distribution and/or use of the Program is restricted in certain countries for any reason, Licensor may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
  5. Limitations. THE PROGRAM IS PROVIDED TO YOU "AS IS," WITHOUT WARRANTY. THERE IS NO WARRANTY FOR THE PROGRAM, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL LICENSOR, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - H Description of MySQL regular expression syntax

Go to the first, previous, next, last section, table of contents.

H Description of MySQL regular expression syntax

A regular expression (regex) is a powerful way of specifying a complex search.

MySQL uses regular Henry Spencer's inplementation of regular expressions. And that is aimed to conform to POSIX 1003.2. MySQL uses the extended version.

This is a simplistic reference that skips the details. To get more exact information, see Henry Spencer's regex(7) manual page that is included in the source distribution. See section C Contributors to MySQL.

A regular expression describes a set of strings. The simplest regexp is one that has no special characters in it. For example, the regexp hello matches hello and nothing else.

Nontrivial regular expressions use certain special constructs so that they can match more than one string. For example, the regexp hello|word matches either the string hello or the string word.

As a more complex example, the regexp B[an]*s matches any of the strings Bananas, Baaaaas, Bs and any other string starting with a B, ending with an s, and containing any number of a or n characters in between.

A regular expression may use any of the following special characters/constructs:

^
Match the beginning of a string.
mysql> select "fo\nfo" REGEXP "^fo$";           -> 0
mysql> select "fofo" REGEXP "^fo";              -> 1
$
Match the end of a string.
mysql> select "fo\no" REGEXP "^fo\no$";         -> 1
mysql> select "fo\no" REGEXP "^fo$";            -> 0
.
Match any character (including newline).
mysql> select "fofo" REGEXP "^f.*";             -> 1
mysql> select "fo\nfo" REGEXP "^f.*";           -> 1
a*
Match any sequence of zero or more a characters.
mysql> select "Ban" REGEXP "^Ba*n";             -> 1
mysql> select "Baaan" REGEXP "^Ba*n";           -> 1
mysql> select "Bn" REGEXP "^Ba*n";              -> 1
a+
Match any sequence of one or more a characters.
mysql> select "Ban" REGEXP "^Ba+n";             -> 1
mysql> select "Bn" REGEXP "^Ba+n";              -> 0
a?
Match either zero or one a character.
mysql> select "Bn" REGEXP "^Ba?n";              -> 1
mysql> select "Ban" REGEXP "^Ba?n";             -> 1
mysql> select "Baan" REGEXP "^Ba?n";            -> 0
de|abc
Match either of the sequences de or abc.
mysql> select "pi" REGEXP "pi|apa";             -> 1
mysql> select "axe" REGEXP "pi|apa";            -> 0
mysql> select "apa" REGEXP "pi|apa";            -> 1
mysql> select "apa" REGEXP "^(pi|apa)$";        -> 1
mysql> select "pi" REGEXP "^(pi|apa)$";         -> 1
mysql> select "pix" REGEXP "^(pi|apa)$";        -> 0
(abc)*
Match zero or more instances of the sequence abc.
mysql> select "pi" REGEXP "^(pi)*$";            -> 1
mysql> select "pip" REGEXP "^(pi)*$";           -> 0
mysql> select "pipi" REGEXP "^(pi)*$";          -> 1
{1}

{2,3}
The is a more general way of writing regexps that match many occurrences of the previous atom.
a*
Can be written as a{0,}.
a+
Can be written as a{1,}.
a?
Can be written as a{0,1}.

To be more precise, an atom followed by a bound containing one integer i and no comma matches a sequence of exactly i matches of the atom. An atom followed by a bound containing one integer i and a comma matches a sequence of i or more matches of the atom. An atom followed by a bound containing two integers i and j matches a sequence of i through j (inclusive) matches of the atom. Both arguments must 0 >= value <= RE_DUP_MAX (default 255). If there are two arguments, the second must be greater than or equal to the first.

[a-dX]

[^a-dX]
Matches any character which is (or is not, if ^ is used) either a, b, c, d or X. To include a literal ] character, it must immediately follow the opening bracket [. To include a literal - character, it must be written first or last. So [0-9] matches any decimal digit. Any character that does not have a defined meaning inside a [] pair has no special meaning and matches only itself.
mysql> select "aXbc" REGEXP "[a-dXYZ]";         -> 1
mysql> select "aXbc" REGEXP "^[a-dXYZ]$";       -> 0
mysql> select "aXbc" REGEXP "^[a-dXYZ]+$";      -> 1
mysql> select "aXbc" REGEXP "^[^a-dXYZ]+$";     -> 0
mysql> select "gheis" REGEXP "^[^a-dXYZ]+$";    -> 1
mysql> select "gheisa" REGEXP "^[^a-dXYZ]+$";   -> 0
[[.characters.]]
The sequence of characters of that collating element. The sequence is a single element of the bracket expression's list. A bracket expression containing a multi-character collating element can thus match more than one character, e.g., if the collating sequence includes a ch collating element, then the regular expression [[.ch.]]*c matches the first five characters of chchcc.
[=character_class=]
An equivalence class, standing for the sequences of characters of all collating elements equivalent to that one, including itself. For example, if o and (+) are the members of an equivalence class, then [[=o=]], [[=(+)=]], and [o(+)] are all synonymous. An equivalence class may not be an endpoint of a range.
[:character_class:]
Within a bracket expression, the name of a character class enclosed in [: and :] stands for the list of all characters belonging to that class. Standard character class names are:
alnum | digit | punct
alpha | graph | space
blank | lower | upper
cntrl | print | xdigit

These stand for the character classes defined in the ctype(3) manual page. A locale may provide others. A character class may not be used as an endpoint of a range.

mysql> select "justalnums" REGEXP "[[:alnum:]]+";       -> 1
mysql> select "!!" REGEXP "[[:alnum:]]+";               -> 0
[[:<:]]

[[:>:]]
These match the null string at the beginning and end of a word respectively. A word is defined as a sequence of word characters which is neither preceded nor followed by word characters. A word character is an alnum character (as defined by ctype(3)) or an underscore (_).
mysql> select "a word a" REGEXP "[[:<:]]word[[:>:]]";      -> 1
mysql> select "a xword a" REGEXP "[[:<:]]word[[:>:]]";     -> 0

mysql> select "weeknights" REGEXP "^(wee|week)(knights|nights)$"; -> 1

Go to the first, previous, next, last section, table of contents.


MySQL中文参考手册-目录

译者：晏子 (clyan@sohu.com） 主页：http://linuxdb.yeah.net

  • 0 译者序
  • 1 MySQL的一般的信息
    • 1.1 什么是MySQL？
    • 1.2 关于本手册
      • 1.2.1 本手册中使用的约定
    • 1.3 MySQL的历史
    • 1.4 MySQL的主要特征
    • 1.5 MySQL稳定性？
    • 1.6 顺应2000年
    • 1.7 SQL一般信息和教程
    • 1.8 有用的MySQL相关链接
  • 2 MySQL 邮件列表及如何提问或报告错误
    • 2.1 MySQL邮件列表
    • 2.2 提问或报告错误
    • 2.3 怎样报告错误或问题
    • 2.4 在邮件列表上回答问题的指南
  • 3 MySQL的许可证和技术支持
    • 3.1 MySQL的许可证政策
    • 3.2 MySQL 使用的版权
      • 3.2.1 可能的未来版权改变
    • 3.3 MySQL商业性分发
    • 3.4 许可证实例
      • 3.4.1 销售使用 MySQL的产品
      • 3.4.2 销售MySQL相关的服务
      • 3.4.3 ISP MySQL服务
      • 3.4.4 运营一个使用MySQL的Web服务器
    • 3.5 MySQL的许可证和技术支持费用
      • 3.5.1 付款信息
      • 3.5.2 联系信息
    • 3.6 商业性支持的类型
      • 3.6.1 基本的电子邮件支持
      • 3.6.2 扩展的电子邮件支持
      • 3.6.3 登录支持
      • 3.6.4 扩展的登录支持
  • 4 安装 MySQL
    • 4.1 怎样获得MySQL
    • 4.2 MySQL支持的操作系统
    • 4.3 使用MySQL哪个版本
    • 4.4 怎样和何时发布更新版本
    • 4.5 安装布局
    • 4.6 安装MySQL二进制代码分发
      • 4.6.1 Linux RPM注意事项
      • 4.6.2 构造客户程序
      • 4.6.3 系统特定的问题
        • 4.6.3.1 Linux 注意事项
        • 4.6.3.2 HP-UX 注意事项
    • 4.7 安装 MySQL源代码分发
      • 4.7.1 快速安装概述
      • 4.7.2 运用补丁
      • 4.7.3 典型的configure选项
    • 4.8 编译问题？
    • 4.9 MIT-pthreads 注意事项
    • 4.10 Perl 安装说明
      • 4.10.1 在Unix操作系统上安装 Perl
      • 4.10.2 在 Win32上安装 ActiveState Perl
      • 4.10.3 在 Win32 上安装 MySQL Perl 分发
      • 4.10.4 使用 Perl DBI/DBD接口遇到的问题
    • 4.11 系统特定的问题
      • 4.11.1 Solaris注意事项
      • 4.11.2 Solaris 2.7 注意事项
      • 4.11.3 Solaris x86 注意事项
      • 4.11.4 SunOS 4 注意事项
      • 4.11.5 Linux (所有的Linux版本)注意事项
        • 4.11.5.1 Linux-x86 注意事项
        • 4.11.5.2 RedHat 5.0 注意事项
        • 4.11.5.3 RedHat 5.1 注意事项
        • 4.11.5.4 Linux-SPARC 注意事项
        • 4.11.5.5 Linux-Alpha 注意事项
        • 4.11.5.6 MkLinux 注意事项
        • 4.11.5.7 Qube2 Linux 注意事项
      • 4.11.6 Alpha-DEC-Unix 注意事项
      • 4.11.7 Alpha-DEC-OSF1 注意事项
      • 4.11.8 SGI-Irix 注意事项
      • 4.11.9 FreeBSD 注意事项
      • 4.11.10 NetBSD 注意事项
      • 4.11.11 BSD/OS 注意事项
        • 4.11.11.1 BSD/OS 2.x 注意事项
        • 4.11.11.2 BSD/OS 3.x 注意事项
        • 4.11.11.3 BSD/OS 4.x 注意事项
      • 4.11.12 SCO 注意事项
      • 4.11.13 SCO Unixware 7.0 注意事项
      • 4.11.14 IBM-AIX 注意事项
      • 4.11.15 HP-UX 注意事项
    • 4.12 Win32 注意事项
      • 4.12.1 在 Win32 上安装 MySQL
      • 4.12.2 在 Win95 /Win98上启动 MySQL
      • 4.12.3 在 NT 上启动 MySQL
      • 4.12.4 在 Win32 上运行 MySQL
      • 4.12.5 用 SSH 从 Win32 连接一个远程MySQL
      • 4.12.6 MySQL-Win32与Unix MySQL 比较
    • 4.13 OS/2 注意事项
    • 4.14 TcX 二进制代码
    • 4.15 安装后期(post-installation)的设置与测试
      • 4.15.1 运行mysql_install_db 的问题
      • 4.15.2 启动 MySQL 服务器的问题
      • 4.15.3 自动启动和停止 MySQL
      • 4.15.4 选项文件
    • 4.16 升级和降级(downgrading)时有什么特别要做的事情吗？
      • 4.16.1 从一个 3.22 版本升级到 3.23
      • 4.16.2 从一个 3.21 版本升级到 3.22
      • 4.16.3 从一个 3.20 版本升级到 3.21
      • 4.16.4 升级到其他的体系结构
  • 5 MySQL 与标准的兼容性？
    • 5.1 MySQL对ANSI SQL92 的扩充
    • 5.2 以ANSI模式运行 MySQL
    • 5.3 MySQL相比ANSI SQL92的差别
    • 5.4 MySQL 缺乏的功能
      • 5.4.1 子选择(Sub-selects)
      • 5.4.2 SELECT INTO TABLE
      • 5.4.3 事务(Transactions)
      • 5.4.4 存储过程和触发器
      • 5.4.5 外键(Foreign Keys)
        • 5.4.5.1 不使用外键的理由
      • 5.4.6 视图(Views)
      • 5.4.7 '--'作为一个 注解的开始
    • 5.5 MySQL 遵循什么标准？
    • 5.6 怎样处理没有提交/回卷(COMMIT / ROLLBACK)
  • 6 MySQL 存取权限系统
    • 6.1 权限系统做什么
    • 6.2 MySQL用户名和口令
    • 6.3 与MySQL服务器连接
    • 6.4 使你的口令安全
    • 6.5 MySQL 提供的权限
    • 6.6 权限系统工作原理
    • 6.7 存取控制,阶段1:连接证实
    • 6.8 存取控制,阶段2:请求证实
    • 6.9 权限更改何时生效
    • 6.10 建立初始的 MySQL权限
    • 6.11 向MySQL增加新用户权限
    • 6.12 怎样设置口令
    • 6.13 存取拒绝(Access Denied)错误的原因
    • 6.14 怎样使MySQL安全以对抗解密高手(cracker)
  • 7 MySQL 语言参考
    • 7.1 文字:怎样写字符串和数字
      • 7.1.1 字符串
      • 7.1.2 数字
      • 7.1.3 十六进制值
      • 7.1.4 NULL值
      • 7.1.5 数据库，表，索引，列和别名的命名
        • 7.1.5.1 名字的大小写敏感性
    • 7.2 用户变量
    • 7.3 列类型
      • 7.3.1 列类型的存储要求
      • 7.3.5 数字类型
      • 7.3.6 日期和时间类型
        • 7.3.6.1 问题和日期类型
        • 7.3.6.2 DATETIME,DATE和TIMESTAMP类型
        • 7.3.6.3 TIME类型
        • 7.3.6.4 YEAR类型
      • 7.3.7 字符串类型
        • 7.3.7.1 CHAR和VARCHAR类型
        • 7.3.7.2 BLOB和TEXT类型
        • 7.3.7.3 ENUM类型
        • 7.3.7.4 SET类型
      • 7.3.8 为列选择正确的类型
      • 7.3.9 列索引
      • 7.3.10 多列索引
      • 7.3.11 使用来自其他数据库引擎的列类型
    • 7.4 用在SELECT和WHERE子句的函数
      • 7.4.1 分组函数
      • 7.4.2 常用的算术运算
      • 7.4.3 位函数
      • 7.4.4 逻辑运算
      • 7.4.5 比较运算符
      • 7.4.6 字符串比较函数
      • 7.4.7 类型转换运算符
      • 7.4.8 控制流函数
      • 7.4.9 数学函数
      • 7.4.10 字符串函数
      • 7.4.11 日期和时间函数
      • 7.4.12 其他函数
      • 7.4.13 与GROUP BY子句一起使用的函数
    • 7.5 CREATE DATABASE (创建数据库)句法
    • 7.6 DROP DATABASE (抛弃数据库)句法
    • 7.7 CREATE TABLE (创建表)句法
      • 7.7.1 隐含(silent)的列指定变化
    • 7.8 ALTER TABLE (改变表)句法
    • 7.9 OPTIMIZE TABLE (优化表) 句法
    • 7.10 DROP TABLE (抛弃表)句法
    • 7.11 DELETE (删除)句法
    • 7.12 SELECT (精选)句法
    • 7.13 JOIN (联接)句法
    • 7.14 INSERT (插入)句法
    • 7.15 REPLACE (替换)句法
    • 7.16 LOAD DATA INFILE (装载数据到文件)句法
    • 7.17 UPDATE (更新)句法
    • 7.18 USE (使用)句法
    • 7.19 FLUSH (清除缓存）句法
    • 7.20 KILL (杀灭)句法
    • 7.21 SHOW (显示)句法(得到关于表,列等的信息）
    • 7.22 EXPLAIN (解释)句法(得到关于SELECT的信息)
    • 7.23 DESCRIBE (描述)句法(得到列的信息）
    • 7.24 LOCK TABLES/UNLOCK TABLES (锁定表/解锁表)句法
    • 7.25 SET OPTION (设置选项)句法
    • 7.26 GRANT (授权)和REVOKE (撤回)句法
    • 7.27 CREATE INDEX (创建索引)句法
    • 7.28 DROP INDEX (抛弃索引)句法
    • 7.29 注释句法
    • 7.30 CREATE FUNCTION/DROP FUNCTION (创建函数/抛弃函数)句法
    • 7.31 MySQL对保留字很挑剔吗？
  • 8 MySQL 教程
    • 8.1 联接和断开服务器
    • 8.2 输入查询
    • 8.3 常用查询的例子
      • 8.3.1 列的最大值
      • 8.3.2 拥有某个列的最大值的行
      • 8.3.3 列的最大值:按组:只有值
      • 8.3.4 拥有某个字段的组间最大值的行
      • 8.3.5 使用外键
    • 8.4 创建并使用一个数据库
      • 8.4.1 创建并选用一个数据库
      • 8.4.2 创建一个数据库表
      • 8.4.3 将数据装入数据库表
      • 8.4.4 从一个数据库表检索信息
        • 8.4.4.1 选择所有数据
        • 8.4.4.2 选择特定行
        • 8.4.4.3 选择特定列
        • 8.4.4.4 排序行
        • 8.4.4.5 日期计算
        • 8.4.4.6 NULL值操作
        • 8.4.4.7 模式匹配
        • 8.4.4.8 行计数
      • 8.4.5 使用多个数据库表
    • 8.5 获得数据库和表的信息
    • 8.6 以批处理模式使用mysql
    • 8.7 从"双胞项目"中查询
      • 8.7.1 找出所有非独处的双胞胎
      • 8.7.2 显示关于双胞胎近况的表
  • 9 MySQL 服务器功能
    • 9.1 MySQL 支持哪些语言？
      • 9.1.1 用于数据和排序的字符集
      • 9.1.2 增加一个新的字符集
      • 9.1.3 多字节字符支持
    • 9.2 更新日志
    • 9.3 MySQL数据库表可以有多大？
    • 9.4 MySQL数据库表类型
  • 10 从 MySQL 得到最大的性能
    • 10.1 优化概述
    • 10.2 系统/编译时和启动参数的调节
      • 10.2.1 编译和链接如何影响 MySQL 的速度
      • 10.2.2 磁盘问题
        • 10.2.2.1 为数据库和表格使用符号链接
      • 10.2.3 调节服务器参数
      • 10.2.4 MySQL 怎样打开和关闭数据库表
      • 10.2.5 在同一个数据库中创建大量数据库表的缺点
      • 10.2.6 为什么有这么多打开的表？
      • 10.2.7 MySQL 怎样使用内存
      • 10.2.8 MySQL 怎样锁定数据库表
      • 10.2.9 数据库表级锁定的问题
    • 10.3 使你的数据尽可能小
    • 10.4 MySQL 索引的使用
    • 10.5 存取或更新数据的查询速度
      • 10.5.1 估计查询性能
      • 10.5.2 SELECT 查询的速度
      • 10.5.3 MySQL 怎样优化WHERE子句
      • 10.5.4 MySQL 怎样优化LEFT JOIN
      • 10.5.5 MySQL 怎样优化LIMIT
      • 10.5.6 INSERT查询的速度
      • 10.5.7 UPDATE查询的速度
      • 10.5.8 DELETE查询的速度
    • 10.6 选择一种表类型
      • 10.6.1 静态(定长)表的特点
      • 10.6.2 动态表的特点
      • 10.6.3 压缩表的特点
      • 10.6.4 内存(In-memory table)表的特点
    • 10.7 其他优化技巧
    • 10.8 使用你自己的基准测试
    • 10.9 设计选择
    • 10.10 MySQL 设计局限/折衷
    • 10.11 可移植性
    • 10.12 我们已将MySQL用在何处？
  • 11 MySQL 基准套件
  • 12 MySQL 实用程序
    • 12.1 各种 MySQL 程序概述
    • 12.2 管理一个 MySQL 服务器
    • 12.3 从 MySQL 数据库和表中倒出(dump)结构和数据
    • 12.4 从文本文件导入数据
    • 12.5 MySQL 压缩只读表生成器
  • 13 维护 MySQL 安装
    • 13.1 使用myisamchk进行表维护和崩溃恢复
      • 13.1.1 myisamchk的调用语法
      • 13.1.2 myisamchk的内存使用
    • 13.2 13.2 建立一个数据库表维护规范
    • 13.3 获得关于一个表的信息
    • 13.4 使用myisamchk进行崩溃恢复
      • 13.4.1 怎样检查表的出错
      • 13.4.2 怎样修复表
      • 13.4.3 表优化
    • 13.5 日志文件维护
  • 14 为MySQL增加新函数
    • 14.1 增加一个新的用户定义函数
      • 14.1.1 UDF调用顺序
      • 14.1.2 参数处理
      • 14.1.3 返回值和出错处理
      • 14.1.4 编译并安装用户定义函数
    • 14.2 增加一个新的原生(native)函数
  • 15 为MySQL增加新过程
    • 15.1 analyse过程
    • 15.2 编写一个过程
  • 16 MySQL对 ODBC 支持
    • 16.1 MyODBC 支持的操作系统
    • 16.2 怎样报告 MyODBC的问题
    • 16.3 已知可用 MyODBC一起工作的程序
    • 16.4 怎样填写 ODBC 管理程序的各种域
    • 16.5 怎样在ODBC中获得一个AUTO_INCREMENT列的值
    • 16.6 报告 MyODBC 的问题
  • 17 与一些常用程序一起使用MySQL
    • 17.1 与 Apache一起使用 MySQL
  • 18 问题和常见的错误
    • 18.1 如果 MySQL总是崩溃怎么办
    • 18.2 使用 MySQL 时一些常见错误
      • 18.2.1 MySQL server has gone away错误
      • 18.2.2 Can't connect to [local] MySQL server错误
      • 18.2.3 Host '...' is blocked错误
      • 18.2.4 Out of memory错误
      • 18.2.5 Packet too large错误
      • 18.2.6 The table is full错误
      • 18.2.7 Commands out of sync in client错误
      • 18.2.8 Ignoring user错误
      • 18.2.9 Table 'xxx' doesn't exist错误
    • 18.3 MySQL 怎样处理一个溢出的磁盘
    • 18.4 怎样从一个文本文件运行SQL命令
    • 18.5 MySQL 在哪儿存储临时文件
    • 18.6 怎样保护"/tmp/mysql.sock"不被删除
    • 18.7 Access denied 出错
    • 18.8 怎样作为一个一般用户运行 MySQL
    • 18.9 怎样重新设置一个忘记的口令
    • 18.10 文件许可权限问题
    • 18.11 文件没找到
    • 18.12 使用DATE列的问题
    • 18.13 时区问题
    • 18.14 在搜索中的大小写敏感性
    • 18.15 NULL值问题
    • 18.16 alias问题
    • 18.17 从相关的表中删除行
    • 18.18 解决没有匹配行的问题
    • 18.19 ALTER TABLE问题
    • 18.20 怎样改变一个表中列的次序
  • 19 解决MySQL 一些常见的问题
    • 19.1 数据库复制
    • 19.2 数据库备份
    • 19.3 在同一台机器上运行多个 MySQL 服务器
  • 20 MySQL 客户工具和 API
    • 20.1 MySQL C API
    • 20.2 C API数据类型
    • 20.3 C API函数概述
    • 20.4 C API函数描述
      • 20.4.1 mysql_affected_rows (）
      • 20.4.2 mysql_close (）
      • 20.4.3 mysql_connect (）
      • 20.4.4 mysql_change_user (）
      • 20.4.5 mysql_create_db (）
      • 20.4.6 mysql_data_seek (）
      • 20.4.7 mysql_debug (）
      • 20.4.8 mysql_drop_db (）
      • 20.4.9 mysql_dump_debug_info (）
      • 20.4.10 mysql_eof (）
      • 20.4.11 mysql_errno (）
      • 20.4.12 mysql_error (）
      • 20.4.13 mysql_escape_string (）
      • 20.4.14 mysql_fetch_field (）
      • 20.4.15 mysql_fetch_fields (）
      • 20.4.16 mysql_fetch_field_direct (）
      • 20.4.17 mysql_fetch_lengths (）
      • 20.4.18 mysql_fetch_row (）
      • 20.4.19 mysql_field_count (）
      • 20.4.20 mysql_field_seek (）
      • 20.4.21 mysql_field_tell (）
      • 20.4.22 mysql_free_result (）
      • 20.4.23 mysql_get_client_info (）
      • 20.4.24 mysql_get_host_info (）
      • 20.4.25 mysql_get_proto_info (）
      • 20.4.26 mysql_get_server_info (）
      • 20.4.27 mysql_info (）
      • 20.4.28 mysql_init (）
      • 20.4.29 mysql_insert_id (）
      • 20.4.30 mysql_kill (）
      • 20.4.31 mysql_list_dbs (）
      • 20.4.32 mysql_list_fields (）
      • 20.4.33 mysql_list_processes (）
      • 20.4.34 mysql_list_tables (）
      • 20.4.35 mysql_num_fields (）
      • 20.4.36 mysql_num_rows (）
      • 20.4.37 mysql_options (）
      • 20.4.38 mysql_ping (）
      • 20.4.39 mysql_query (）
      • 20.4.40 mysql_real_connect (）
      • 20.4.41 mysql_real_query (）
      • 20.4.42 mysql_reload (）
      • 20.4.43 mysql_row_seek (）
      • 20.4.44 mysql_row_tell (）
      • 20.4.45 mysql_select_db (）
      • 20.4.46 mysql_shutdown (）
      • 20.4.47 mysql_stat (）
      • 20.4.48 mysql_store_result (）
      • 20.4.49 mysql_thread_id (）
      • 20.4.50 mysql_use_result (）
      • 20.4.51 为什么在mysql_query()返回成功后mysql_store_result()有时返回NULL?
      • 20.4.52 我能从查询得到什么结果？
      • 20.4.53 我怎样才能获得最后插入的行的唯一ID？
      • 20.4.54 链接 C API的问题
      • 20.4.55 怎样制作一个线程安全(thread-safe)的客户
    • 20.5 MySQL Perl API
      • 20.5.1 DBI与DBD::mysql
      • 20.5.2 DBI接口
      • 20.5.3 更多的DBI/DBD信息
    • 20.6 MySQL Eiffel 包装
    • 20.7 MySQL Java 连接(JDBC)
    • 20.8 MySQL PHP API
    • 20.9 MySQL C++ API
    • 20.10 MySQL Python API
    • 20.11 MySQL TCL API
  • 21 怎样对比MySQL与其他数据库
    • 21.1 怎样对比MySQL和mSQL
      • 21.1.1 怎样将mSQL工具转换到MySQL
      • 21.1.2 mSQL和MySQL的 客户机/服务器通讯协议有何不同
      • 21.1.3 mSQL 2.0 SQL句法与MySQL有何不同
    • 21.2 怎样对比MySQL与PostgreSQL
  • A 一些 MySQL 用户
  • B 贡献的程序
  • C MySQL贡献者
  • D MySQL 变迁的历史记录
  • E MySQL中已知的错误和设计缺限
  • F 我们想要在未来加入到MySQL 的计划表( TODO ）
  • G 对移植到其他系统的说明
  • H MySQL 正则表达式句法的描述
  • I 什么是 Unireg？
  • J 针对非微软操作系统的 MySQL 服务器许可证
  • K 针对微软操作系统的 MySQL 许可证
  • SQL命令，类型和函数索引
  • 概念索引


MySQL Reference Manual for version 3.23.7-alpha. - F List of things we want to add to MySQL in the future (The TODO)

Go to the first, previous, next, last section, table of contents.

F List of things we want to add to MySQL in the future (The TODO)

Everything in this list is in the order it will be done. If you want to affect the priority order, please register a license or support us and tell us what you want to have done more quickly. See section 3 MySQL licensing and support.

F.1 Things that must done in the real near future

  • One way replication
  • Transactions
  • Subqueries. select id from t where grp in (select grp from g where u > 100)
  • Allow mysqld to support many character sets at the same time.
  • If you perform an ALTER TABLE on a table that is symlinked to another disk, create temporary tables on this disk.
  • RENAME table as table, table as table [,...]
  • FreeBSD and MIT-pthreads; Do sleeping threads take CPU?
  • Allow join on key parts (optimization issue).
  • Entry for DECRYPT().
  • Remember FOREIGN key definitions in the `.frm' file.
  • Server side cursors.
  • Allow users to change startup options.
  • Add --ansi option to MySQL (to change || -> CONCAT())
  • Don't add automatic DEFAULT values to columns. Give an error when using an INSERT that doesn't contain a column that doesn't have a DEFAULT.
  • Caching of queries and results. This should be done as a separated module that examines each query and if this is query is in the cache the cached result should be returned. When one updates a table one should remove as few queries as possible from the cache. This should give a big speed bost on machines with much RAM where queries are often repeated (like WWW applications). One idea would be to only cache queries of type: SELECT CACHED ....
  • Fix `libmysql.c' to allow two mysql_query() commands in a row without reading results or give a nice error message when one does this.
  • Optimize BIT type to take 1 bit (now BIT takes 1 char).
  • Check why MIT-pthreads ctime() doesn't work on some FreeBSD systems.
  • Check if locked threads take any CPU.
  • Add ORDER BY to update. This would be handy with functions like: generate_id(start,step).
  • Add an IMAGE option to LOAD DATA INFILE to not update TIMESTAMP and AUTO_INCREMENT fields.
  • Make LOAD DATA INFILE understand a syntax like:
    LOAD DATA INFILE 'file_name.txt' INTO TABLE tbl_name
TEXT_FIELDS (text_field1, text_field2, text_field3)
SET table_field1=concatenate(text_field1, text_field2), table_field3=23
IGNORE text_field3
  • Add true VARCHAR support (There is already support for this in MyISAM).
  • Automatic output from mysql to netscape.
  • LOCK DATABASES. (with various options)
  • NATURAL JOIN.
  • Change sort to allocate memory in ``hunks'' to get better memory utilization.
  • DECIMAL and NUMERIC types can't read exponential numbers; Field_decimal::store(const char *from,uint len) must be recoded to fix this.
  • Fix mysql.cc to do fewer malloc() calls when hashing field names.
  • Functions: ADD_TO_SET(value,set) and REMOVE_FROM_SET(value,set)
  • Add use of t1 JOIN t2 ON ... and t1 JOIN t2 USING ... Currently, you can only use this syntax with LEFT JOIN.
  • Add full support for unsigned long long type.
  • Function CASE.
  • Many more variables for show status. Counts for: INSERT/DELETE/UPDATE statements. Records reads and updated. Selects on 1 table and selects with joins. Mean number of tables in select. Key buffer read/write hits (logical and real). ORDER BY, GROUP BY, temporary tables created.
  • If you abort mysql in the middle of a query, you should open another connection and kill the old running query. Alternatively, an attempt should be made to detect this in the server.
  • Add a handler interface for table information so you can use it as a system table. This would be a bit slow if you requested information about all tables, but very flexible. SHOW INFO FROM tbl_name for basic table information should be implemented.
  • Add support for UNICODE.
  • NATURAL JOIN.
  • Oracle like CONNECT BY PRIOR ... to search hierarchy structures.
  • RENAME DATABASE
  • mysqladmin copy database new-database.
  • Processlist should show number of queries/thread.
  • IGNORE option to the UPDATE statement (this will delete all rows that gets a dupplicate key error while updating).
  • Change the format of DATETIME to store fractions of seconds.
  • Add all missing ANSI92 and ODBC 3.0 types.
  • Change table names from empty strings to NULL for calculated columns.

F.2 Things that have to be done sometime

  • Implement function: get_changed_tables(timeout,table1,table2,...)
  • Implement function: LAST_UPDATED(tbl_name)
  • Atomic updates; This includes a language that one can even use for a set of stored procedures.
  • update items,month set items.price=month.price where items.id=month.id;
  • Change reading through tables to use memmap when possible. Now only compressed tables use memmap.
  • Add a new privilege 'Show_priv' for SHOW commands.
  • Make the automatic timestamp code nicer. Add timestamps to the update log with SET TIMESTAMP=#;
  • Use read/write mutex in some places to get more speed.
  • Full foreign key support. One probably wants to implement a procedural language first.
  • Simple views (first on one table, later on any expression).
  • Automatically close some tables if a table, temporary table or temporary files gets error 23 (not enough open files).
  • When one finds a field=#, change all occurrences of field to #. Now this is only done for some simple cases.
  • Change all const expressions with calculated expressions if possible.
  • Optimize key = expression. At the moment only key = field or key = constant are optimized.
  • Join some of the copy functions for nicer code.
  • Change `sql_yacc.yy' to an inline parser to reduce its size and get better error messages (5 days).
  • Change the parser to use only one rule per different number of arguments in function.
  • Use of full calculation names in the order part. (For ACCESS97)
  • UNION, MINUS, INTERSECT and FULL OUTER JOIN. (Currently only LEFT OUTER JOIN is supported)
  • Allow UNIQUE on fields that can be NULL.
  • SQL_OPTION MAX_SELECT_TIME=# to put a time limit on a query.
  • Make the update log to a database.
  • Negative LIMIT to retrieve data from the end.
  • Alarm around client connect/read/write functions.
  • Make a mysqld version which isn't multithreaded (3-5 days).
  • Please note the changes to safe_mysqld: according to FSSTND (which Debian tries to follow) PID files should go into `/var/run/<progname>.pid' and log files into `/var/log'. It would be nice if you could put the "DATADIR" in the first declaration of "pidfile" and "log", so the placement of these files can be changed with a single statement.
  • Better dynamic record layout to avoid fragmentation.
  • UPDATE SET blob=read_blob_from_file('my_gif') where id=1;
  • Allow a client to request logging.
  • Add use of zlib() for gzip-ed files to LOAD DATA INFILE.
  • Fix sorting and grouping of BLOB columns (partly solved now).
  • Stored procedures. This is currently not regarded to be very important as stored procedures are not very standardized yet. Another problem is that true stored procedures make it much harder for the optimizer and in many cases the result is slower than before We will, on the other hand, add a simple (atomic) update language that can be used to write loops and such in the MySQL server.
  • Change to use semaphores when counting threads. One should first implement a semaphore library to MIT-pthreads.
  • Don't assign a new AUTO_INCREMENT value when one sets a column to 0. Use NULL instead.
  • Add full support for JOIN with parentheses.
  • Reuse threads for system with a lot of connections.

Time is given according to amount of work, not real time. TcX's main business is the use of MySQL not the development of it. But since TcX is a very flexible company, we have put a lot of resources into the development of MySQL.

F.3 Some things we don't have any plans to do

  • Transactions with rollback (we mainly do SELECTs, and because we don't do transactions, we can be much quicker on everything else). We will support some kind of atomic operations on multiple tables, though. Currently atomic operations can be done with LOCK TABLES/UNLOCK TABLES but we will make this more automatic in the future.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - I What is Unireg?

Go to the first, previous, next, last section, table of contents.

I What is Unireg?

Unireg is our tty interface builder, but it uses a low level connection to our ISAM (which is used by MySQL) and because of this it is very quick. It has existed since 1979 (on Unix in C since ~1986).

Unireg has the following components:

  • One table viewer with updates/browsing.
  • Multi table viewer (with one scrolling region).
  • Table creator. (With lots of column tags you can't create with MySQL) This is WYSIWYG (for a tty). You design a screen and Unireg prompts for the column specification.
  • Report generator.
  • A lot of utilities (quick export/import of tables to/from text files, analysis of table contents...).
  • Powerful multi-table updates (which we use a lot) with a BASIC-like language with LOTS of functions.
  • Dynamic languages (at present in Swedish and Finnish). If somebody wants an English version there are a few files that would have to be translated.
  • The ability to run updates interactively or in a batch.
  • Emacs-like key definitions with keyboard macros.
  • All this in a binary of 800K.
  • The convform utility. Converts `.frm' and text files between different character sets.
  • The myisampack utility. Packs a ISAM table (makes it 50-80% smaller). The table can be read by MySQL like an ordinary table. Only one record has to be decompressed per access. Cannot handle BLOB or TEXT columns or updates (yet).

We update most of our production databases with the Unireg interface and serve web pages through MySQL (and in some extreme cases the Unireg report generator).

Unireg takes about 3M of disk space and works on at least the following platforms: SunOS 4.x, Solaris, Linux, HP-UX, ICL Unix, DNIX, SCO and MS-DOS.

Unireg is currently only available in Swedish and Finnish.

The price tag for Unireg is 10,000 Swedish kr (about $1500 US), but this includes support. Unireg is distributed as a binary. (But all the ISAM sources can be found in MySQL). Usually we compile the binary for the customer at their site.

All new development is concentrated to MySQL.

Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - A Some MySQL users

Go to the first, previous, next, last section, table of contents.

A Some MySQL users

A.1 General news sites

  • A pro-Linux/tech news and comment/discussion site
  • All about Linux
  • 32Bits Online: because there's more than one way to compute
  • New about new versions of computer related stuff
  • @end itemize

    A.2 Some Web search engines

    • AAA Matilda Web Search
    • What's New
    • Aladin
    • Columbus Finder
    • Spider
    • Blitzsuche
    • Indoseek Indonesia
    • Yaboo - Yet Another BOOkmarker
    • Yahoosuck
    • OzSearch Internet Guide
    • Splat! Search

    A.3 Some Information search engines concentrated on some area

    • Jobvertise: Post and search for jobs
    • The Music Database
    • Fotball (Soccer) search page
    • TAKEDOWN - wrestling
    • The International Lyrics Network
    • Musicians looking for other musicians (Free Service)
    • AddALL books searching and price comparison
    • Harvard's Gray Herbarium Index of Plant Names
    • The Game Development Search Engine
    • My-Recipe.com; Cookbook at i-run.com
    • The Innkeeper Vacation Guides
    • The Mac Game Database uses PHP and MySQL
    • Research Publications at Monash University in Australia
    • Occupational Health & Safety website databse (a project for the ECC)
    • Bioinformatics databases at the Montreal Children's Hospital using MySQL

    A.4 Web sites the use MySQL as a backed

    • Qt Widget and Object Repository
    • Brazilian samba site (in Portuguese)
    • Polish General Social Survey
    • Expo2000 World-wide distribution of tickets for this event is implemented using MySQL and tcl/tk. More than 5000 travel-agencies all over the world have access to it.
    • FreeVote.com is a free voting service with millions of users.
    • Forza Motorsport

    A.5 Some Domain/Internet/Web and related services

    • Registry of Web providers that support MySQL
    • Dynamic DNS Services
    • Dynamic domain name service
    • Open DNS Project; free dynamic DNS service
    • Free 3rd level domains
    • Online Database
    • BigBiz Internet Services
    • The Virt Gazette
    • Global InfoNet Inc
    • WebHosters - A Guide to WWW Providers
    • Internet information server
    • A technology news site
    • WorldNet Communications - An Internet Services Provider
    • Netizen: Australian-based web consultancy
    • Search site for training courses in the UK
    • Gannon Chat (GPL). Written in Perl and Javascript
    • A general links directory
    • A web-based bookmark management service
    • Walnut Creek CDROM
    • WWWThreads; Interactive discussion Forums
    • In Italian; Storage data from meteo station
    • Online "Person To Person" Auction
    • Tips on web development
    • Mailfriends.com is a FREE service for everybody who wants to find friends over the internet.
    • Web Page Telnet BBS List
    • UniNova Digital Postcards
    • DSL providers search with reviews Made with MySQL and Modperl, all pages are generated dynamically out of the MySQL database

    A.6 Web sites that use PHP and MySQL

    • Jgaa's Internet - Official Support Site
    • Ionline - online publication: MySQL, PHP, Java, Web programming, DB development
    • BaBoo(Browse and bookmark). Free web-based bookmark manager and Calendar
    • Course Schedule System at Pensacola Junior College
    • Florida Community College at Jacksonville
    • 32bit.com; An extensive shareware / freeware archive
    • Jokes 2000
    • Burken.NU Burken is a webhotel that provides scripts, among other things, for remote users, like counters, guestbooks etc.
    • tips.pair.com Contains tips on html, javascript, 2d/3d graphics and PHP3/MySQL. All pages are generated from a database.

    A.7 Some MySQL consultants

    • Ayni AG
    • Online Database
    • DataGuard (Uses MySQL and PHP)
    • WWITS (Uses MySQL and PHP)
    • WCN - The World Community Network
    • Chip Castle Dot Com Inc
    • Cybersource Pty. Ltd
    • Spring infotainment gmbh & co. kg
    • Develops websites using MySQL

    A.8 Programming

    • The Perl CPAN Testers results page

    A.9 Uncategorized pages

    • AZC.COM's Feature Showcase
    • Course Search
    • Northerbys Online Auctions
    • Amsterdam Airport Schiphol
    • CD database
    • Used Audio Gear Database
    • Musical note-sheets
    • Bagism - A John Lennon fan page
    • US Folk art broker
    • Mail reading on the web
    • Free home pages on www.somecoolname.mypage.org
    • Der Server f@"ur Schulen im Web (In German)
    • Auldhaefen Online Services
    • CaryNET Information Center
    • Dataden Computer Systems
    • Andr'emuseet (In Swedish)
    • HOMESITE Internet Marketing
    • Jade-V Network Services
    • Weather World 2010 Technical Credits
    • About The Gimp plugin registry
    • Java tool Archiver technical detail (Slightly optimistic about MySQL ANSI-92 compliance)
    • Games Domain Cheats Database
    • The "Powered By" Page (Kcilink)
    • Netcasting
    • NBL (Australian National Basketball League) tipping
    • CGI shop
    • Whirlycott: Website Design
    • Museum Tusculanum Press
    • Centro Siciliano di Documentazione
    • Quake statistics database
    • Astroforum: Astrologie and related things (in German)
    • OpenDebate - Interactive Polls & Open Discussion
    • Online chemical dissertation server
    • FreSch! The Free Scholarship Search Service
    • Stockholm Pinball Locator
    • HEK A construction company
    • Elsevier Bussines Information
    • Medical Links (Using Coldfusion and MySQL)
    • Search for jobs & people at JobLink-USA
    • Daily news about Linux in German language
    • Competition Formation Skydiving
    • E-commerce and internal accounting
    • Denmark's leading business daily newspaper B@o{rsen}
    • The Internet NES Database
    • Travel agency in Prague in 3 languages
    • Linkstation
    • Searchable online database at Peoplestaff
    • A searchable database system for horse classified ads
    • The Poot site
    • "Playin' in the LAN"; a network monitoring suite
    • U.S. Army Publishing Agency
    • Realestate handling in Yugoslavia
    • PIMS; a Patient Information Management System
    • Pilkington Software Inc
    • Betazine - The Ultimate Online Beta Tester's Magazine
    • A Vietnam Veteran's Memorial (The Wall) database.
    • Gamer's Union specializes inauctions of used & out of print gaming material
    • A daily bulletin at Monterey High school
    • Computer Currents Magazine
    • Community-owned site serving Lake Washington's Eastside residents and businesses
    • French bowling site.

    Send any additions to this list to webmaster@mysql.com.

    Go to the first, previous, next, last section, table of contents.


MySQL Reference Manual for version 3.23.7-alpha. - K The MySQL license for Microsoft operating systems

Go to the first, previous, next, last section, table of contents.

K The MySQL license for Microsoft operating systems

MySQL shareware license for Microsoft operating systems (Version 1, September 4, 1998)

Copyright (C) 1998 TcX AB & Monty Program KB & Detron HB Stockholm SWEDEN, Helsingfors FINLAND and Uppsala SWEDEN All rights reserved.

This License applies to the computer program known as "MySQL".

This License applies when running MySQL on any Microsoft operating system. Microsoft operating systems include all versions of Microsoft Windows NT and Microsoft Windows.

YOU SHOULD CAREFULLY READ THE FOLLOWING TERMS AND CONDITIONS BEFORE USING, COPYING OR DISTRIBUTING MySQL. BY USING, COPYING AND DISTRIBUTING MySQL, YOU INDICATE YOUR ACCEPTANCE OF THIS LICENSE TO DO SO, AND ALL ITS TERMS AND CONDITIONS FOR USING, COPYING AND DISTRIBUTING MySQL OR WORKS BASED ON IT. NOTHING OTHER THAN THIS LICENSE GRANTS YOU PERMISSION TO USE, COPY OR DISTRIBUTE MySQL OR ITS DERIVATIVE WORKS. THESE ACTIONS ARE PROHIBITED BY LAW. IF YOU DO NOT ACCEPT THESE TERMS AND CONDITIONS, DO NOT USE, COPY OR DISTRIBUTE MySQL.

  1. Evaluation and License Registration. This is an evaluation version of MySQL for Win32. Subject to the terms below, you are hereby licensed to use MySQL for evaluation purposes without charge for a period of 30 days. If you use MySQL after the 30 day evaluation period the registration and purchase of a MySQL license is required. The price for a MySQL license is currently 200 US dollars and email support starts from 200 US dollars/year. Quantity discounts are available. If you pay by credit card, the currency is EURO (The European Unions common currency) so the prices will differ slightly. The easiest way to register or find options about how to pay for MySQL is to use the license form at TcX's secure server at https://www.mysql.com/license.htmy. This can be used also when paying with credit card over the Internet. Other applicable methods for paying are SWIFT payments, cheques and credit cards. Payment should be made to:
    Postgirot Bank AB
105 06 STOCKHOLM, SWEDEN

TCX DataKonsult AB
BOX 6434
11382 STOCKHOLM, SWEDEN

SWIFT address: PGSI SESS
Account number: 96 77 06 - 3

    Specify: license and/or support and your name and email address. In Europe and Japan, EuroGiro (that should be cheaper) can be used to the same account. If you want to pay by cheque make it payable to "Monty Program KB" and mail it to the address below.

    TCX DataKonsult AB
BOX 6434
11382 STOCKHOLM, SWEDEN

    For more information about commercial licensing, please contact:

    David Axmark
Kungsgatan 65 B
753 21 UPPSALA
SWEDEN
Voice Phone +46-18-10 22 80     GMT 9-21. Swedish and English spoken
Fax +46-8-729 69 05             Email *much* preferred.
E-Mail: mysql-licensing@mysql.com

    For more about the license prices and commercial support, like email support, please refer to the MySQL manual. See section 3.5 MySQL licensing and support costs. See section 3.6 Types of commercial support. The use of MySQL or any work based on MySQL after the 30-day evaluation period is in violation of international copyright laws.

  2. Registered version of MySQL. After you have purchased a MySQL license we will send you a receipt by paper mail. You are allowed to use MySQL or any work based on MySQL after the 30-days evaluation period. The use of MySQL is, however, restricted to one physical computer, but there are no restrictions on concurrent uses of MySQL or the number of MySQL servers run on the computer. We will also email you an address and password for a password-protected WWW page that always has the newest MySQL-Win32 version. Our current policy is that a user with the MySQL license can get free upgrades. The best way to ensure that you get the best possible support is to purchase commercial support!
  3. Registration for use in education and university or government-sponsored research. You may obtain a MySQL license for the use in education and university or government-sponsored research for free. In that case, send a detailed application for licensing MySQL for such use to the email address The following information is required in the application:
    • The name of the school or institute.
    • A short description of the school or institute and of the type of education, resarch or other functions it provides.
    • A detailed report of the use of MySQL in the institution.

    In this case you will be provided with a license that entitles you to use MySQL in a specified manner.

  4. Distribution. Provided that you verify that you are distributing an evaluation or educational/research version of MySQL you are hereby licensed to make as many literal (i.e., verbatim) copies of the evaluation version of MySQL and documentation as you wish.
  5. Restrictions. The client code of MySQL is in the Public Domain or under the GPL (for example the code for readline) license. You are not allowed to modify, recompile, translate or create derivative works based upon any part of the server code of MySQL.
  6. Reservation of Rights. No rights are granted to MySQL except as expressly set forth herein. You may not copy or distribute MySQL except as expressly provided under this License. Any attempt otherwise to copy or distribute MySQL is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
  7. Other Restrictions. If the distribution and/or use of MySQL is restricted in certain countries for any reason, the Licensor may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
  8. Limitations. MySQL IS PROVIDED TO YOU "AS IS," WITHOUT WARRANTY. THERE IS NO WARRANTY FOR MySQL, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF MySQL IS WITH YOU. SHOULD MySQL PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL THE LICENSOR, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE MySQL AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE MySQL (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF MySQL TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Go to the first, previous, next, last section, table of contents.