1、MySQL中文参考手册6(MySQL与标准的兼容性) 对ANSI SQL92扩充 http:/ 邮件群发 MySQL中文参考手册6(MySQL与标准的兼容性)转载 译者:晏子返回转发q译者:晏子 ()主页:http:/5 MySQL与标准的兼容性?5.1 MySQL对ANSI SQL92 扩充MySQL包含了一些可能在其他SQL数据库找不到的扩充。要注意如果你使用他们,你的代码将不与其他SQL服务器兼容。在一些情况下,你可以编写包括MySQL扩展的代码,但是仍然是可移植的,通过使用/*! . */形式的注释。在这种情况下, MySQL将 进行词法分析并且执行在注释内的代码,好像它是任何其它My
2、SQL语句,但是其他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_INCREME
3、NT、BINARY、UNSIGNED和ZEROFILL。 缺省地,所有的字符串比较是忽略大小写的,由当前的字符集决定了(缺省为ISO-8859-1Latin1)排序 顺序。如果你不喜欢这样,你应该用BINARY属性或使用BINARY 强制符声明列,它导致根据MySQL服务器主机的ASCII顺序进行排序。 MySQL将每个数据库映射一个MySQL数据目录下面的目 录,将数据库表映射到数据库目录下的数据库文件名。 这有2个含意: 在区分大小写文件名的操作系统(象大多数 Unix 系统一样)上的MySQL中数据库名字和表名是区分大小写的。如果你有困难记得表名,接受一个一致的约定,例如总是用小写名字创
4、建数据库和表。 数据库、表、索引、列或别名可以以数字开始(但是不能仅由数字组成)。你可以使用标准的系统命令备份、重命名、移动、删除和拷贝表。例如,重命名一个表,重命名 “.MYD”、“.MYI”和“.frm”文件为相应的表 在SQL语句中,你可以用db_name.tbl_name语法访问不同数据库中的表。一些SQL服务器提供同样的功能但是称它 们为这User space(用 户空间)。MySQL 不支持类似在create table ralph.my_table.IN my_tablespace中的表空间。 LIKE在数字列上被允许。 在一SELECT语句里面使用INTO OUTFILE和ST
5、RAIGHT_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
6、.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、。见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
8、 SQL句法和 ODBC句法。 MySQL理解|和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(),
9、或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,
10、 MySQL的下列行为改变。 |是字符串并置而不是OR 。可在一个函数名字之间与 “(”有任何数量的空格。 这 也使所有的功能名字成为保留词。 “将是一个标识符引号字符(象MySQL 引号字符一 样)而不是一个字符串引号字符。 REAL将是FLOAT一个同义词,不是 DOUBLE一个同义词。 5.3 MySQL相比ANSI SQL92 的差别我们尝试使得MySQL 遵照ANSI SQL 标准和ODBC SQL标准,但是在一些情况下, MySQL做一些不同的事情: -只是一个注释,如果后面跟一个白空字符。见5.4.7 -#作为一个注释的开始。 对 于VARCHAR 列,当 值被存储时,拖后的空格
11、被删除。见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中下列语句还不能工作: SELEC
12、T * 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对于更复 杂的子
13、 查询,通常你可以创建临时的表保存子查询。然而在一些情况下,这种选择将行不通。最经常遇到的情形是 DELETE语 句, 对于它标准SQL 不支持联结(join)(除了在子选择)。对于这种情况,有2个可用选择,直到子选择被MySQL支持。 第一个选择是使用一种过程化的程序语言(例如Perl或PHP)来提交一个SELECT 查询获得要被删除记录主键,并然后使用这些值构造DELETE语句(DELETE FROM . WHERE . IN (key1, key2, .)。 第二个选择是使用交互式SQL自动构造一套DELETE语句,使用MySQL扩展CONCAT()(代替标准| 操作符)。例如: SEL
14、ECT CONCAT(#DELETE FROM tab1 WHERE pkid = #, tab1.pkid, #;#)FROM tab1, tab2WHERE tab1.col1 = tab2.col2;你可以把这个查询放在一个脚本文件并且从它重定向输入到mysql 命令行解释器,将其输出作为管道返回给解释器的第2个实例: prompt mysql -skip-column-names mydb replace “ -“ “ #“ mysql database replace “ -“ “ #“ - text-file-with-funny-comments.sql用这个命令改回他们: sh
15、ell replace “ #“ “ -“ - text-file-with-funny-comments.sql5.5 MySQL 遵循什么标 准?Entry level SQL92。ODBC level 0-2。 5.6 怎样处理没有COMMIT/ROLLBACKMySQL不支持COMMIT-ROLLBACK 。问题是有效地处理COMMIT-ROLLBACK将需要完全不同于 MySQL今天使用的表布局。MySQL也将需要额外的线程在表上做自动清除工作,而且磁盘用量将更高。这将使MySQL比现今慢上大约2-4倍。MySQL比几乎所有其他SQL数据库都快(一般至少快2-3倍)。原因之一就是缺少
16、 COMMIT-ROLLBACK。 目前,我 们是更多地实现 SQL服务器语言(象存储过程),有了它,你将确实很少需要COMMIT-ROLLBACK,这也将得到更好的性能。 通常需要事务的循环可以借助LOCK TABLES进行编码,并且当你能即时地更新记录时,你不需要光 标(cursor)。 我们 在 TODO上有事务和光标,然而并非相当 优先。如果我们实现这些,将作为CREATE TABLE的选项,那意味着COMMIT-ROLLBACK将仅工作在那些表上,以便速度损失仅仅强加在那些表上。 我们在TcX有一个更大的需求,一个比100%通用数据库的真正快速的数据库。无论何时我们发现一个方法来实现
17、这些特征而没有任何速度损失,我们将可能做它。暂时,有许多更重要的事情要做。检查TODO,看我们此时如何将事情优先排列。(有的较高级别支持的客户可以改变它,因此事情是可以重新优先化的。)当前的问题实际上是ROLLBACK,没有ROLLBACK ,你能用LOCK TABLES 做任何COMMIT动作。为了支持 ROLLBACK,MySQL将必 须被改变以存储所有的旧记录,如果发出ROLLBACK,它 们被更新的并且将任何东 西恢复到起点。对于简单的情形,这不是 难做的 (当前isamlog可以用于此目的),但是为ALTER/DROP/CREATE TABLE实现ROLLBACK将是更困难的。 避免
18、使用ROLLBACK ,你可以使用下列策略: 使用LOCK TABLES .锁住所有你想要存取的数据库表。 测试条件。 如果一切无误,更新。 使用UNLOCK TABLES释放你的锁。 这通常比使用可能带ROLLBACK的交易是一个更快的方法,尽管不总是这样。这个解决方案不能处理的唯一状况是当某人在更新当中杀死线程时。在这种情况下,所有的锁将被释放,但是一些更改不能被执行。 你也可使函数以单个操作更新记录。你能通 过使用下列技术得到一个很有效率的应用程序: 相对他们的当前的值修改字段 仅仅更新那些实际上更改的字段 例如,当我们正在更新一些客户信息时,我们仅仅更新那些改变了的客户数据并只测试没有
19、任何数据的改变 ,或数据取决于改 变的数据,与原来的行相比变化了。对于改变 了的数据的测试用WHERE子句在UPDATE语句中完成。如果记录没被更新,我们给客户一条消息: “你改变了的一些数据已被其他用户改变了”,然后我们在一个窗口中显示新行对照旧行,因此用户能决定他该使用哪个版本的客户记录。 这给了我们类似于“ 列锁定” 的东西,但是 实际上甚至更好,因为我们仅仅更新某些列,使用相对于他们的当前值的值。这意味着典型的 UPDATE语句看上去象这些一样东西: UPDATE tablename SET pay_back=pay_back+#relative change#;UPDATE cust
20、omerSETcustomer_date=#current_date#,address=#new address#,phone=#new phone#,money_he_owes_us=money_he_owes_us+#new_money#WHEREcustomer_id=id AND address=#old address# AND phone=#old phone#;正如你能看到的,这是很有效的并且就算其他客户已经改变了pay_back 或money_he_owes_us列的也能工作。 在许多情况下,为管理一些表格的唯一标识符目的,用户已经想要ROLLBACK 或LOCK TABLES
21、。这可用一个 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;# 责任编辑:eight(2001-06-07 00:45)