第13章:SQL語句語法

目錄

13.1. 數據定義語句
13.1.1. ALTER DATABASE語法
13.1.2. ALTER TABLE語法
13.1.3. CREATE DATABASE語法
13.1.4. CREATE INDEX語法
13.1.5. CREATE TABLE語法
13.1.6. DROP DATABASE語法
13.1.7. DROP INDEX語法
13.1.8. DROP TABLE語法
13.1.9. RENAME TABLE語法
13.2. 數據操作語句
13.2.1. DELETE語法
13.2.2. DO語法
13.2.3. HANDLER語法
13.2.4. INSERT語法
13.2.5. LOAD DATA INFILE語法
13.2.6. REPLACE語法
13.2.7. SELECT語法
13.2.8. Subquery語法
13.2.9. TRUNCATE語法
13.2.10. UPDATE語法
13.3. MySQL實用工具語句
13.3.1. DESCRIBE語法(獲取有關列的信息)
13.3.2. USE語法
13.4. MySQL事務處理和鎖定語句
13.4.1. START TRANSACTION, COMMIT和ROLLBACK語法
13.4.2. 不能回滾的語句
13.4.3. 會造成隱式提交的語句
13.4.4. SAVEPOINT和ROLLBACK TO SAVEPOINT語法
13.4.5. LOCK TABLES和UNLOCK TABLES語法
13.4.6. SET TRANSACTION語法
13.4.7. XA事務
13.5. 數據庫管理語句
13.5.1. 賬戶管理語句
13.5.2. 表維護語句
13.5.3. SET語法
13.5.4. SHOW語法
13.5.5. 其它管理語句
13.6. 復制語句
13.6.1. 用于控制主服務器的SQL語句
13.6.2. 用于控制從服務器的SQL語句
13.7. 用于預處理語句的SQL語法
本章介紹了SQL語句的語法。

13.1. 數據定義語句

13.1.1.?ALTER DATABASE語法

ALTER {DATABASE | SCHEMA} [db_name]
    alter_specification [, alter_specification] ...

alter_specification:
    [DEFAULT] CHARACTER SET charset_name
  | [DEFAULT] COLLATE collation_name

ALTER DATABASE用于更改數據庫的全局特性。這些特性儲存在數據庫目錄中的db.opt文件中。要使用ALTER DATABASE,您需要獲得數據庫ALTER權限。

CHARACTER SET子句用于更改默認的數據庫字符集。COLLATE子句用于更改默認的數據庫整序。在第10章字符集支持中對字符集和整序名稱進行了討論。

數據庫名稱可以忽略,此時,語句對應于默認數據庫。也可以使用ALTER SCHEMA

13.1.2.?ALTER TABLE語法

ALTER [IGNORE] TABLE tbl_name
    alter_specification [, alter_specification] ...

alter_specification:
    ADD [COLUMN] column_definition [FIRST | AFTER col_name ]
  | ADD [COLUMN] (column_definition,...)
  | ADD INDEX [index_name] [index_type] (index_col_name,...)
  | ADD [CONSTRAINT [symbol]]
        PRIMARY KEY [index_type] (index_col_name,...)
  | ADD [CONSTRAINT [symbol]]
        UNIQUE [index_name] [index_type] (index_col_name,...)
  | ADD [FULLTEXT|SPATIAL] [index_name] (index_col_name,...)
  | ADD [CONSTRAINT [symbol]]
        FOREIGN KEY [index_name] (index_col_name,...)
        [reference_definition]
  | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
  | CHANGE [COLUMN] old_col_name column_definition
        [FIRST|AFTER col_name]
  | MODIFY [COLUMN] column_definition [FIRST | AFTER col_name]
  | DROP [COLUMN] col_name
  | DROP PRIMARY KEY
  | DROP INDEX index_name
  | DROP FOREIGN KEY fk_symbol
  | DISABLE KEYS
  | ENABLE KEYS
  | RENAME [TO] new_tbl_name
  | ORDER BY col_name
  | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
  | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
  | DISCARD TABLESPACE
  | IMPORT TABLESPACE
  | table_options
  | partition_options
  | ADD PARTITION partition_definition
  | DROP PARTITION partition_names
  | COALESCE PARTITION number
  | REORGANIZE PARTITION partition_names INTO (partition_definitions)
  | ANALYZE PARTITION partition_names
  | CHECK PARTITION partition_names
  | OPTIMIZE PARTITION partition_names
  | REBUILD PARTITION partition_names
  | REPAIR PARTITION partition_names

ALTER TABLE用于更改原有表的結構。例如,您可以增加或刪減列,創建或取消索引,更改原有列的類型,或重新命名列或表。您還可以更改表的評注和表的類型。

允許進行的變更中,許多子句的語法與CREATE TABLE中的子句的語法相近。其中包括table_options修改,選項有ENGINE, AUTO_INCREMENTAVG_ROW_LENGTH等。請見13.1.5節,“CREATE TABLE語法”

存儲引擎不支持有些操作,如果進行這些操作,會出現警告。使用SHOW WARNINGS可以顯示出這些警告。請參見13.5.4.22節,“SHOW WARNINGS語法”

如果您使用ALTER TABLE更改列規約,但是DESCRIBE tbl_name提示您列規約并沒有改變,則可能是因為MySQL忽略了您所做的更改。忽略更改的原因見13.1.5.1節,“沉寂的列規格變更”。例如,如果您試圖把VARCHAR列更改為CHAR列,此時,如果表包含其它長度可變的列,則MySQL仍會使用VARCHAR

ALTER TABLE運行時會對原表進行臨時復制,在副本上進行更改,然后刪除原表,再對新表進行重命名。在執行ALTER TABLE時,其它用戶可以閱讀原表,但是對表的更新和修改的操作將被延遲,直到新表生成為止。新表生成后,這些更新和修改信息會自動轉移到新表上。

注意,如果您在執行ALTER TABLE時使用除了RENAME以外的選項,則MySQL會創建一個臨時表。即使數據并不需要進行復制(例如當您更改列的名稱時),MySQL也會這么操作。對于MyISAM表,您可以通過把myisam_sort_buffer_size系統變量設置到一個較高的值,來加快重新創建索引(該操作是變更過程中速度最慢的一部分)的速度。

·         要使用ALTER TABLE,您需要獲得表的ALTER, INSERTCREATE權限。

·         IGNOREMySQL相對于標準SQL的擴展。如果在新表中有重復關鍵字,或者當STRICT模式啟動后出現警告,則使用IGNORE控制ALTER TABLE的運行。如果沒有指定IGNORE,當重復關鍵字錯誤發生時,復制操作被放棄,返回前一步驟。如果指定了IGNORE,則對于有重復關鍵字的行,只使用第一行,其它有沖突的行被刪除。并且,對錯誤值進行修正,使之盡量接近正確值。

·         您可以在一個ALTER TABLE語句里寫入多個ADD, ALTER, DROPCHANGE子句,中間用逗號分開。這是MySQL相對于標準SQL的擴展。在標準SQL中,每個ALTER TABLE語句中每個子句只允許使用一次。例如,在一個語句中取消多個列:

·                mysql> ALTER TABLE t2 DROP COLUMN c, DROP COLUMN d;

·         CHANGE col_name, DROP col_nameDROP INDEXMySQL相對于標準SQL的擴展。

·         MODIFYOracleALTER TABLE的擴展。

·         COLUMN只是自選項目,可以忽略。

·         如果您使用ALTER TABLE tbl_name RENAME TO new_tbl_name并且沒有其它選項,則MySQL只對與table tbl_name相對應的文件進行重命名。不需要創建一個臨時表。(您也可以使用RENAME TABLE語句對表進行重命名。請參見13.1.9節,“RENAME TABLE語法”。)

·         column_definition子句使用與CREATE TABLE中的ADDCHANGE子句相同的語法。注意,此語法包括列名稱,而不只是列類型。請參見13.1.5節,“CREATE TABLE語法”

·         您可以使用CHANGE old_col_name column_definition子句對列進行重命名。重命名時,需給定舊的和新的列名稱和列當前的類型。例如:要把一個INTEGER列的名稱從a變更到b,您需要如下操作:

·                mysql> ALTER TABLE t1 CHANGE a b INTEGER;

如果您想要更改列的類型而不是名稱, CHANGE語法仍然要求舊的和新的列名稱,即使舊的和新的列名稱是一樣的。例如:

mysql> ALTER TABLE t1 CHANGE b b BIGINT NOT NULL;

您也可以使用MODIFY來改變列的類型,此時不需要重命名:

mysql> ALTER TABLE t1 MODIFY b BIGINT NOT NULL;

·         如果您使用CHANGEMODITY縮短列長時,列中存在有索引,并且縮短后的列長小于索引長度,則MySQL會自動縮短索引的長度。

·         當您使用CHANGEMODIFY更改列的類型時,MySQL會盡量把原有的列值轉化為新的類型。

·         您可以使用FIRSTAFTER col_name在一個表行中的某個特定位置添加列。默認把列添加到最后。您也可以在CHANGEMODIFY語句中使用FIRSTAFTER

·         AFTER COLUMN用于指定列的新默認值,或刪除舊的默認值。如果舊的默認值被刪除同時列值為NULL,則新的默認值為NULL。如果列值不能為NULLMySQL會指定一個默認值,請參見13.1.5節,“CREATE TABLE語法”

·         DROP INDEX用于取消索引。這是MySQL相對于標準SQL的擴展。請參見13.1.7節,“DROP INDEX語法”

·         如果列從表中被取消了,則這些列也從相應的索引中被取消。如果組成一個索引的所有列均被取消,則該索引也被取消。

·         如果一個表只包含一列,則此列不能被取消。如果您想要取消表,應使用DROP TABLE

·         DROP PRIMAY DEY用于取消主索引。注釋:在MySQL較早的版本中,如果沒有主索引,則DROP PRIMARY KEY會取消表中的第一個UNIQUE索引。在MySQL 5.1中不會出現這種情況。如果在MySQL 5.1中對沒有主鍵的表使用DROP PRIMARY KEY,則會出現錯誤信息。

如果您向表中添加UNIQUE KEYPRIMARY KEY,則UNIQUE KEYPRIMARY KEY會被儲存在非唯一索引之前,這樣MySQL就可以盡早地檢查出重復關鍵字。

·         ORDER BY用于在創建新表時,讓各行按一定的順序排列。注意,在插入和刪除后,表不會仍保持此順序。當您知道多數情況下您會按照特定的順序查詢各行時,可以使用這個選項;在對表進行了大的改動后,通過使用此選項,您可以提高查詢效率。在有些情況下,如果表按列排序,對于MySQL來說,排序可能會更簡單。

·         如果您對一個MyISAM表使用ALTER TABLE,則所有非唯一索引會被創建到一個單獨的批里(和REPAIR TABLE相同)。當您有許多索引時,這樣做可以使ALTER TABLE的速度更快。

這項功能可以明確激活。ALTER TABLE...DISABLE KEYSMySQL停止更新MyISAM表中的非唯一索引。然后使用ALTER TABLE ... ENABLE KEYS重新創建丟失的索引。進行此操作時,MySQL采用一種特殊的算法,比一個接一個地插入關鍵字要快很多。因此,在進行成批插入操作前先使關鍵字禁用可以大大地加快速度。使用ALTER TABLE ... DISABLE KEYS除了需要獲得以前提到的權限以外,還需要獲得INDEX權限。

·         Innodb存儲引擎支持FOREIGN KEYREFERENCES子句。Innodb存儲引擎執行ADD [CONSTRAINT [symbol]] FOREIGN KEY (...) REFERENCES ... (...)。請參見15.2.6.4節,“FOREIGN KEY約束”。對于其它存儲引擎,這些子句會被分析,但是會被忽略。對于所有的存儲引擎,CHECK子句會被分析,但是會被忽略。請參見13.1.5節,“CREATE TABLE語法”。接受這些子句但又忽略子句的原因是為了提高兼容性,以便更容易地從其它SQL服務器中導入代碼,并運行應用程序,創建帶參考數據的表。請參見1.8.5節,“MySQL與標準SQL的差別”

·         InnoDB支持使用ALTER TABLE來取消外鍵:

·                ALTER TABLE yourtablename DROP FOREIGN KEY fk_symbol;

要了解更多信息,請參見15.2.6.4節,“FOREIGN KEY約束”

·         ALTER TABLE忽略DATA DIRECTORYINDEX DIRECTORY表選項。

·         如果您想要把表默認的字符集和所有字符列(CHAR, VARCHAR, TEXT)改為新的字符集,應使用如下語句:

·                ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

警告:前面的操作轉換了字符集之間的列類型。如果您有一列使用一種字符集(如latin1),但是存儲的值實際上使用了其它的字符集(如utf8),這種情況不是您想要的。此時,您必須對這樣的列進行以下操作。

ALTER TABLE t1 CHANGE c1 c1 BLOB;
ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;

這種方法能夠實現此功能的原因是,當您轉換到BLOB列或從BLOB列轉換過來時,并沒有發生轉換。

如果您指定CONVERT TO CHARACTER SET為二進制,則TEXT列被轉換到相應的二進制字符串類型(BINARY, VARBINARY, BLOB)。這意味著這些列將不再有字符集,接下來的CONVERT TO操作也將不適用于這些列。

要僅僅改變一個表的默認字符集,應使用此語句:

ALTER TABLE tbl_name DEFAULT CHARACTER SET charset_name;

詞語DEFAULT為自選項。如果您在向表中添加一個新列時(例如,使用ALTER TABLE...ADD column)沒有指定字符集,則此時使用的字符集為默認字符集。

警告:ALTER TABLE...DEFAULT CHARACTER SETALTER TABLE...CHARACTER SET是等價的,只用于更改默認的表字符集。

·         如果InnoDB表在創建時,使用了.ibd文件中的自己的表空間,則這樣的文件可以被刪除和導入。使用此語句刪除.ibd文件:

·                ALTER TABLE tbl_name DISCARD TABLESPACE;

此語句用于刪除當前的.ibd文件,所以應首先確認您有一個備份。如果在表空間被刪除后嘗試打開表格,則會出現錯誤。

要把備份的.ibd文件還原到表中,需把此文件復制到數據庫目錄中,然后書寫此語句:

ALTER TABLE tbl_name IMPORT TABLESPACE;

15.2.6.6節,“使用按表的表空間”

·         使用mysql_info() C API函數,您可以了解有多少記錄已被復制,以及(當使用IGNORE時)有多少記錄由于重復關鍵字的原因已被刪除。請參見25.2.3.34節,“mysql_info()”

·         ALTER TABLE也可以用于對帶分區的表進行重新分區,功能包括添加、取消、合并和拆分各分區,還可以用于進行分區維護。

對帶分區的表使用partition_options子句和ALTER TABLE可以對表進行重新分區,使用時依據partition_options定義的分區方法。本子句以PARTITION BY為開頭,然后使用與用于CREATE TABLEpartition_options子句一樣的語法和規則(要了解詳細信息,請參見13.1.5節,“CREATE TABLE語法”)。注釋:MySQL 5.1服務器目前接受此語法,但是不實際執行;等MySQL 5.1開發出來后,將執行此語法。

用于ALTER TABLE ADD PARTITIONpartition_definition子句支持用于CREATE TABLE語句的partition_definition子句的同樣名稱的選項。(要了解語法和介紹,請參見13.1.5節,“CREATE TABLE語法”。)例如,假設您有一個按照以下方式創建的帶分區的表:

CREATE TABLE t1 (
    id INT,
    year_col INT
)
PARTITION BY RANGE (year_col) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1995),
    PARTITION p2 VALUES LESS THAN (1999)
);    

您可以在表中增加一個新的分區p3,該分區用于儲存小于2002的值。添加方法如下:

ALTER TABLE t1 ADD PARTITION p3 VALUES LESS THAN (2002);

注釋:您不能使用ALTER TABLE向一個沒有進行分區的表添加分區。

DROP PARTITION用于取消一個或多個RANGELIST分區。此命令不能用于HASHKEY 分區;用于這兩個分區時,應使用COALESCE PARTITION(見后)。如果被取消的分區其名稱列于partition_names清單中,則儲存在此分區中的數據也被取消。例如,如果以前已定義的表t1,您可以采用如下方法取消名稱為p0p1的分區:

ALTER TABLE DROP PARTITION p0, p1;

ADD PARTITIONDROP PARTITION目前不支持IF [NOT] EXISTS。也不可能對一個分區或一個已分區的表進行重命名。如果您希望對一個分區進行重命名,您必須取消分區,再重新建立;如果您希望對一個已分區的表進行重新命名,您必須取消所有分區,然后對表進行重命名,再添加被取消的分區。

COALESCE PARTITION可以用于使用HASHKEY進行分區的表,以便使用number來減少分區的數目。例如,假設您使用下列方法創建了表t2

CREATE TABLE t2 (
    name VARCHAR (30),
    started DATE
)
PARTITION BY HASH(YEAR(started))
PARTITIONS (6);

您可以使用以下命令,把t2使用的分區的數目由6個減少到4個:

ALTER TABLE t2 COALESCE PARTITION 2;

包含在最后一個number分區中的數據將被合并到其余的分區中。在此情況下,分區4和分區5將被合并到前4個分區中(編號為0123的分區)。

如果要更改部分分區,但不更改所有的分區,您可以使用REORGANIZE PARTITION。這個命令有多種使用方法:

o        把多個分區合并為一個分區。通過把多個分區的名稱列入partition_names清單,并為partition_definition提供一個單一的定義,可以實現這個功能。

o        把一個原有的分區拆分為多個分區。通過為partition_names命名一個分區,并提供多個partition_definitions,可以實現這個功能。

o        更改使用VALUES LESS THAN定義的分區子集的范圍或更改使用VALUES IN定義的分區子集的值清單。

注釋:對于沒有明確命名的分區,MySQL會自動提供默認名稱p0, p1, p2等。

要了解有關ALTER TALBE...REORANIZE PARTITION命令的詳細信息,請參見18.3節,“分區管理”

·         多個附加子句用于提供分區維護和修補功能。這些功能與用于非分區表的功能類似。這些功能由CHECK TABLEREPAIR TABLE等命令(這些命令不支持用于分區表)執行。這些子句包括ANALYZE PARTITION, CHECK PARTITION, OPTIMIZE PARTITION, REBUILD PARTITIONREPAIR PARTITION.每個選項均為一個partition_names子句,包括一個或多個分區名稱。需要更改的表中必須已存在這些分區。多個分區名稱用逗號分隔。要了解更多信息,或要了解舉例說明,請參見18.3.3節,“分區維護”

以下例子展示了ALTER TABLE的使用。首先展示表t1。表t1采用如下方法創建:

mysql> CREATE TABLE t1 (a INTEGER,b CHAR(10));

把表t1重新命名為t2

mysql> ALTER TABLE t1 RENAME t2;

把列aINTERGER更改為TINYINT NOT NULL(名稱保持不變),并把列bCHAR(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 INDEX (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 PRIMARY KEY (c);

注意我們為c編制了索引(作為PRIMARY KEY),因為AUTO_INCREMENT列必須編制索引。同時我們定義cNOT NULL,因為主鍵列不能為NULL

當您添加一個AUTO_INCREMENT列時,列值被自動地按序號填入。對于MyISAM表,您可以在ALTER TABLE之前執行SET INSERT_ID=value來設置第一個序號,也可以使用AUTO_INCREMENT=value表選項來設置。請參見13.5.3節,“SET語法”

如果值大于AUTO_INCREMENT列中的最大值,則您可以使用用于InnoDB表的ALTER TALBE...AUTO_INCREMENT=value表選項,來為新行設置序號。如果值小于列中當前的最大值,不會出現錯誤信息,當前的序列值也不改變。

使用MyISAM表時,如果您不更改AUTO_INCREMENT列,則序列號不受影響。如果您取消一個AUTO_INCREMENT列,然后添加另一個AUTO_INCREMENT列,則序號重新排列,從1開始。

A.7.1節,“與ALTER TABLE有關的問題”

13.1.3.?CREATE DATABASE語法

CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name
    [create_specification [, create_specification] ...]
 
create_specification:
    [DEFAULT] CHARACTER SET charset_name
  | [DEFAULT] COLLATE collation_name

CREATE DATABASE用于創建數據庫,并進行命名。如果要使用CREATE DATABASE,您需要獲得數據庫CREATE權限。

有關合法數據庫名稱的規定列于9.2節,“數據庫、表、索引、列和別名”。如果存在數據庫,并且您沒有指定IF NOT EXISTS,則會出現錯誤。

create_specification選項用于指定數據庫的特性。數據庫特性儲存在數據庫目錄中的db.opt文件中。CHARACTER SET子句用于指定默認的數據庫字符集。COLLATE子句用于指定默認的數據庫整序。字符集和整序名稱在第10章字符集支持中討論。

有些目錄包含文件,這些文件與數據庫中的表對應。MySQL中的數據庫的執行方法與這些目錄的執行方法相同。因為當數據庫剛剛被創建時,在數據庫中沒有表,所以CREATE DATABASE只創建一個目錄。這個目錄位于MySQL數據目錄和db.opt文件之下。

如果您手動在數據目錄之下創建一個目錄(例如,使用mkdir),則服務器會認為這是一個數據庫目錄,并在SHOW DATABASES的輸出中顯示出來。

也可以使用CREATE SCHEMA

您還可以使用mysqladmin程序創建數據庫。請參見8.5節,“mysqladmin:用于管理MySQL服務器的客戶端”

13.1.4.?CREATE INDEX語法

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
    [USING index_type]
    ON tbl_name (index_col_name,...)
 
index_col_name:
    col_name [(length)] [ASC | DESC]

CREATE INDEX被映射到一個ALTER TABLE語句上,用于創建索引。請參見13.1.2節,“ALTER TABLE語法”

通常,當使用CREATE TABLE創建表時,也同時在表中創建了所有的索引。請參見13.1.5節,“CREATE TABLE語法”CREATE INDEX允許您向已有的表中添加索引。

格式為(col1, col2,...)的一個列清單創建出一個多列索引。通過串接給定列中的值,確定索引值的格式。

對于CHARVARCHAR列,只用一列的一部分就可創建索引。創建索引時,使用col_name(length)語法,對前綴編制索引。前綴包括每列值的前length字符。BLOBTEXT列也可以編制索引,但是必須給出前綴長度。

此處展示的語句用于創建一個索引,索引使用列名稱的前10個字符。

CREATE INDEX part_of_name ON customer (name(10));

因為多數名稱的前10個字符通常不同,所以此索引不會比使用列的全名創建的索引速度慢很多。另外,使用列的一部分創建索引可以使索引文件大大減小,從而節省了大量的磁盤空間,有可能提高INSERT操作的速度。

前綴最長為255字節。對于MyISAMInnoDB表,前綴最長為1000字節。注意前綴的限長以字節計,而CREATE INDEX語句中的前綴長度指的是字符的數目。對于使用多字節字符集的列,在指定列的前綴長度時,要考慮這一點。

MySQL 5.1中:

·         只有當您正在使用MyISAM, InnoDBBDB表類型時,您可以向有NULL值的列中添加索引。

·         只有當您正在使用MyISAM, BDBInnoDB表類型時,您可以向BLOBTEXT列中添加索引。

一個index_col_name規約可以以ASCDESC為結尾。這些關鍵詞將來可以擴展,用于指定遞增或遞減索引值存儲。目前,這些關鍵詞被分析,但是被忽略;索引值均以遞增順序存儲。

部分儲存引擎允許在創建索引時指定索引類型。index_type指定語句的語法是USING type_name。不同的儲存引擎所支持的type_name值已顯示在下表中。如果列有多個索引類型,當沒有指定index_type時,第一個類型是默認值

存儲引擎

允許的索引類型

MyISAM

BTREE

InnoDB

BTREE

MEMORY/HEAP

HASH, BTREE

示例:

CREATE TABLE lookup (id INT) ENGINE = MEMORY;
CREATE INDEX id_index USING BTREE ON lookup (id);

TYPE type_name可以作為USING type_name的同義詞,用于指定索引類型。但是,USING是首選的格式。另外,在索引規約語法中,位于索引類型前面的索引名稱不能使用TYPE。這是因為,與USING不同,TYPE不是保留詞,因此會被認為是一個索引名稱。

如果您指定的索引類型在給定的儲存引擎中不合法,但是有其它的索引類型適合引擎使用,并且不會影響查詢功能,則引擎應使用此類型。

要了解更多有關MySQL如何使用索引的信息,請參見7.4.5節,“MySQL如何使用索引”

FULLTEXT索引只能對CHAR, VARCHARTEXT列編制索引,并且只能在MyISAM表中編制。請參見12.7節,“全文搜索功能”

SPATIAL索引只能對空間列編制索引,并且只能在MyISAM表中編制。空間列類型在第19章:MySQL中的空間擴展中進行了描述。

13.1.5.?CREATE TABLE語法

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,...)]
    [table_options] [select_statement]

或:

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(] LIKE old_tbl_name [)];
 
create_definition:
    column_definition
  | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...)
  | KEY [index_name] [index_type] (index_col_name,...)
  | INDEX [index_name] [index_type] (index_col_name,...)
  | [CONSTRAINT [symbol]] UNIQUE [INDEX]
        [index_name] [index_type] (index_col_name,...)
  | [FULLTEXT|SPATIAL] [INDEX] [index_name] (index_col_name,...)
  | [CONSTRAINT [symbol]] FOREIGN KEY
        [index_name] (index_col_name,...) [reference_definition]
  | CHECK (expr)
 
column_definition:
    col_name type [NOT NULL | NULL] [DEFAULT default_value]
        [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
        [COMMENT 'string'] [reference_definition]
 
type:
    TINYINT[(length)] [UNSIGNED] [ZEROFILL]
  | SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
  | MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
  | INT[(length)] [UNSIGNED] [ZEROFILL]
  | INTEGER[(length)] [UNSIGNED] [ZEROFILL]
  | BIGINT[(length)] [UNSIGNED] [ZEROFILL]
  | REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
  | DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
  | NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
  | DATE
  | TIME
  | TIMESTAMP
  | DATETIME
  | CHAR(length) [BINARY | ASCII | UNICODE]
  | VARCHAR(length) [BINARY]
  | TINYBLOB
  | BLOB
  | MEDIUMBLOB
  | LONGBLOB
  | TINYTEXT [BINARY]
  | TEXT [BINARY]
  | MEDIUMTEXT [BINARY]
  | LONGTEXT [BINARY]
  | ENUM(value1,value2,value3,...)
  | SET(value1,value2,value3,...)
  | spatial_type
 
index_col_name:
    col_name [(length)] [ASC | DESC]
 
reference_definition:
    REFERENCES tbl_name [(index_col_name,...)]
               [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
               [ON DELETE reference_option]
               [ON UPDATE reference_option]
 
reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION
 
table_options: table_option [table_option] ...
 
table_option:
    {ENGINE|TYPE} = engine_name
  | AUTO_INCREMENT = value
  | AVG_ROW_LENGTH = value
  | [DEFAULT] CHARACTER SET charset_name [COLLATE collation_name]
  | CHECKSUM = {0 | 1}
  | COMMENT = 'string'
  | CONNECTION = 'connect_string'
  | MAX_ROWS = value
  | MIN_ROWS = value
  | PACK_KEYS = {0 | 1 | DEFAULT}
  | PASSWORD = 'string'
  | DELAY_KEY_WRITE = {0 | 1}
  | ROW_FORMAT = {DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}
  | UNION = (tbl_name[,tbl_name]...)
  | INSERT_METHOD = { NO | FIRST | LAST }
  | DATA DIRECTORY = 'absolute path to directory'
  | INDEX DIRECTORY = 'absolute path to directory'
 
partition_options:
    PARTITION BY
           [LINEAR] HASH(expr)
        |  [LINEAR] KEY(column_list)
        |  RANGE(expr)
        |  LIST(column_list)
    [PARTITIONS num]
    [  SUBPARTITION BY
           [LINEAR] HASH(expr)
         | [LINEAR] KEY(column_list)
      [SUBPARTITIONS(num)]  
    ]
    [(partition_definition), [(partition_definition)], ...]
 
partition_definition:
    PARTITION partition_name
        [VALUES { 
                  LESS THAN (expr) | MAXVALUE 
                | IN (value_list) }]
        [[STORAGE] ENGINE [=] engine-name]
        [COMMENT [=] 'comment_text' ]
        [DATA DIRECTORY [=] 'data_dir']
        [INDEX DIRECTORY [=] 'index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] (tablespace_name)]
        [NODEGROUP [=] node_group_id]
        [(subpartition_definition), [(subpartition_definition)], ...]
 
subpartition_definition:
    SUBPARTITION logical_name
        [[STORAGE] ENGINE [=] engine-name]
        [COMMENT [=] 'comment_text' ]
        [DATA DIRECTORY [=] 'data_dir']
        [INDEX DIRECTORY [=] 'index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] (tablespace_name)]
        [NODEGROUP [=] node_group_id]
 
select_statement:
    [IGNORE | REPLACE] [AS] SELECT ...   (Some legal select statement)

CREATE TABLE用于創建帶給定名稱的表。您必須擁有表CREATE權限。

允許的表名稱的規則列于9.2節,“數據庫、表、索引、列和別名”中。默認的情況是,表被創建到當前的數據庫中。如果表已存在,或者如果沒有當前數據庫,或者如果數據庫不存在,則會出現錯誤。

表名稱被指定為db_name.tbl_name,以便在特定的數據庫中創建表。不論是否有當前數據庫,都可以通過這種方式創建表。如果您使用加引號的識別名,則應對數據庫和表名稱分別加引號。例如,`mydb`.`mytbl`是合法的,但是`mydb.mytbl`不合法。

在創建表格時,您可以使用TEMPORARY關鍵詞。只有在當前連接情況下,TEMPORARY表才是可見的。當連接關閉時,TEMPORARY表被自動取消。這意味著兩個不同的連接可以使用相同的臨時表名稱,同時兩個臨時表不會互相沖突,也不與原有的同名的非臨時表沖突。(原有的表被隱藏,直到臨時表被取消時為止。)您必須擁有CREATE TEMPORARY TABLES權限,才能創建臨時表。

如果表已存在,則使用關鍵詞IF NOT EXISTS可以防止發生錯誤。注意,原有表的結構與CREATE TABLE語句中表示的表的結構是否相同,這一點沒有驗證。注釋:如果您在CREATE TABLE...SELECT語句中使用IF NOT EXISTS,則不論表是否已存在,由SELECT部分選擇的記錄都會被插入。

MySQL通過數據庫目錄中的.frm表格式(定義)文件表示每個表。表的存儲引擎也可能會創建其它文件。對于MyISAM表,存儲引擎可以創建數據和索引文件。因此,對于每個MyISAMtbl_name,有三個磁盤文件:

文件

作用

tbl_name.frm

表格式(定義)文件

tbl_name.MYD

數據文件

tbl_name.MYI

索引文件

用于表示表的由存儲引擎創建的文件在第15章:存儲引擎和表類型中描述。

要了解有關各種列類型的性質的一般說明,請參見第11章:列類型。要了解有關空間列類型的說明,請參見第19章:MySQL中的空間擴展

·         如果沒有指定是NULL或是NOT NULL,則列在創建時假定指定為NULL

·         一個整數列可以擁有一個附加屬性AUTO_INCREMENT。當您向一個已編入索引的AUTO_INCREMENT列中插入一個NULL值(建議)或0時,此列被設置為下一個序列的值。通常情況下為value+1,此處value是當前在表中的列的最大值。AUTO_INCREMENT序列從1開始。這樣的列必須被定義為一種整數類型,請參見11.1.1節,“數值類型概述”中的敘述。(值1.0不是整數)。請參見25.2.3.36節,“mysql_insert_id()”

--sql-mode服務器選項或sql_mode系統變量指定NO_AUTO_VALUE_ON_ZERO特征位,這樣可以把0存儲到AUTO_INCREMENT列中,同時不生成一個新的序列值。請參見5.3.1節,“mysqld命令行選項”

注釋:有時候,每個表只有一個AUTO_INCREMENT列,此列必須編制索引,不能有DEFAULT值。一個AUTO_INCREMENT列只有在只包含正數的情況下,才能運行正常。插入一個負數會被認為是插入了一個非常大的正數。這樣做是為了避免當數字由正數轉為負數時出現精度問題,同時也為了確保AUTO_INCREMENT列中不會包含0

對于MyISAMBDB表,您可以在一個多列關鍵字中指定一個AUTO_INCREMENT次級列。請參見3.6.9節,“使用AUTO_INCREMENT”

為了讓MySQL與部分ODBC應用軟件相兼容,您可以使用以下查詢方法找到最后一個插入行的AUTO_INCREMENT值:

SELECT * FROM tbl_name WHERE auto_col IS NULL

·         字符列的定義可以包括一個CHARACTER SET屬性,用來指定字符集,也可以指定列的整序。要了解詳細情況,請參見第10章:字符集支持CHARSETCHARACTER SET的同義詞。

·                CREATE TABLE t (c CHAR(20) CHARACTER SET utf8 COLLATE utf8_bin);

MySQL 5.1理解,在字符列定義中的長度規約以字符為單位。(有些早期版本以字節為單位。)

·         DEFAULT子句用于為列指定一個默認值。默認值必須為一個常數,不能為一個函數或一個表達式,有一種情況例外。例如,一個日期列的默認值不能被設置為一個函數,如NOW()CURRENT_DATE。不過,有一種例外,您可以對TIMESTAMP列指定CURRENT_TIMESTAMP為默認值。請參見11.3.1.1節,“MySQL 4.1中的TIMESTAMP屬性”

BLOBTEXT列不能被賦予默認值。

如果在列定義中沒有明確的DEFAULT值,則MySQL按照如下規則確定默認值:

如果列可以使用NULL作為值,則使用DEFAULT NULL子句對列進行定義。(在MySQL的早期版本中也如此。)

如果列不能使用NULL作為值,則MySQL對列進行定義時不使用DEFAULT子句。輸入數據時,如果INSERTREPLACE語句不包括列的值,則MySQL依據當時的有效的SQL模式操作列:

o        如果嚴格模式沒有被啟用,則MySQL會根據列數據類型,把列設置為明確的默認值。

o        如果嚴格模式已被啟用,則事務表會出現錯誤,語句被回滾。對于非事務表,會出現錯誤,不過,如果錯誤出現在一個多行語句中的第二行或后續行,則以前的各行將被插入。

假設表t按下面的方法進行定義:

CREATE TABLE t (i INT NOT NULL);

在這種情況下,i沒有明確的默認值,所以在嚴格模式中,每個后續語句都會產生一個錯誤,并且沒有行被插入。當未使用嚴格模式時,只有第三個語句產生錯誤;明確的默認值被插入到前兩個語句中,但是第三個語句會出現錯誤,因為DEFAULT(i)不會產生一個值:

INSERT INTO t VALUES();
INSERT INTO t VALUES(DEFAULT);
INSERT INTO t VALUES(DEFAULT(i));

5.3.2節,“SQL服務器模式”

對于一個給定的表,您可以使用SHOW CREATE TABLE語句來查看那些列有明確的DEFAULT子句。

·         對于列的評注可以使用COMMENT選項來進行指定。評注通過SHOW CREATE TABLESHOW FULL COLUMNS語句顯示。

·         屬性SERIAL可以用作BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE的別名。

·         KEY通常是INDEX同義詞。如果關鍵字屬性PRIMARY KEY在列定義中已給定,則PRIMARY KEY也可以只指定為KEY。這么做的目的是與其它數據庫系統兼容。

·         UNIQUE索引中,所有的值必須互不相同。如果您在添加新行時使用的關鍵字與原有行的關鍵字相同,則會出現錯誤。例外情況是,如果索引中的一個列允許包含NULL值,則此列可以包含多個NULL值。此例外情況不適用于BDB表。在BDB中,帶索引的列只允許一個單一NULL

·         PRIMARY KEY是一個唯一KEY,此時,所有的關鍵字列必須定義為NOT NULL。如果這些列沒有被明確地定義為NOT NULLMySQL應隱含地定義這些列。一個表只有一個PRIMARY KEY。如果您沒有PRIMARY KEY并且一個應用程序要求在表中使用PRIMARY KEY,則MySQL返回第一個UNIQUE索引,此索引沒有作為PRIMARY KEYNULL列。

·         在已創建的表中,PRIMARY KEY的位置最靠前,然后是所有的UNIQUE索引,然后是非唯一索引。這可以幫助MySQL優化程序選擇優先使用哪個索引,并且更快速的檢測出重復的UNIQUE關鍵字。

·         PRIMARY KEY可以是一個多列索引。但是,在列規約中使用PRIMARY KEY關鍵字屬性無法創建多列索引。這么做只能把一個列標記為主列。您必須使用一個單獨的PRIMARY KEYindex_col_name, ...)子句。

·         如果PRIMARY KEYUNIQUE索引只包括一個列,并且此列為整數類型,則您也可以在SELECT語句中把此列作為_rowid引用。

·         MySQL中,PRIMARY KEY的名稱為PRIMARY。對于其它索引,如果您沒有賦予名稱,則索引被賦予的名稱與第一個已編入索引的列的名稱相同,并自選添加后綴(_2, _3,...),使名稱為唯一名稱。您可以使用SHOW INDEX FROM tbl_name來查看表的索引名稱。請參見13.5.4.11節,“SHOW INDEX語法”

·         部分存儲引擎允許您在創建索引時指定索引類型。index_type指示語句的語法是USING type_name

示例:

CREATE TABLE lookup
  (id INT, INDEX USING BTREE (id))
  ENGINE = MEMORY;

要了解有關USING的詳細說明,請參見13.1.4節,“CREATE INDEX語法”

要了解有關MySQL如何使用索引的更多信息,請參見7.4.5節,“MySQL如何使用索引”

·         MySQL 5.1中,只有MyISAMInnoDB, BDBMEMORY存儲引擎支持在含有NULL值的列中編索引。在其它情況下,您必須定義已編索引的列為NOT NULL,否則會出現錯誤。

·         在一個索引規約中使用col_name(length)語法,您可以創建一個索引,此索引只使用一個CHARVARCHAR列的第一個length字符。只對列值的前綴編制索引可以使索引文件大大減小。請參見7.4.3節,“列索引”

MyISAMInnoDB存儲引擎也支持對BLOBTEXT列編索引。當對BLOBTEXT列編索引時,您必須為索引指定一個前綴長度。例如:

CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));

對于MyISAMInnoDB表,前綴最長可以為1000字節,對于其它表格類型,最長可以為255字節。注意前綴長度限值以字節為單位,而在CREATE TABLE語句中的前綴長度用字符數目來表述。當為一個使用多字節字符集的列指定前綴長度時,一定要考慮到這一點。

·         一個index_col_name規約可以以ASCDESC結尾。這些關鍵詞可以在將來進行擴展,用于指定升序或降序的索引值存儲。當前,這些關鍵詞被分析但是被忽略;索引值均以升序儲存。

·         當您在SELECT中的TEXT列或BLOB列中使用ORDER BYGROUP BY時,服務器只使用初始的字節數目對值進行分類。字節數目由max_sort_length系統變量進行指示。請參見11.4.3節,“BLOB和TEXT類型

·         您可以創建特殊的FULLTEXT索引,用于全文搜索。只有MyISAM表類型支持FULLTEXT索引。FULLTEXT索引只可以從CHAR, VARCHARTEXT列中創建。整個列都會被編入索引;不支持對部分列編索引。如果已指定,前綴長度會被忽略。要了解運行的詳細說明,請參見12.7節,“全文搜索功能”

·         您可以為空間列類型創建SPATIAL索引。只有MyISAM表支持空間類型,已編索引的列必須聲明為NOT NULL。請參見第19章:MySQL中的空間擴展

·         InnoDB表支持對外鍵限制條件進行檢查。請參見15.2節,“InnoDB存儲引擎”。注意,在InnoDB中,FOREIGN KEY語法比本節開始時介紹的CREATE TABLE語句的語法更嚴格:被引用的表中的列必須有明確的命名。InnoDB支持外鍵的ON DELETEON UPDATE兩種操作。有關精確語法的說明,請參見15.2.6.4節,“FOREIGN KEY約束”

對于其它存儲引擎,MySQL服務器對CREATE TABLE語句中的FOREIGN KEYREFERENCES語法進行分析,但不采取進一步的行動。所有的存儲引擎均對CHECK子句進行分析,但是忽略CHECK子句。請參見1.8.5.5節,“外鍵”

·         對于MyISAM表,每個NULL列要多占用一位,進位到距離最近的字節。最大記錄長度(以字節為單位)按照如下方法計算:

·                row length = 1
·                             + (sum of column lengths)
·                             + (number of NULL columns + delete_flag + 7)/8
·                             + (number of variable-length columns)

對于采用靜態記錄格式的表,delete_flag1。靜態表在行記錄中使用一位用作位標記。位標記指示該行是否已被刪除。對于動態表,delete_flag0,因為在動態行標題中已存儲了位標記。

這些計算方法不適用于InnoDB表。對于InnoDB表,NULL列的存儲量與NOT NULL列的存儲量沒有區別。

ENGINETYPE選項用于為表指定存儲引擎。ENGINE是首選的選項名稱。

ENGINETYPE選項采用以下值:

存儲引擎

說明

ARCHIVE

檔案存儲引擎。請參見15.8節,“ARCHIVE存儲引擎”

BDB

帶頁面鎖定的事務安全表。也稱為BerkeleyDB。請參見15.5節,“BDB (BerkeleyDB)存儲引擎”

CSV

值之間用逗號隔開的表。請參見15.9節,“CSV存儲引擎

EXAMPLE

示例引擎。請參見15.6節,“EXAMPLE存儲引擎”

FEDERATED

可以訪問遠程表的存儲引擎。請參見15.7節,“FEDERATED存儲引擎”

HEAP

15.4節,“MEMORY (HEAP)存儲引擎”

(OBSOLETE) ISAM

MySQL 5.1中沒有此引擎。如果您要從以前的版本升級到MySQL 5.1,您應該在進行升級前把原有的ISAM表轉換為MyISAM表。請參見第15章:存儲引擎和表類型

InnoDB

帶行鎖定和外鍵的事務安全表。請參見15.2節,“InnoDB存儲引擎”

MEMORY

本表類型的數據只保存在存儲器里。(在早期MySQL版本中被稱為HEAP。)

MERGE

MyISAM表的集合,作為一個表使用。也稱為MRG_MyISAM。請參見15.3節,“MERGE存儲引擎”

MyISAM

二進制輕便式存儲引擎,此引擎是MySQL所用的默認存儲引擎。請參見15.1節,“MyISAM存儲引擎”

NDBCLUSTER

成簇表,容錯表,以存儲器為基礎的表。也稱為NDB。請參見第17章:MySQL簇

要了解有關MySQL存儲引擎的更多信息,請參見第15章:存儲引擎和表類型

如果被指定的存儲引擎無法利用,則MySQL使用MyISAM代替。例如,一個表定義包括ENGINE=BDB選項,但是MySQL服務器不支持BDB表,則表被創建為MyISAM表。這樣,如果您在主機上有事務表,但在從屬機上創建的是非交互式表(以加快速度)時,可以進行復制設置。在MySQL 5.1中,如果沒有遵守存儲引擎規約,則會出現警告。

其它表選項用于優化表的性質。在多數情況下,您不必指定表選項。這些選項適用于所有存儲引擎,另有說明除外:

·         AUTO_INCREMENT

表的初始AUTO_INCREMENT值。在MySQL 5.1中,本選項只適用于MyISAMMEMORY表。InnoDB也支持本選項。如果引擎不支持AUTO_INCREMENT表選項,則要設置引擎的第一個auto-increment值,需插入一個“假”行。該行的值比創建表后的值小一,然后刪除該假行。

對于在CREATE TABLE語句中支持AUTO_INCREMENT表選項的引擎,您也可以使用ALTER TABLE tbl_name AUTO_INCREMENT = n來重新設置AUTO_INCREMENT值。

·         AVG_ROW_LENGTH

表中平均行長度的近似值。只需要對含尺寸可變的記錄的大型表進行此項設置。

當創建一個MyISAM表時,MySQL使用MAX_ROWSAVG_ROW_LENGTH選項的乘積來確定得出的表有多大。如果有一個選項未指定,則表的最大尺寸為65,536TB數據。(如果操作系統不支持這么大的文件,則表的尺寸被限定在操作系統的限值處。)如果您想縮小指針尺寸使索引更小,速度更快,并且您不需要大文件,則您可以通過設置myisam_data_pointer_size系統變量來減少默認指針的尺寸。(見5.3.3節,“服務器系統變量”。)如果您希望所有的表可以擴大,超過默認限值,并且愿意讓表稍微慢點,并稍微大點,則您可以通過設置此變量增加默認指針的尺寸。

·         [DEFAULT] CHARACTER SET

用于為表指定一個默認字符集。CHARSETCHARACTER SET的同義詞。

對于CHARACTER SET.

·         COLLATE

用于為表指定一個默認整序。

·         CHECKSUM

如果您希望MySQL隨時對所有行進行實時檢驗求和(也就是,表變更后,MySQL自動更新檢驗求和),則應把此項設置為1。這樣做,表的更新速度會略微慢些,但是更容易尋找到受損的表。CHECKSUM TABLE語句用于報告檢驗求和(僅限于MyISAM)。

·         COMMENT

表的注釋,最長60個字符。

·         CONNECTION

FEDERATED表的連接字符串。( 注釋:較早版本的MySQL使用COMMENT選項用于連接字符串。

·         MAX_ROWS

您打算儲存在表中的行數目的最大值。這不是一個硬性限值,而更像一個指示語句,指示出表必須能存儲至少這么多行。

·         MIN_ROWS

您打算存儲在表中的行數目的最小值。

·         PACK_KEYS

如果您希望索引更小,則把此選項設置為1。這樣做通常使更新速度變慢,同時閱讀速度加快。把選項設置為0可以取消所有的關鍵字壓縮。把此選項設置為DEFAULT時,存儲引擎只壓縮長的CHARVARCHAR列(僅限于MyISAM)。

如果您不使用PACK_KEYS,則默認操作是只壓縮字符串,但不壓縮數字。如果您使用PACK_KEYS=1,則對數字也進行壓縮。

在對二進制數字關鍵字進行壓縮時,MySQL采用前綴壓縮:

o        每個關鍵字需要一個額外的字節來指示前一個關鍵字中有多少字節與下一個關鍵字相同。

o        指向行的指針以高位字節優先的順序存儲在關鍵字的后面,用于改進壓縮效果。

這意味著,如果兩個連續行中有許多相同的關鍵字,則后續的“相同”的關鍵字通常只占用兩個字節(包括指向行的指針)。與此相比,常規情況下,后續的關鍵字占用storage_size_for_key + pointer_size(指針尺寸通常為4)。但是,只有在許多數字相同的情況下,前綴壓縮才有好處。如果所有的關鍵字完全不同,并且關鍵字不能含有NULL值,則每個關鍵字要多使用一個字節。(在這種情況中,儲存壓縮后的關鍵字的長度的字節與用于標記關鍵字是否為NULL的字節是同一字節。)

·         PASSWORD

使用密碼對.frm文件加密。在標準MySQL版本中,本選項不起任何作用。

·         DELAY_KEY_WRITE

如果您想要延遲對關鍵字的更新,等到表關閉后再更新,則把此項設置為1(僅限于MyISAM)。

·         ROW_FORMAT

定義各行應如何儲存。當前,此選項只適用于MyISAM表。對于靜態行或長度可變行,此選項值可以為FIXEDDYNAMICmyisampack用于把類型設置為COMPRESSED。請參見15.1.3節,“MyISAM表的存儲格式”

在默認情況下,InnoDB記錄以壓縮格式存儲(ROW_FORMAT=COMPACT)。通過指定ROW_FORMAT=REDUNDANT,仍然可以申請用于較早版本的MySQL中的非壓縮格式。

·         RAID_TYPE

MySQL 5.0,RAID支持被刪除了。要了解有關RAID的說明,請參見http://dev.mysql.com/doc/refman/4.1/en/create-table.html

·         UNION

當您想要把一組相同的表當作一個表使用時,采用UNIONUNION僅適用于MERGE表。請參見15.3節,“MERGE存儲引擎”

對于您映射到一個MERGE表上的表,您必須擁有SELECT, UPDATEDELETE權限。(注釋:以前,所有被使用的表必須位于同一個數據庫中,并作為MERGE表。這些限制不再適用。)

·         INSERT_METHOD

如果您希望在MERGE表中插入數據,您必須用INSERT_METHOD指定應插入行的表。INSERT_METHOD選項僅用于MERGE表。使用FIRSTLAST把行插入到第一個或最后一個表中;或者使用NO,阻止插入行。請參見15.3節,“MERGE存儲引擎”

·         DATA DIRECTORY, INDEX DIRECTORY

通過使用DATA DIRECTORY='directory'INDEX DIRECTORY='directory',您可以指定MyISAM存儲引擎放置表格數據文件和索引文件的位置。注意,目錄應是通向目錄的完整路徑(不是相對路徑)。

僅當您沒有使用--skip-symbolic-links選項時,DATA DIRECTORY, INDEX DIRECTORY才能使用。操作系統必須有一個正在工作的、線程安全的realpath()調用。要了解全面信息,請參見7.6.1.2節,“在Unix平臺上使用表的符號鏈接”。

·         對于用CREATE TABLE創建的表,可以使用partition_options控制分區。如果使用了partition_options,則其中必須包含至少一個PARTITION BY子句。本子句包含用于確定分區的函數;該函數會返回一個整值,范圍從1num。此處num為分區的數目。此函數中可以使用的選項顯示在下面的清單中。 要點:在本節開始時介紹的用于partition_options的語法中顯示的選項,并不是都能用于所有分區類型。要了解各種類型具體的信息 ,請參見以下各類型的清單。要了解有關在MySQL中的分區的操作和使用情況的全面說明,以及要了解表創建的示例和與MySQL分區有關的其它命令,請參見第18章:分區

o        HASHexpr):用于混編一個或多個列,創建一個關鍵字,用于放置行,并確定行的位置。expr是一個表達式,使用一個或多個表中的列。該表達式可以是任何能夠生成單一整值的合法的MySQL表達式(包括MySQL函數)。例如,這些都是有效的CREATE TABLE語句,語句中使用了PARTITION BY HASH

o                     CREATE TABLE t1 (col1 INT, col2 CHAR(5)) 
o                         PARTITION BY HASH(col1);
o                      
o                     CREATE TABLE t1 (col1 INT, col2 CHAR(5))
o                         PARTITION BY HASH( ORD(col2) );
o                      
o                     CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME)
o                         PARTITION BY HASH ( YEAR(col3) );

VALUES LESS THANVALUES IN子句不能和PARTITION BY HASH一起使用。

PARTITION BY HASH使用expr被分區數目所除后的余數(也就是模數)。要了解示例和其它信息,請參見18.2.3節,“HASH分區”

LENEAR關鍵詞需要一種不同的算法。在這種情況下,通過一次或多次邏輯AND運算得出的結果,計算出存儲記錄的分區的數目。要了解線形混編的討論和示例,請參見18.2.3.1節,“LINEAR HASH分區”

o        KEY(column_list):與HASH近似,除了有一點不一樣,即MySQL提供了混編函數,以保證均勻的數據分布。column_list自變量只是各列的一個清單。本示例顯示了由關鍵字進行分區的一個簡單的表,分為4個分區:

o                     CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
o                         PARTITION BY KEY(col3)
o                         PARTITIONS 4;

采用LINEAR關鍵詞,您可以對由關鍵字分區的表進行線形分區。這與由HASH進行分區的表格有同樣的效果;也就是說,使用&操作符查找分區數目,而不是使用模數(詳細說明見18.2.3.1節,“LINEAR HASH分區”18.2.4節,“KEY分區”)。本示例采用了關鍵字線形分區,用來在5個分區之間分配數據:

CREATE TABLE tk (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY LINEAR KEY(col3)
    PARTITIONS 5;

VALUES LESS THANVALUES IN子句不能和PARTITION BY KEY一起使用。

o        RANGE:在此情況下,expr使用一套VALUES LESS THAN操作符顯示了某一范圍內的值。當使用范圍分區時,您必須使用VALUES LESS THAN定義至少一個分區。VALUES IN不能和范圍分區一起使用。

VALUES LESS THAN可以與一個文字值同時使用,或者與一個可以求算單一值的表達式同時使用。

舉例說明,假設您有一個表,您希望采用以下方法對包含年份值的一列進行分區:

分區編號:

年份范圍:

0

1990以前

1

1991 - 1994

2

1995 - 1998

3

1999 - 2002

4

2003 - 2005

5

2006年以后

采用這種分區方法的表可以通過如下CREATE TABLE語句實現:

CREATE TABLE t1 (
    year_col INT, 
    some_data INT 
) 
PARTITION BY RANGE (year_col) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1995),
    PARTITION p2 VALUES LESS THAN (1999),
    PARTITION p3 VALUES LESS THAN (2002),
    PARTITION p4 VALUES LESS THAN (2006),
    PARTITION p5 VALUES LESS THAN MAXVALUE
);

PARTITION ... VALUES LESS THAN ...語句按順序執行。VALUES LESS THAN MAXVALUE的作用是指定大于最大值的“其余”的值。

注意,VALUES LESS THAN子句按順序執行,執行方式類似于switch ... case語段的一部分(許多編程語言,如C, JavaPHP也如此)。也就是說,子句必須按照這樣一種方法排列,每一個后續的VALUES LESS THAN中指定的上限值大于前一個VALUES LESS THAN中指定的上限值,并在清單的最后加一個參照性的MAXVALUE

VALUES IN與一系列的值同時使用。舉例說明,您可以創建如下的分區方法:

CREATE TABLE client_firms (
    id INT,
    name VARCHAR(35)
)
PARTITION BY RANGE (id) (
    PARTITION r0 VALUES IN (1, 5, 9, 13, 17, 21),
    PARTITION r1 VALUES IN (2, 6, 10, 14, 18, 22),
    PARTITION r2 VALUES IN (3, 7, 11, 15, 19, 23),
    PARTITION r3 VALUES IN (4, 8, 12, 16, 20, 24)
);

當前,與VALUES IN...同時使用的值必須只包含整數值。

(因為此表只使用VALUES IN表達式進行分區,您也可以用PARTITION BY LIST代替,而不是使用PARTITION BY RANGE。請參見下一條。)

在使用VALUES LESS THANVALUES IN情況下,每個分區使用PARTITION name定義,此處name是分區的標識名,后面接VALUES...子句。

o        LIST(expr):當根據含有一系列限定性值(例如州代碼或國家代碼)的列進行分區時使用。在這種情況下,所有與特定的州或國家有關的記錄都被分配到一個單一分區中,或者可以預留出一個分區,用于一系列特定的州或國家。LIST(expr)RANGE類似,除了一點以外,即只有VALUES IN可以被用于為每個分區指定值。

當使用清單分區時,您必須使用VALUES IN定義至少一個分區。VALUES LESS THAN不能與PARTITION BY LIST一起使用。

o        分區數目可以使用PARTITION num子句,自選進行指定,此處,num是分區的數目。如果本子句和其它PARTITION子句同時使用,則num必須與使用PARTITION子句說明的分區的總數相等。

注釋:不論您在創建一個由RANGELIST進行分區的表時是否使用了PARTITIONS子句,您必須在表定義中包括至少一個PARTITION VALUES(見后)。

o        一個分區可以自選分隔成多個子分區。使用自選的SUBPARTITION BY子句可以指示。子分區可以由HASHKEY進行分隔。兩種方法建立的子分區均為LINEAR。分隔子分區時的操作方式與以前描述的分區類型的操作方式一樣。(無法由LISTRANGE進行子分區分隔。)

使用SUBPARTITIONS關鍵詞,后面接一個整值,可以對子分區的數目進行指示。

·         使用一個partition_definition子句可以對每個分區分別進行定義。下面是組成這個子句的各個部分:

o        PARTITION partition_name:用于為分區指定一個邏輯名稱。

o        VALUE子句:對于范圍分區,每個分區必須包括一個VALUES LESS THAN子句;對于清單分區,您必須為每個分區指定一個VALUES IN子句。本子句用于確定哪些行將被存儲到此分區中。要了解語法示例,請參見第18章:分區中對分區類型的討論。

o        自選的COMMENT子句可以用于描述分區。注釋必須加單引號。舉例說明:

o                     COMMENT = 'Data for the years previous to 1999'

o        DATA DIRECTORYINDEX DIRECTORY可以被用于指示本分區的數據和索引各自的存儲位置的目錄。data_dirindex_dir都必須是絕對系統路徑。例如:

o                     CREATE TABLE th (id INT, name VARCHAR(30), adate DATE)
o                     PARTITION BY LIST(YEAR(adate))
o                     (
o                         PARTITION p1999 VALUES IN (1995, 1999, 2003) DATA DIRECTORY = '/var/appdata/95/data' INDEX DIRECTORY = '/var/appdata/95/idx',
o                         PARTITION p2000 VALUES IN (1996, 2000, 2004) DATA DIRECTORY = '/var/appdata/96/data' INDEX DIRECTORY = '/var/appdata/96/idx',
o                         PARTITION p2001 VALUES IN (1997, 2001, 2005) DATA DIRECTORY = '/var/appdata/97/data' INDEX DIRECTORY = '/var/appdata/97/idx',
o                         PARTITION p2000 VALUES IN (1998, 2002, 2006) DATA DIRECTORY = '/var/appdata/98/data' INDEX DIRECTORY = '/var/appdata/98/idx'
);

DATA DIRECTORYINDEX DIRECTORY的操作方法與CREATE TABLE語句中的table_option子句的操作方法一樣。此table_option子句用于位于MyISAM表管理程序下的各表。

可以為每個分區指定一個數據目錄和一個索引目錄。如果不指定,則數據和索引被存儲在默認的MySQL數據目錄中。

o        MAX_ROWSMIN_ROWS分別用于將被存儲在分區中的行數目最大值和行數目最小值。max_number_of_rowsmin_number_of_rows的值必須為正整數。和具有同樣名稱的桌面選項一樣,max_number_of_rowsmin_number_of_rows只作為對服務器的“建議”值,并不是硬性限值。

o        自選的TABLESPACE子句可以用于為分區指定一個桌面空間。僅用于MySQL Cluster

o        自選的[STORAGE] ENGINE子句可以把本分區中表的類型改為指定的類型。表的類型可以是本MySQL服務器支持的所有類型。STORAGE關鍵字和等號(=)均為自選項。如果沒有使用此選項設置分區存儲引擎,則適用于整個表的引擎可以用于此分區。

注釋:分區管理程序對于PARTITIONSUBPARTITION均接受[STORAGE] ENGINE選項。目前,此子句的使用方式僅限于對所有的分區或子分區設置同一個存儲引擎,如果試圖在同一個表內對不同的分區或子分區設置不同的存儲引擎,則會出現錯誤ERROR 1469 (HY000):在本版本的MySQL中,不允許在各分區中混用管理程序。我們打算在將來的MySQL 5.1版本中加入這種對分區的限定。

o        NODEGROUP選項可以用于使本分區可以作為節點組的一部分,節點組使用node_group_id識別。本選項僅適用于MySQL Cluster

o        分區定義可以自選地包含一個或多個subpartition_definition子句。每個這種子句至少包括SUBPARTITION name,此處,name是子分區的識別名稱。除了用SUBPARTITION代替PARTITION關鍵詞外,用于子分區定義的語法與用于分區定義的語法一樣。

子分區必須由HASHKEY完成,并且只能對RANGELIST分區進行子分區。請參見18.2.5節,“子分區”

·         分區可以修改、合并、添加到表中,或從表中刪去。要了解有關完成這些任務的MySQL命令的基本說明,請參見13.1.2節,“ALTER TABLE語法”。要了解詳細的說明和示例,請參見18.3節,“分區管理”

您可以在CREATE TABLE語句的末尾添加一個SELECT語句,在一個表的基礎上創建表。

CREATE TABLE new_tbl SELECT * FROM orig_tbl;

MySQL會對SELECT中的所有項創建新列。舉例說明:

mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
    ->        PRIMARY KEY (a), KEY(b))
    ->        TYPE=MyISAM SELECT b,c FROM test2;

本語句用于創建含三個列(a, b, c)的MyISAM表。注意,用SELECT語句創建的列附在表的右側,而不是覆蓋在表上。參考以下示例:

mysql> SELECT * FROM foo;
+---+
| n |
+---+
| 1 |
+---+
 
mysql> CREATE TABLE bar (m INT) SELECT n FROM foo;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0
 
mysql> SELECT * FROM bar;
+------+---+
| m    | n |
+------+---+
| NULL | 1 |
+------+---+
1 row in set (0.00 sec)

對應于表foo中的每一行,在表bar中插入一行,含有表foo中的值以及新列中的默認值。

在由CREATE TABLE...SELECT生成的表中,只在CREATE TABLE部分中命名的列首先出現。在兩個部分中都命名的列和只在SELECT部分中命名的列隨后出現。也可以通過指定CREATE TABLE部分中的列覆蓋SELECT列中的數據類型。

如果在把數據復制到表中時出現錯誤,則表會自動被取消,不會被創建。

CREATE TABLE...SELECT不會自動創建任何索引。索引需要專門創建,以便使語句的靈活性更強。如果您希望為已創建的表建立索引,您應在SELECT語句前指定索引。

mysql> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;

列的類型會發生部分轉化。例如,AUTO_INCREAMENT屬性不會被保留,VARCHAR列會變成CHAR列。

當使用CREATE...SELECT創建表時,在查詢時一定要對功能調用和表達式起別名。如果不起別名,則CREATE語句會出現錯誤或者生成不符合需要的列名稱。

CREATE TABLE artists_and_works
SELECT artist.name, COUNT(work.artist_id) AS number_of_works
FROM artist LEFT JOIN work ON artist.id = work.artist_id
GROUP BY artist.id;

您也可以明確地為一個已生成的列指定類型:

CREATE TABLE foo (a TINYINT NOT NULL) SELECT b+1 AS a FROM bar;

根據其它表的定義(包括在原表中定義的所有的列屬性和索引),使用LIKE創建一個空表:

CREATE TABLE new_tbl LIKE orig_tbl;

CREATE TABLE...LIKE不會復制對原表或外鍵定義指定的DATA DIRECTORYINDEX DIRECTORY表選項。

您可以在SELECT前增加IGNOREREPLACE,指示如何對復制唯一關鍵字值的記錄進行操縱。使用IGNORE后,如果新記錄復制了原有的唯一關鍵字值的記錄,則新記錄被丟棄。使用REPLACE后,新記錄替換具有相同的唯一關鍵字值的記錄。如果沒有指定IGNOREREPLACE,則出現多重唯一關鍵字值時會導致發生錯誤。

為了確保更新日志/二進位日志可以被用于再次創建原表,MySQL不允許在CREATE TABLE...SELECT過程中進行聯合插入。

13.1.5.1. 沉寂的列規格變更

在有些情況下,較早版本的MySQL會靜默地更改在CREATE TABLEALTER TABLE語句中給定的列規約。在MySQL 5.1中不會進行這類變更。如果使用指定的數據類型無法創建列,則會出現錯誤。

13.1.6.?DROP DATABASE語法

DROP {DATABASE | SCHEMA} [IF EXISTS] db_name

DROP DATABASE用于取消數據庫中的所用表格和取消數據庫。使用此語句時要非常小心!如果要使用DROP DATABASE,您需要獲得數據庫DROP權限。

IF EXISTS用于防止當數據庫不存在時發生錯誤。

也可以使用DROP SCHEMA

如果您對一個帶有符號鏈接的數據庫使用DROP DATABASE,則鏈接和原數據庫都被取消。

DROP DATABASE會返回已被取消的表的數目。此數目相當于被取消的.frm文件的數目。

在正常操作中MySQL自身會創建出一些文件和目錄。DROP DATABASE語句會從給定的數據庫目錄中取消這些文件和目錄:

·         所有帶這些擴展名的文件:

.BAK

.DAT

.HSH

 

.MRG

.MYD

.ISD

 

.MYI

.db

.frm

 

·         名稱中包含兩位16進制數00-ff的所有子目錄。這些子目錄用于RAID表。(當對RAID表的支持被取消時,在MySQL 5.0中,這些目錄不會被取消。您應該在升級到MySQL 5.0或更新的版本前轉化原有的RAID表,并人工取消這些目錄。請參見MySQL 5.0參考手冊中有關從較早版本升級到MySQL 5.0的章節。MySQL 5.0參考手冊可以從MySQL網站中獲取。)

·         db.opt文件

如果在MySQL取消了上述這些文件之后,在數據庫目錄中仍保留有其它文件和目錄,則數據庫目錄不能被取消。在這種情況下,您必須人工取消所有保留下的文件或目錄,并再次發送DROP DATABASE語句。

您還可以使用mysqladmin來取消文件。請參見8.5節,“mysqladmin:用于管理MySQL服務器的客戶端”

13.1.7.?DROP INDEX語法

DROP INDEX index_name ON tbl_name

DROP INDEX用于從表tbl_name中取消名稱為index_name的索引。本語句被映射到一個ALTER TABLE語句中,用于取消索引。請參見13.1.2節,“ALTER TABLE語法”

13.1.8.?DROP TABLE語法

DROP [TEMPORARY] TABLE [IF EXISTS]
    tbl_name [, tbl_name] ...
    [RESTRICT | CASCADE]

DROP TABLE用于取消一個或多個表。您必須有每個表的DROP權限。所有的表數據和表定義會被取消,所以使用本語句要小心!

注意,對于一個帶分區的表,DROP TABLE會永久性地取消表定義,取消各分區,并取消儲存在這些分區中的所有數據。DROP TABLE還會取消與被取消的表有關聯的分區定義(.par)文件。

對與不存在的表,使用IF EXISTS用于防止錯誤發生。當使用IF EXISTS時,對于每個不存在的表,會生成一個NOTE。請參見13.5.4.22節,“SHOW WARNINGS語法”

RESTRICTCASCADE可以使分區更容易。目前,RESTRICTCASCADE不起作用。

注釋:除非您使用TEMPORARY關鍵詞,DROP TABLE會自動提交當前的有效的事務。

TEMPORARY關鍵詞具有以下作用:

·         語句只取消TEMPORARY表。

·         語句不會終止正在進行中的事務。

·         不會查驗存取權。(TEMPORARY表僅對于創建該表的客戶端是可見的,所以查驗是不必要的。)

使用TEMPORARY是確保您不會意外取消一個非TEMPORARY表的良好方法。

13.1.9.?RENAME TABLE語法

RENAME TABLE tbl_name TO new_tbl_name
    [, tbl_name2 TO new_tbl_name2] ...

本語句用于對一個或多個表進行重命名。

重命名操作自動進行,這意味著當重命名正在運行時,其它線程不能讀取任何表。例如,如果您有一個原有的表old_table,您可以創建另一個具有相同結構的空表new_table,然后用此空表替換原有的表:

CREATE TABLE new_table (...);
RENAME TABLE old_table TO backup_table, new_table TO old_table;

如果此語句用于對多個表進行重命名,則重命名操作從左至右進行。如果您想要交換兩個表的名稱,您可以這樣做(假設不存在名稱為tmp_table的表):

RENAME TABLE old_table TO tmp_table,
             new_table TO old_table,
             tmp_table TO new_table;

只要兩個數據庫位于同一文件系統中,您還可以對表進行重命名,把表從一個數據庫中移動到另一個數據庫中:

RENAME TABLE current_db.tbl_name TO other_db.tbl_name;

當您執行RENAME時,您不能有被鎖定的表,也不能有處于活性狀態的事務。您還必須擁有原表的ALTERDROP權限,以及新表的CREATEINSERT權限。

如果MySQL對多個表進行重命名時遇到了錯誤,MySQL會對所有已被重命名的表進行反向重命名,返回到原來的狀態。

只要您不嘗試通過重命名把視圖加入另一個數據庫中,則RENAME TABLE也可以用于視圖。

13.2. 數據操作語句

13.2.1.?DELETE語法

單表語法:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
    [WHERE where_definition]
    [ORDER BY ...]
    [LIMIT row_count]

多表語法:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    tbl_name[.*] [, tbl_name[.*] ...]
    FROM table_references
    [WHERE where_definition]

或:

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[.*] [, tbl_name[.*] ...]
    USING table_references
    [WHERE where_definition]

tbl_name中有些行滿足由where_definition給定的條件。DELETE用于刪除這些行,并返回被刪除的記錄的數目。

如果您編寫的DELETE語句中沒有WHERE子句,則所有的行都被刪除。當您不想知道被刪除的行的數目時,有一個更快的方法,即使用TRUNCATE TABLE。請參見13.2.9節,“TRUNCATE語法”

如果您刪除的行中包括用于AUTO_INCREMENT列的最大值,則該值被重新用于BDB表,但是不會被用于MyISAM表或InnoDB表。如果您在AUTOCOMMIT模式下使用DELETE FROM tbl_name(不含WHERE子句)刪除表中的所有行,則對于所有的表類型(除InnoDBMyISAM外),序列重新編排。對于InnoDB表,此項操作有一些例外,在15.2.6.3節,“AUTO_INCREMENT列如何在InnoDB中運行”中進行了討論。

對于MyISAMBDB表,您可以把AUTO_INCREMENT次級列指定到一個多列關鍵字中。在這種情況下,從序列的頂端被刪除的值被再次使用,甚至對于MyISAM表也如此。請參見3.6.9節,“使用AUTO_INCREMENT”

DELETE語句支持以下修飾符:

·         如果您指定LOW_PRIORITY,則DELETE的執行被延遲,直到沒有其它客戶端讀取本表時再執行。

·         對于MyISAM表,如果您使用QUICK關鍵詞,則在刪除過程中,存儲引擎不會合并索引端結點,這樣可以加快部分種類的刪除操作的速度。

·         在刪除行的過程中,IGNORE關鍵詞會使MySQL忽略所有的錯誤。(在分析階段遇到的錯誤會以常規方式處理。)由于使用本選項而被忽略的錯誤會作為警告返回。

刪除操作的速度會受到一些因素的影響,這些因素在7.2.18節,“DELETE語句的速度”中進行了討論。

MyISAM表中,被刪除的記錄被保留在一個帶鏈接的清單中,后續的INSERT操作會重新使用舊的記錄位置。要重新使用未使用的空間并減小文件的尺寸,則使用OPTIMIZE TABLE語句或myisamchk應用程序重新編排表。OPTIMIZE TABLE更簡便,但是myisamchk速度更快。請參見13.5.2.5節,“OPTIMIZE TABLE語法”第7章:優化

QUICK修飾符會影響到在刪除操作中索引端結點是否合并。當用于被刪除的行的索引值被來自后插入的行的相近的索引值代替時,DELETE QUICK最為適用。在此情況下,被刪除的值留下來的空穴被重新使用。

未充滿的索引塊跨越某一個范圍的索引值,會再次發生新的插入。當被刪除的值導致出現未充滿的索引塊時,DELETE QUICK沒有作用。在此情況下,使用QUICK會導致未利用的索引中出現廢棄空間。下面是此種情況的舉例說明:

1.    創建一個表,表中包含已編索引的AUTO_INCREMENT列。

2.    在表中插入很多記錄。每次插入會產生一個索引值,此索引值被添加到索引的高端處。

3.    使用DELETE QUICK從列的低端處刪除一組記錄。

在此情況下,與被刪除的索引值相關的索引塊變成未充滿的狀態,但是,由于使用了QUICK,這些索引塊不會與其它索引塊合并。當插入新值時,這些索引塊仍為未充滿的狀態,原因是新記錄不含有在被刪除的范圍內的索引值。另外,即使您此后使用DELETE時不包含QUICK,這些索引塊也仍是未充滿的,除非被刪除的索引值中有一部分碰巧位于這些未充滿的塊的之中,或與這些塊相鄰。在這些情況下,如果要重新利用未使用的索引空間,需使用OPTIMIZE TABLE

如果您打算從一個表中刪除許多行,使用DELETE QUICK再加上OPTIMIZE TABLE可以加快速度。這樣做可以重新建立索引,而不是進行大量的索引塊合并操作。

用于DELETEMySQL唯一的LIMIT row_count選項用于告知服務器在控制命令被返回到客戶端前被刪除的行的最大值。本選項用于確保一個DELETE語句不會占用過多的時間。您可以只重復DELETE語句,直到相關行的數目少于LIMIT值為止。

如果DELETE語句包括一個ORDER BY子句,則各行按照子句中指定的順序進行刪除。此子句只在與LIMIT聯用是才起作用。例如,以下子句用于查找與WHERE子句對應的行,使用timestamp_column進行分類,并刪除第一(最舊的)行:

DELETE FROM somelog
WHERE user = 'jcole'
ORDER BY timestamp_column
LIMIT 1;

您可以在一個DELETE語句中指定多個表,根據多個表中的特定條件,從一個表或多個表中刪除行。不過,您不能在一個多表DELETE語句中使用ORDER BYLIMIT

table_references部分列出了包含在聯合中的表。此語法在13.2.7.1節,“JOIN語法”中進行了說明。

對于第一個語法,只刪除列于FROM子句之前的表中的對應的行。對于第二個語法,只刪除列于FROM子句之中(在USING子句之前)的表中的對應的行。作用是,您可以同時刪除許多個表中的行,并使用其它的表進行搜索:

DELETE t1, t2 FROM t1, t2, t3 WHERE t1.id=t2.id AND t2.id=t3.id;

或:

DELETE FROM t1, t2 USING t1, t2, t3 WHERE t1.id=t2.id AND t2.id=t3.id;

當搜索待刪除的行時,這些語句使用所有三個表,但是只從表t1和表t2中刪除對應的行。

以上例子顯示了使用逗號操作符的內部聯合,但是多表DELETE語句可以使用SELECT語句中允許的所有類型的聯合,比如LEFT JOIN

本語法允許在名稱后面加.*,以便與Access相容。

如果您使用的多表DELETE語句包括InnoDB表,并且這些表受外鍵的限制,則MySQL優化程序會對表進行處理,改變原來的從屬關系。在這種情況下,該語句出現錯誤并返回到前面的步驟。要避免此錯誤,您應該從單一表中刪除,并依靠InnoDB提供的ON DELETE功能,對其它表進行相應的修改。

注釋:當引用表名稱時,您必須使用別名(如果已給定):

DELETE t1 FROM test AS t1, test2 WHERE ...

進行多表刪除時支持跨數據庫刪除,但是在此情況下,您在引用表時不能使用別名。舉例說明:

DELETE test1.tmp1, test2.tmp2 FROM test1.tmp1, test2.tmp2 WHERE ...

目前,您不能從一個表中刪除,同時又在子查詢中從同一個表中選擇。

13.2.2.?DO語法

DO expr [, expr] ...
DO用于執行表達式,但是不返回任何結果。DOSELECT expr的簡化表達方式DO有一個優勢,就是如果您不太關心結果的話,DO的速度稍快。

DO主要用于執行有副作用的函數,比如RELEASE_LOCK()

13.2.3.?HANDLER語法

HANDLER tbl_name OPEN [ AS alias ]
HANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...)
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE

HANDLER語句提供通往表存儲引擎接口的直接通道。HANDLER可以用于MyISAMInnoDB表。

HANDLER...OPEN語句用于打開一個表,通過后續的HANDLER...READ語句建立讀取表的通道。本表目標不會被其它線程共享,也不會關閉,直到線程調用HANDLER...CLOSE或線程中止時為止。如果您使用一個別名打開表,則使用其它HANDLER語句進一步參閱表是必須使用此別名,而不能使用表名。

如果被指定的索引滿足給定的值并且符合了WHERE條件,則第一個HANDLER...READ語法取出一行。如果您有一個多列索引,則指定索引列值為一個用逗號隔開的清單。既可以為索引中的所有列指定值,也可以為索引列的最左邊的前綴指定值。假設一個索引包括三個列,名稱為col_a, col_b,col_c,并按此順序排列。HANDLER語句可以為索引中的所有三個列指定值,或者為一個最左邊前綴中的各列指定值。舉例說明:

HANDLER ... index_name = (col_a_val,col_b_val,col_c_val) ...
HANDLER ... index_name = (col_a_val,col_b_val) ...
HANDLER ... index_name = (col_a_val) ...

第二個HANDLER...READ語法按索引的順序從表中取出一行。索引的順序符合WHERE條件。

第三個HANDLER...READ語法按自然行的順序從表中取出一行。自然行的順序符合WHERE條件。當想要對整個表進行掃描時,此語句比HANDLER tbl_name READ index_name更快。自然行的順序指的是行存儲在MyISAM表數據文件的順序。本語句也適用于InnoDB表,但是因為沒有獨立的數據文件,所以沒有這類概念。

不使用LIMIT子句時,所有形式的HANDLER...READ語句均只取出一行。 如果要返回多個行,應加入一個LIMIT子句。本語句于SELECT語句的語法一樣。請參見13.2.7節,“SELECT語法”

HANDLER...CLOSE用于關閉使用HANDLER...OPEN打開的表。

注釋:要使用HANDLER接口來查閱一個表的PRIMARY KEY,應使用帶引號的識別符`PRIMARY`

HANDLER tbl_name READ `PRIMARY` > (...);

HANDLER是比較低級別的語句。例如,它不能提供一致性。也就是說,HANDLER...OPEN不能為表做快照,也不能鎖定表。這意味著,當一個HANDLER...OPEN語句被編寫后,表數據可以被更改(用此線程或用其它線程),并且這些更改只會部分地出現在HANDLER...NEXTHANDLER...PREV掃描中。

使用HANDLER接口代替常規的SELECT語句有多個原因:

·         HANDLERSELECT更快:

o        一個指定的存儲引擎管理程序目標為了HANDLER...OPEN進行整序。該目標被重新用于該表的后續的HANDLER語句;不需要對每個語句進行重新初始化。

o        涉及的分析較少。

o        沒有優化程序或查詢校驗開銷。

o        在兩個管理程序請求之間,不需要鎖定表。

o        管理程序接口不需要提供外觀一致的數據(例如,允許無條理的讀取),所以存儲引擎可以使用優化,而SELECT通常不允許使用優化。

·         有些應用程序使用與ISAM近似的接口與MySQL連接。使用HANDLER可以更容易地與這些應用程序連接。

·         HANDLER允許您采用一種特殊的方式進出數據庫。而使用SELECT時難以采用(或不可能采用)這種方式。有些應用程序可以提供一個交互式的用戶接口與數據庫連接。當與這些應用程序同時使用時,用HANDLER接口觀看數據更加自然。

13.2.4.?INSERT語法

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    VALUES ({expr | DEFAULT},...),(...),...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

或:

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

或:

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

INSERT用于向一個已有的表中插入新行。INSERT...VALUESINSERT...SET形式的語句根據明確指定的值插入行。INSERT...SELECT形式的語句插入從其它表中選出的行。在13.2.4.1節,“INSERT ... SELECT語法”中對INSERT...SELECT進行了進一步的討論。

行應被插入到tbl_name表中。可以按以下方法指定列。本語句向這些列提供值。

·         列名稱清單或SET子句明確的指示了列。

·         如果您不為INSERT...VALUESINSERT...SELECT指定列的清單,則表中每列的值必須在VALUES清單中提供,或由SELECT提供。如果您不知道表中各列的順序,則使用DESCRIBE tbl_name查詢。

列值可以采用多種方法給定:

·         如果不是在嚴格模式下運行,則所有沒有明確給定值的列都被設置為默認值(明確的或隱含的)。例如,如果您指定了一個列清單,但此清單沒有對表中所有的列進行命名,則未命名的各列被設置為默認值。默認值的賦值在13.1.5節,“CREATE TABLE語法”中進行了說明。也可參見1.8.6.2節,“對無效數據的約束”

有時候,您需要對所有沒有默認值的列明確地指定值。如果您希望,在沒有明確指定值時,INSERT語句可以生成錯誤信息,則您應該使用STRICT模式。請參見5.3.2節,“SQL服務器模式”

·         使用關鍵詞DEFAULT,明確地把列設置為默認值。這樣,編寫向所有列賦值的INSERT語句時可以更容易,因為使用DEFAULT可以避免編寫出不完整的、未包含全部列值的VALUES清單。如果不使用DEFUALT,您必須編寫一個列名稱清單,與VALUES清單中的每個值對應。

您還可以使用DEFAULT(col_name)作為一種更通用的形式,在表達式中使用,用于生成一個列的默認值。

·         如果列清單和VALUES清單均為空清單,則INSERT會創建一個行,每個列都被設置為默認值:

·                mysql> INSERT INTO tbl_name () VALUES();

STRICT模式中,如果有一列沒有默認值,則會出現錯誤。或者,MySQL會對所有沒有明確定義默認值的列使用隱含的默認值。

·         您可以指定一個表達式expr來提供一個列值。如果表達式的類型與列值不匹配,這樣做會造成類型轉化。并且,給定值的轉化會導致不同的插入值,插入何值由列類型而定。例如,向一個INT, FLOAT, DECIMAL(10,6)YEAR列插入字符串'1999.0e-2',插入值分別是199919.992119.9921001999。存儲在INTYEAR列中的值為1999的原因是,在從字符串到整數的轉化中,只把字符串的前面部分看作有效的整數或年份。對于浮點列和固定點列,在從字符串到浮點的轉化中,把整個字符串均看作有效的浮點值。

表達式expr可以引用在值清單中已設置的所有列。例如,您可以這么操作,因為用于col2的值引用了col1,而col1已經被賦值:

mysql> INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);

但是以下語句不合法,因為用于col1的值引用了col2,而col2col1之后被賦值:

mysql> INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);

有一種例外情況,那就是含有AUTO_INCREMENT值的列。因為AUTO_INCREMENT值在其它值賦值之后被生成,所以任何在賦值時對AUTO_INCREMENT列的引用都會返回0

INSERT語句支持下列修改符:

·         如果您使用DELAYED關鍵字,則服務器會把待插入的行放到一個緩沖器中,而發送INSERT DELAYED語句的客戶端會繼續運行。如果表正在被使用,則服務器會保留這些行。當表空閑時,服務器開始插入行,并定期檢查是否有新的讀取請求。如果有新的讀取請求,則被延遲的行被延緩執行,直到表再次空閑時為止。請參見13.2.4.2節,“INSERT DELAYED語法”

·         如果您使用LOW_PRIORITY關鍵詞,則INSERT的執行被延遲,直到沒有其它客戶端從表中讀取為止。當原有客戶端正在讀取時,有些客戶端剛開始讀取。這些客戶端也被包括在內。此時,INSERT LOW_PRIORITY語句等候。因此,在讀取量很大的情況下,發出INSERT LOW_PRIORITY語句的客戶端有可能需要等待很長一段時間(甚至是永遠等待下去)。(這與INSERT DELAYED形成對比,INSERT DELAYED立刻讓客戶端繼續執行。請參見13.2.4.2節,“INSERT DELAYED語法”。)注意LOW_PRIORITY通常不應用于MyISAM表,因為這么做會取消同時進行的插入。請參見15.1節,“MyISAM存儲引擎”

·         如果您指定了HIGH_PRIORITY,同時服務器采用--low-priority-updates選項啟動,則HIGH_PRIORITY將覆蓋--low-priority-updates選項。這么做還會導致同時進行的插入被取消。

·         使用mysql_affected_rows() C API函數,可以獲得用于INSERT的受影響行的值。請參見25.2.3.1節,“mysql_affected_rows()”

·         如果您在一個INSERT語句中使用IGNORE關鍵詞,在執行語句時出現的錯誤被當作警告處理。例如,沒有使用IGNORE時,如果一個行復制了原有的UNIQUE索引或PRIMARY KEY值,會導致出現重復關鍵字錯誤,語句執行失敗。使用IGNORE時,該行仍然未被插入,但是不會出現錯誤。IGNORE未被指定時,如果數據轉化引發錯誤,則會使語句執行失敗。使用IGNORE后,無效數據被調整到最接近的值,并被插入;此時,生成警告,但是語句執行不會失敗。您可以使用mysql_info() C API函數測定有多少行被插入到表中。

如果您指定了ON DUPLICATE KEY UPDATE,并且插入行后會導致在一個UNIQUE索引或PRIMARY KEY中出現重復值,則執行舊行UPDATE。例如,如果列a被定義為UNIQUE,并且包含值1,則以下兩個語句具有相同的效果:

mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
    -> ON DUPLICATE KEY UPDATE c=c+1;
 
mysql> UPDATE table SET c=c+1 WHERE a=1;

如果行作為新記錄被插入,則受影響行的值為1;如果原有的記錄被更新,則受影響行的值為2

注釋:如果列b也是唯一列,則INSERT與此UPDATE語句相當:

mysql> UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

如果a=1 OR b=2與多個行向匹配,則只有一個行被更新。通常,您應該盡量避免對帶有多個唯一關鍵字的表使用ON DUPLICATE KEY子句。

您可以在UPDATE子句中使用VALUES(col_name)函數從INSERT...UPDATE語句的INSERT部分引用列值。換句話說,如果沒有發生重復關鍵字沖突,則UPDATE子句中的VALUES(col_name)可以引用被插入的col_name的值。本函數特別適用于多行插入。VALUES()函數只在INSERT...UPDATE語句中有意義,其它時候會返回NULL

示例:

mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
    -> ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

本語句與以下兩個語句作用相同:

mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
    -> ON DUPLICATE KEY UPDATE c=3;
mysql> INSERT INTO table (a,b,c) VALUES (4,5,6)
    -> ON DUPLICATE KEY UPDATE c=9;

當您使用ON DUPLICATE KEY UPDATE時,DELAYED選項被忽略。

您可以使用SQL LAST_INSERT_ID()函數查找用于AUTO_INCREMENT列的值。從C API的內部,使用mysql_insert_id()函數。不過,您應該注意,兩個函數的作用并不總是相同的。在12.9.3節,“信息函數”25.2.3.36節,“mysql_insert_id()”中進一步討論了與AUTO_INCREMENT列有關的INSERT語句的作用。

如果您使用INSERT...VALUES語句時采用了多個值清單或INSERT...SELECT,則該語句按以下格式返回一個信息字符串:

Records: 100 Duplicates: 0 Warnings: 0

記錄指示了經過語句處理的行的數目。(因為重復數目可以不是零,所以該數目不一定是實際被插入的行的數目。)重復數目指的是不能被插入的行的數目,因為這些行會復制部分原有的唯一索引值。警告指的是插入有錯誤或有問題的列值的次數。在以下情況下會出現警告:

·         向一個已定義為NOT NULL的列中插入NULL。對于一個多行INSERT語句或INSERT INTO...SELECT語句,根據列數據的類型,列被設置為隱含的默認值。對于數字類型,默認值為0;對于字符串類型,默認值為空字符串('');對于日期和時間類型,默認值為“zero”值。對INSERT INTO...SELECT語句的處理方法與對多行插入的處理方法一樣,因為服務器不能檢測來自SELECT的結果,不能判斷是否返回單一行。(對于單一行INSERT,當NULL被插入一個NOT NULL列時,不會出現警告,而是出現錯誤,并且語句運行失敗。)

·         數字列的值被設置在列的值范圍之外。此值被修改為未最接近的值范圍端點。

·         向一個數字列賦予一個例如'10.34 a'的值。尾部的非數字文本被刪節,其余的數字部分被插入,如果字符串值沒有前導的數字部分,則該列被設置為0

·         向一個字符串列(CHAR, VARCHAR, TEXTBLOB)中插入的字符串超過了列的最大長度。此值被刪節到列的最大長度。

·         向日期或時間列中插入的值對于該列的類型是不合法的。根據列的類型,該列被設置到相應的零值。

如果您正在使用C API,則可以通過調用mysql_info()函數獲取信息字符串。請參見25.2.3.34節,“mysql_info()”

13.2.4.1.?INSERT ... SELECT語法

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

使用INSERT...SELECT,您可以快速地從一個或多個表中向一個表中插入多個行。

示例:

INSERT INTO tbl_temp2 (fld_id)
    SELECT tbl_temp1.fld_order_id
    FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

使用INSERT...SELECT語句時會出現以下情況:

·         明確地指定IGNORE,用于忽略會導致重復關鍵字錯誤的記錄。

·         不要同時使用DELAYEDINSERT...SELECT

·         INSERT語句的目標表會顯示在查詢的SELECT部分的FROM子句中。(在有些舊版本的MySQL中不會出現這種情況。)

·         AUTO_INCREMENT列照常運行。

·         為了確保二進制日志可以被用于再次創建原表,MySQL不允許在INSERT...SELECT運行期間同時進行插入操作。

·         目前,您不能在向一個表插入的同時,又在一個子查詢中從同一個表中選擇。

ON DUPLICATE KEY UPDATE的值部分中,只要您不使用SELECT部分中的GROUP BY,您就可以引用在其它表中的列。有一個副作用是,您必須使值部分中的非唯一列的名稱符合要求。

您可以使用REPLACE替代INSERT,來覆蓋舊行。對于包含唯一關鍵字值,并復制了舊行的新行,在進行處理時,REPLACE可以作為INSERT IGNORE的同類子句:新行被用于替換舊行,而不是被丟棄。

13.2.4.2.?INSERT DELAYED語法

INSERT DELAYED ...

用于INSERT語句的DELAYED選項是MySQL相對于標準SQL的擴展。如果您的客戶端不能等待INSERT完成,則這個選項是非常有用的。當您使用MySQL進行日志編寫時,這是非常常見的問題。您也可以定期運行SELECTUPDATE語句,這些語句花費的時間較長。

當一個客戶端使用INSERT DELAYED時,會立刻從服務器處得到一個確定。并且行被排入隊列,當表沒有被其它線程使用時,此行被插入。

使用INSERT DELAYED的另一個重要的好處是,來自許多客戶端的插入被集中在一起,并被編寫入一個塊。這比執行許多獨立的插入要快很多。

使用DELAYED時有一些限制:

·         INSERT DELAYED僅適用于MyISAM, MEMORYARCHIVE表。對于MyISAM表,如果在數據文件的中間沒有空閑的塊,則支持同時采用SELECTINSERT語句。在這些情況下,基本不需要對MyISAM使用INSERT DELAYED。請參見15.1節,“MyISAM存儲引擎”, 15.4節,“MEMORY (HEAP)存儲引擎”15.8節,“ARCHIVE存儲引擎”

·         INSERT DELAYED應該僅用于指定值清單的INSERT語句。服務器忽略用于INSERT DELAYED...SELECT語句的DELAYED

·         服務器忽略用于INSERT DELAYED...ON DUPLICATE UPDATE語句的DELAYED

·         因為在行被插入前,語句立刻返回,所以您不能使用LAST_INSERT_ID()來獲取AUTO_INCREMENT值。AUTO_INCREMENT值可能由語句生成。

·         對于SELECT語句,DELAYED行不可見,直到這些行確實被插入了為止。

·         DELAYED在從屬復制服務器中被忽略了,因為DELAYED不會在從屬服務器中產生與主服務器不一樣的數據。

注意,目前在隊列中的各行只保存在存儲器中,直到它們被插入到表中為止。這意味著,如果您強行中止了mysqld(例如,使用kill -9)或者如果mysqld意外停止,則所有沒有被寫入磁盤的行都會丟失。

以下詳細描述了當您對INSERTREPLACE使用DELAYED選項時會發生什么情況。在這些描述中,“線程”指的是已接受了一個INSERT DELAYED語句的線程,“管理程序”指的是為某個特定的表處理所有INSERT DELAYED語句的線程。

·         當一個線程對一個表執行DELAYED語句時,會創建出一個管理程序線程(如果原來不存在),對用于本表的所有DELAYED語句進行處理。

·         線程會檢查是否管理程序以前已獲取了DELAYED鎖定;如果沒有獲取,則告知管理程序線程進行此項操作。即使其它線程對表有READWRITE鎖定,也可以獲得DELAYED鎖定。但是管理程序會等待所有的ALTER TABLE鎖定或FLUSH TABLE鎖定,以確保表的結構是最新的。

·         線程執行INSERT語句,但不是把行寫入表中,而是把最終行的拷貝放入一個由管理程序線程管理的隊列中。線程會提示出現語法錯誤,這些錯誤會被報告到客戶端中。

·         因為在插入操作之前,INSERT返回已經完成,所以客戶端不能從服務器處獲取重復記錄的數目,也不能獲取生成的行的AUTO_INCREMENT值。(如果您使用C API,則出于同樣的原因,mysql_info()函數不會返回任何有意義的東西。)

·         當行被插入表中時,二進制日志被管理程序線程更新。在多行插入情況下,當第一行被插入時,二進制日志被更新。

·         每次delayed_insert_limit行被編寫時,管理程序會檢查是否有SELECT語句仍然未執行。如果有,則會在繼續運行前,讓這些語句先執行。

·         當管理程序的隊列中沒有多余的行時,表被解鎖。如果在delayed_insert_timeout時間內,沒有接收到新的INSERT DELAYED語句,則管理程序中止。

·         如果在某個特定的管理程序隊列中,有超過delayed_queue_size的行未被執行,則申請INSERT DELAYED的線程會等待,直到隊列中出現空間為止。這么做可以確保mysqld不會把所有的存儲器都用于被延遲的存儲隊列。

·         管理程序線程會顯示在MySQL進程清單中,其命令列中包含delayed_insert。如果您執行一個FLUSH TABLES語句或使用KILL thread_id進行刪除,則會刪除此線程。不過,在退出前,線程會首先把所有排入隊列的行存儲到表中。在這期間,該線程不會從其它線程處接受任何新的INSERT語句。如果您在此之后執行一個INSERT DELAYED語句,則會創建出一個新的管理程序線程。

注意,如果有一個INSERT DELAYED管理程序正在運行,則這意味著INSERT DELAYED語句比常規的INSERT語句具有更高的優先權。其它更新語句必須等待,直到INSERT DELAYED語句隊列都運行完畢,或者管理程序線程被中止(使用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

13.2.5.?LOAD DATA INFILE語法

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name.txt'
    [REPLACE | IGNORE]
    INTO TABLE tbl_name
    [FIELDS
        [TERMINATED BY 'string']
        [[OPTIONALLY] ENCLOSED BY 'char']
        [ESCAPED BY 'char' ]
    ]
    [LINES
        [STARTING BY 'string']
        [TERMINATED BY 'string']
    ]
    [IGNORE number LINES]
    [(col_name_or_user_var,...)]
    [SET col_name = expr,...)]

LOAD DATA INFILE語句用于高速地從一個文本文件中讀取行,并裝入一個表中。文件名稱必須為一個文字字符串。

要了解有關INSERTLOAD DATA INFILE的效率的對比和有關LOAD DATA INFILE加速的更多信息,請參見7.2.16節,“INSERT語句的速度”

character_set_database系統變量指示的字符集被用于解釋文件中的信息。SET NAMEScharacter_set_client的設置不會影響對輸入的解釋。

注意,目前不能載入UCS2數據文件。

您也可以通過使用mysqlimport應用程序載入數據文件;通過向服務器發送一個LOAD DATA INFILE語句實現此功能。--local選項用于使mysqlimport從客戶主機中讀取數據文件。如果客戶端和服務器支持壓縮協議,則您可以指定—compress選項提高在慢速網絡中的性能。請參見8.10節,“mysqlimport:數據導入程序

如果您使用LOW_PRIORITY,則LOAD DATA語句的執行被延遲,直到沒有其它的客戶端從表中讀取為止。

如果一個MyISAM表滿足同時插入的條件(即該表在中間有空閑塊),并且您對這個MyISAM表指定了CONCURRENT,則當LOAD DATA正在執行時,其它線程會從表中重新獲取數據。即使沒有其它線程在同時使用本表格,使用本選項也會略微影響LOAD DATA的性能。

如果指定了LOCAL,則被認為與連接的客戶端有關:

·         如果指定了LOCAL,則文件會被客戶主機上的客戶端讀取,并被發送到服務器。文件會被給予一個完整的路徑名稱,以指定確切的位置。如果給定的是一個相對的路徑名稱,則此名稱會被理解為相對于啟動客戶端時所在的目錄。

·         如果LOCAL沒有被指定,則文件必須位于服務器主機上,并且被服務器直接讀取。

當在服務器主機上為文件定位時,服務器使用以下規則:

·         如果給定了一個絕對的路徑名稱,則服務器使用此路徑名稱。

·         如果給定了帶有一個或多個引導組件的相對路徑名稱,則服務器會搜索相對于服務器數據目錄的文件。

·         如果給定了一個不帶引導組件的文件名稱,則服務器會在默認數據庫的數據庫目錄中尋找文件。

注意,這些規則意味著名為./myfile.txt的文件會從服務器數據目錄中被讀取,而名為myfile.txt的同樣的文件會從默認數據庫的數據庫目錄中讀取。例如,下面的LOAD DATA語句會從db1數據庫目錄中讀取文件data.txt,因為db1是當前數據庫。即使語句明確把文件載入到db2數據庫中的表里,也會從db1目錄中讀取。

mysql> USE db1;
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;

注意,使用正斜杠指定Windows路徑名稱,而不是使用反斜杠。如果您使用反斜杠,您必須使用兩個。

出于安全原因,當讀取位于服務器中的文本文件時,文件必須位于數據庫目錄中,或者是全體可讀的。另外,要對服務器文件使用LOAD DATA INFILE,您必須擁有FILE權限。

5.7.3節,“MySQL提供的權限”

與讓服務器直接讀取文件相比,使用LOCAL速度略慢,這是因為文件的內容必須通過客戶端發送到服務器上。不過,您不需要FILE權限來載入本地文件。

只有當您的服務器和您的客戶端都許可時,LOCAL才可運行。例如,如果使用—local-infile=0啟動mysqld,則LOCAL不運行。請參見5.6.4節,“LOAD DATA LOCAL安全問題

如果您需要LOAD DATA來從一個管道中讀取,您可以使用以下方法(此處我們把/目錄清單載入一個表格):

mkfifo /mysql/db/x/x
chmod 666 /mysql/db/x/x
find / -ls > /mysql/db/x/x
mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x

有些輸入記錄把原有的記錄復制到唯一關鍵字值上。REPLACEIGNORE關鍵字用于控制這些輸入記錄的操作。

如果您指定了REPLACE,則輸入行會替換原有行(換句話說,與原有行一樣,對一個主索引或唯一索引具有相同值的行)。請參見13.2.6節,“REPLACE語法”

如果您指定IGNORE,則把原有行復制到唯一關鍵字值的輸入行被跳過。如果您這兩個選項都不指定,則運行情況根據LOCAL關鍵詞是否被指定而定。不使用LOCAL時,當出現重復關鍵字值時,會發生錯誤,并且剩下的文本文件被忽略。使用LOCAL時,默認的運行情況和IGNORE被指定時的情況相同;這是因為在運行中間,服務器沒有辦法中止文件的傳輸。

如果您希望在載入運行過程中忽略外鍵的限制,您可以在執行LOAD DATA前發送一個SET FOREIGN_KEY_CHECKS=0語句。

如果您對一個空的MyISAM表使用LOAD DATA INFILE,則所有的非唯一索引會被創建在一個獨立批中(對于REPAIR TABLE)。當您有許多索引時,這通常會使LOAD DATA INFILE大大加快。通常,LOAD DATA INFILE的速度會非常快,但是在某些極端情況下,您可以在把文件載入到表中之前使用ALTER TABLE...DISABLE KEYS關閉LOAD DATA INFILE,或者在載入文件之后使用ALTER TABLE...ENABLE KEYS再次創建索引,使創建索引的速度更快。請參見7.2.16節,“INSERT語句的速度”

LOAD DATA INFILESELECT...INTO OUTFILE的補語。(見13.2.7節,“SELECT語法”。)要從一個表中把數據寫入一個文件中,應使用SELECT...INTO OUTFILE。要讀取文件,放回到表中,應使用LOAD DATA INFILEFIELDSLINES子句的語法對于兩個語句是一樣的。兩個子句都是自選的,但是如果兩個都被指定了,FIELDS必須位于LINES的前面。

如果您指定了一個FIELDS子句,則每個亞子句(TERMINATED BY, [OPTIONALLY] ENCLOSED BYESCAPED BY)也是自選的。不過,您必須指定其中至少一個。

如果您不指定FIELDS子句,則默認值為假設您寫下如下語句時的值:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'

如果您不指定LINES子句,則默認值為假設您寫下如下語句時的值:

LINES TERMINATED BY '\n' STARTING BY ''

換句話說,當讀取輸入值時,默認值會使LOAD DATA INFILE按如下方式運行:

·         在新行處尋找行的邊界。

·         不會跳過任何行前綴。

·         在制表符處把行分解為字段。

·         不希望字段被包含在任何引號字符之中。

·         出現制表符、新行、或在‘\’前有‘\’時,理解為作為字段值一部分的文字字符。

相反的,當編寫輸出值時,默認值會使SELECT...INTO OUTFILE按如下方式運行:

·         在字段之間寫入制表符。

·         不把字段包含在任何引號字符中。

·         當字段值中出現制表符、新行或‘\’時,使用‘\’進行轉義。

·         在行的末端寫入新行。

注意,要寫入FIELDS ESCAPED BY \\’,您必須為待讀取的值指定兩個反斜杠,作為一個單反斜杠使用。

注釋:如果您已經在Windows系統中生成了文本文件,您可能必須使用LINES TERMINATED BY \r\n’來正確地讀取文件,因為Windows程序通常使用兩個字符作為一個行終止符。部分程序,比如WordPad,當編寫文件時,可能會使用\r作為行終止符。要讀取這樣的文件,應使用LINES TERMINATED BY \r’。

如果所有您希望讀入的行都含有一個您希望忽略的共用前綴,則您可以使用'prefix_string'來跳過前綴(和前綴前的字符)。如果某行不包括前綴,則整個行被跳過。注釋:prefix_string會出現在一行的中間。

示例:

mysql> LOAD DATA INFILE '/tmp/test.txt'
    -> INTO TABLE test LINES STARTING BY "xxx";

使用此語句,您可以讀入包含有如下內容的文件:

xxx"row",1
something xxx"row",2

并只得到數據("row",1)("row",2)

IGNORE number LINES選項可以被用于在文件的開始處忽略行。例如,您可以使用IGNORE 1 LINES來跳過一個包含列名稱的起始標題行:

mysql> LOAD DATA INFILE '/tmp/test.txt'
    -> INTO TABLE test IGNORE 1 LINES;

當您聯合使用SELECT...INTO OUTFILELOAD DATA INFILE來從一個數據庫中把數據寫入一個文件中,然后再讀取文件,返回到數據庫中時,用于兩個語句的field-line-handling選項必須匹配。否則,LOAD DATA INFILE不會正確地理解文件的內容。假設您使用SELECT...INTO OUTFILE來編寫一個的文件,字段由逗號分隔:

mysql> SELECT * INTO OUTFILE 'data.txt'
    ->          FIELDS TERMINATED BY ','
    ->          FROM table2;

要讀取由逗號分隔的文件并返回,則正確的語句應該是:

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格式的文件具有以逗號分隔并且包含在雙引號中的字段。如果文件中的各行以新行為結尾,則此處所示的語句描述了您可以用于載入文件的field-line-handling選項:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
    ->           FIELDS TERMINATED BY ',' ENCLOSED BY '"'
    ->           LINES TERMINATED BY '\n';

所有field-line-handling選項都可以指定一個空字符串('')。如果字符串不是空的,則FIELDS [OPTIONALLY] ENCLOSED BYFIELDS ESCAPED BY值必須為單一字符。FIELDS TERMINATED BY, LINES STARTING BYLINES TERMINATED BY值可以超過一個字符。例如,要編寫由回車/換行成對字符作為結尾的行,或讀取包含這類行的文件,則應指定一個LINES TERMINATED BY \r\n’子句。

如果jokes被由%%組成的行分隔,要讀取包含jokes的文件,您可以這么操作:

mysql> CREATE TABLE jokes
    ->     (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     joke TEXT NOT NULL);
mysql> LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes
    ->     FIELDS TERMINATED BY ''
    ->     LINES TERMINATED BY '\n%%\n' (joke);

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"

如果您指定了OPTINALLY,則ENCLOSED BY字符只被用于包含具有字符串數據類型(比如CHAR, BINARY, TEXTENUM)的列中的值:

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字符作為前綴,對ENCLOSED 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字符為開始,當出現這類字符時,只有后面接著字段或行TERMINATED 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 BYLINES TERMINATED BY值的第一個字符

·         ASCII 0(在轉義符之后編寫的字符實際上是ASCII0’,而不是一個值為0的字節)

如果FIELDS ESCAPED BY字符為空字符,則沒有字符被轉義,并且NULL被作為NULL輸出,而不是\N。去指定一個空的轉義符不是一個好辦法,特別是如果數據的字段值包含任何剛給定的清單中的字符時,更不能這么做。

對于輸入值,如果FIELDS ESCAPED BY字符不是空字符,則出現這種字符時會被剝離,然后以下字符被作為字段值的一部分。例外情況是,被轉義的‘0’或‘N’(例如,\0\N,此時轉義符為‘\’)。這些序列被理解為ASCII NUL(一個零值字節)和NULL。用于NULL處理的規則在本節的后部進行說明。

要了解有關‘\-escape語法的更多信息,請參見9.1節,“文字值”

在特定情況下,field-line-handling選項相互影響:

·         如果LINES TERMINATED BY是空字符串,并且FIELDS TERMINATED BY不是空字符串,則各行以FIELDS TERMINATED BY作為結尾。

·         如果FIELDS TERMINATED BYFIELDS ENCLOSED BY值均為空值(''),則使用固定行(無分隔)格式。使用固定行格式時,在字段之間不使用分隔符(但是您仍然可以有行終止符)。列值使用列的顯示寬度進行寫入和讀取。例如,如果某列被定義為INT(7),則使用7字符字段寫入列值。輸出時,通過讀取7個字符獲取列值。

LINES TERMINATED BY仍然用于分隔行。如果某行不包含所有字段,則其余的各列被設置到默認值。如果您沒有行終止符,您應該把終止符設置為''。在此情況下,文本文件必須包含每行的所有字段。

固定行格式也會影響NULL值的操作,這將在以后進行介紹。注意,如果您正在使用一個多字節字符集,則固定規格格式不會運行。

根據正在使用中的FIELDSLINES選項的不同,NULL值的操作有所變化:

·         對于默認的FIELDSLINES值,NULL被作為\N的字段值編寫,用于輸出;\N字段值被作為NULL讀取,用于輸入(假設ESCAPED BY字符為‘\’)。

·         如果FIELDS ENCLOSED BY不是空值,則包含以文字詞語NULL為值的字段被作為NULL值讀取。這與被FIELDS ENCLOSED BY字符包圍的詞語NULL不同。該詞語被作為字符串'NULL'讀取。

·         如果FIELDS ESCAPED BY是空值,則NULL被作為詞語NULL寫入。

·         采用固定行格式時(當FIELDS TERMINATED BYFIELDS ENCLOSED BY均為空值時采用),NULL被作為一個空字符串寫入。注意,這會導致在被寫入文件時,表中的NULL值和空字符串均無法辨別,這是因為兩者都被作為空字符串寫入。如果您需要在讀取文件并返回時能夠分辨兩者,則您不應使用固定行格式。

LOAD DATA INFILE不支持有些情況:

·         固定規格行(FIELDS TERMINATED BYFIELDS ENCLOSED BY均為空值)和BLOBTEXT列。

·         如果您指定了一個分隔符,并且該分隔符與其它的前綴一樣,則LOAD DATA INFILE不能正確地理解輸入值。例如,下面的FIELDS子句會導致問題:

·                FIELDS TERMINATED BY '"' ENCLOSED BY '"'

·         如果FIELDS ESCAPED BY為空值,則包含FIELDS ENCLOSED BYLINES TERMINATED BY的字段值后面再接FIELDS TERMINATED BY值會導致LOAD DATA INFILE過早地停止讀取一個字段或行。出現這種情況的原因是LOAD DATA INFILE不能正確地決定字段或行值在哪里結束。

以下的例子載入了persondata表中的所有列:

mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;

默認情況下,如果在LOAD DATA INFILE語句的末尾處沒有設列清單時,則輸入行預計會包含一個字段,用于表中的每個列。如果您只想載入一個表的部分列,則應指定一個列清單:

mysql> LOAD DATA INFILE 'persondata.txt'
    ->           INTO TABLE persondata (col1,col2,...);

如果輸入文件中各字段的順序與表中各列的順序不同,您也必須指定一個列清單。否則,MySQL不能把輸入字段和表中的列匹配起來。

列清單可以包含列名稱或用戶變量。支持SET子句。這使您可以把輸入值賦予用戶變量,然后在把結果賦予列之前,對這些值進行變換。

SET子句中的用戶變量可以采用多種方式使用。以下例子使用數據文件中的第一列,直接用于t1.column1的值。在用戶變量被用于t2.column2值之前,把第二列賦予用戶變量。該變量從屬于一個分割運行。

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, @var1)
  SET column2 = @var1/100;

SET子句可以被用于提供不是來源于輸入文件的值。以下語句把column3設置為當前的日期和時間:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, column2)
  SET column3 = CURRENT_TIMESTAMP;

您也可以通過把輸入值賦予一個用戶變量,同時不把變量賦予表中的列,來丟棄此輸入值:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, @dummy, column2, @dummy, column3);

/變量清單和SET子句的使用受到以下限定:

·         SET子句中的賦值應只含有位于賦值操作符的左側的列名稱。

·         您可以在SET賦值的右側使用子查詢。如果子查詢可以返回一個值,并且此值將被賦予到一個列中,則此子查詢只能是標量子查詢。另外,您不能使用子查詢從一個正在被載入的表中選擇。

·         對于于列/變量清單或SET子句,被IGNORE子句忽略的行不被處理。

·         當載入采用固定行格式的數據時,不能使用用戶變量,因為用戶變量沒有顯示寬度。

當處理一個輸入行時,LOAD DATA會依據列/變量清單和SET子句,把行拆分成字段,并使用值。然后,得到的行被插入表中。如果有用于表的BEFORE INSERTAFTER INSERT觸發器,則在插入行之前和插入行之后分別啟動觸發器。

如果一個輸入行含有過多的字段,則多余的字段被忽略,并且警告的數量增加。

如果一個輸入行含有的字段過少,則輸入字段缺失的表中的列被設置為默認值。默認值賦值在13.1.5節,“CREATE TABLE語法”中進行了說明。

如果字段值缺失,則對一個空字段值會被按不同方式理解:

·         對于字符串類型,列被設置為空字符串。

·         對于數字類型,列被設置為0

·         對于日期和時間類型,列被設置為該類型相應的“zero”。請參見11.3節,“日期和時間類型”

如果您明確地把一個空字符串賦予一個INSERTUPDATE語句中的字符串類型、數字類型或日期或時間類型,則產生的這些值相同。

只有在兩種情況下TIMESTAMP列被設置為當前日期和時間。一種情況時當列有一個NULL值(也就是\N)時;另一種情況是(僅對于第一個TIMESTAMP列),當一個字段清單被指定時,TIMESTAMP列會從字段清單中被略去。

LOAD DATA INFILE把所有的輸入值當作字符串,所以您不能按照使用INSERT語句的方式使用ENUMSET列的數字值。所有的ENUMSET值必須被指定為字符串。

LOAD DATA INFILE語句結束時,會按以下格式返回一個信息字符串:

Records: 1  Deleted: 0  Skipped: 0  Warnings: 0

如果您正在使用C API,您可以通過調用mysql_info()函數獲取有關語句的信息。請參見25.2.3.34節,“mysql_info()”

當值通過INSERT語句被插入時或出現相同情況時,會發生警告(見13.2.4節,“INSERT語法”)。例外情況是,當輸入行中字段過多或過少時,LOAD DATA INFILE也生成警告。這些警告并不存儲;警告的數量只用于指示運行是否良好。

您可以使用SHOW WARNINGS來得到第一批max_error_count警告的清單,作為有關運行錯誤的信息。請參見13.5.4.22節,“SHOW WARNINGS語法”

13.2.6.?REPLACE語法

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name [(col_name,...)]
    VALUES ({expr | DEFAULT},...),(...),...

或:

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...

或:

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...

REPLACE的運行與INSERT很相像。只有一點除外,如果表中的一個舊記錄與一個用于PRIMARY KEY或一個UNIQUE索引的新記錄具有相同的值,則在新記錄被插入之前,舊記錄被刪除。請參見13.2.4節,“INSERT語法”

注意,除非表有一個PRIMARY KEYUNIQUE索引,否則,使用一個REPLACE語句沒有意義。該語句會與INSERT相同,因為沒有索引被用于確定是否新行復制了其它的行。

所有列的值均取自在REPLACE語句中被指定的值。所有缺失的列被設置為各自的默認值,這和INSERT一樣。您不能從當前行中引用值,也不能在新行中使用值。如果您使用一個例如“SET col_name = col_name + 1”的賦值,則對位于右側的列名稱的引用會被作為DEFAULT(col_name)處理。因此,該賦值相當于SET col_name = DEFAULT(col_name) + 1

為了能夠使用REPLACE,您必須同時擁有表的INSERTDELETE權限。

REPLACE語句會返回一個數,來指示受影響的行的數目。該數是被刪除和被插入的行數的和。如果對于一個單行REPLACE該數為1,則一行被插入,同時沒有行被刪除。如果該數大于1,則在新行被插入前,有一個或多個舊行被刪除。如果表包含多個唯一索引,并且新行復制了在不同的唯一索引中的不同舊行的值,則有可能是一個單一行替換了多個舊行。

受影響的行數可以容易地確定是否REPLACE只添加了一行,或者是否REPLACE也替換了其它行:檢查該數是否為1(添加)或更大(替換)。

如果您正在使用C API,則可以使用mysql_affected_rows()函數獲得受影響的行數。

目前,您不能在一個子查詢中,向一個表中更換,同時從同一個表中選擇。

以下是所用算法的更詳細的說明(該算法也用于LOAD DATA...REPLACE):

1.    嘗試把新行插入到表中

2.    當因為對于主鍵或唯一關鍵字出現重復關鍵字錯誤而造成插入失敗時:

a.    從表中刪除含有重復關鍵字值的沖突行

b.    再次嘗試把新行插入到表中

13.2.7.?SELECT語法

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr, ...
    [INTO OUTFILE 'file_name' export_options
      | INTO DUMPFILE 'file_name']
    [FROM table_references
    [WHERE where_definition]
    [GROUP BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_definition]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC] , ...]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
    [FOR UPDATE | LOCK IN SHARE MODE]]

SELECT用于恢復從一個或多個表中選擇的行,并可以加入UNION語句和子查詢。請參見13.2.7.2節,“UNION語法
13.2.8節,“Subquery語法”

·         每個select_expr都指示一個您想要恢復的列。

·         table_references指示行從哪個表或哪些表中被恢復。在13.2.7.1節,“JOIN語法”中對該語法進行了說明。

·         where_definition包括關鍵詞WHERE,后面接一個表達式。該表達式指示被選擇的行必須滿足的條件。

有的行在計算時未引用任何表。SELECT也可以用于恢復這類行。

舉例說明:

mysql> SELECT 1 + 1;
        -> 2

所有被使用的子句必須按語法說明中顯示的順序嚴格地排序。例如,一個HAVING子句必須位于GROUP BY子句之后,并位于ORDER BY子句之前。

·         使用AS alias_name可以為select_expr給定一個別名。此別名用作表達式的列名,可以用于GROUP BYORDER BYHAVING子句。例如:

·                mysql> SELECT CONCAT(last_name,', ',first_name) AS full_name
·                    -> FROM mytable ORDER BY full_name;

在為select_expr給定別名時,AS關鍵詞是自選的。前面的例子可以這樣編寫:

mysql> SELECT CONCAT(last_name,', ',first_name) full_name
    -> FROM mytable ORDER BY full_name;

因為AS是自選的,如果您忘記在兩個select_expr表達式之間加逗號,則會出現一個小問題:MySQL會把第二個表達式理解為一個別名。例如,在以下語句中,columnb被作為別名對待:

mysql> SELECT columna columnb FROM mytable;

因此,使用AS明確地指定列的別名,把它作為習慣,是一個良好的操作規范。

·         在一個WHERE子句中使用列別名是不允許的,因為當執行WHERE子句時,列值可能還沒有被確定。請參見A.5.4節,“與列別名有關的問題”

·         FROM table_references子句指示行從哪些表中被恢復。如果您命名的表多于一個,則您在進行一個聯合操作。要了解有關聯合語法的說明,請參見13.2.7.1節,“JOIN語法”。對于每一個被指定的表,您可以自選地指定一個別名。

·                tbl_name [[AS] alias]
·                    [{USE|IGNORE|FORCE} INDEX (key_list)]

使用USE INDEXIGNORE INDEXFORCE INDEX可以向優化符提示如何選擇索引。這部分內容在13.2.7.1節,“JOIN語法”中進行了討論。

您可以使用SET max_seeks_for_key=value作為一種替代方法,來促使MySQL優先采用關鍵字掃描,替代表掃描。

·         您可以把當前數據庫中的一個表作為tbl_name(在當前數據庫中)引用,或作為db_name.tbl_name引用,來明確地指定一個數據庫。您可以把一列作為col_name, tbl_name.col_name引用或作為db_name.tbl_name.col_name引用。您不需要對一個列引用指定一個tbl_namedb_name.tbl_name前綴,除非此引用意義不明確。意義不明確時,要求指定明確的列引用格式。有關示例見9.2節,“數據庫、表、索引、列和別名”

·         在沒有表被引用的情況下,允許您指定DUAL作為一個假的表名。

·                mysql> SELECT 1 + 1 FROM DUAL;
·                        -> 2

有些服務器要求一個FROM子句。DUAL僅用于與這些服務器兼容。如果沒有表被引用,則MySQL不要求該子句,前面的語句可以按以下方法編寫:

mysql> SELECT 1 + 1;
        -> 2

·         使用tbl_name AS alias_nametbl_name 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;

·         WHERE子句中,您可以使用MySQL支持的所有函數,不過總計(總結)函數除外。請參見第12章:函數和操作符

·         被選擇的用于輸出的列可以使用列名稱、列別名或列位置被引用到ORDER BYGROUP 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關鍵詞明確地指定。

不建議使用列位置,因為該語法已經從SQL標準中刪除。

·         如果您使用GROUP BY,則輸出行根據GROUP BY列進行分類,如同您對相同的列進行了ORDER BYMySQLGROUP BY進行了擴展,因此您可以在各列(在子句中進行命名)的后面指定ASCDESC

·                SELECT a, COUNT(b) FROM test_table GROUP BY a DESC

·         MySQLGROUP BY的使用進行了擴展,允許選擇在GROUP BY子句中沒有被提到的字段。如果您沒有得到預期的結果,請閱讀GROUP BY的說明,請參見12.10節,“與GROUP BY子句同時使用的函數和修改程序

·         GROUP BY允許一個WITH ROLLUP修飾符。請參見12.10.2節,“GROUP BY修改程序”

·         HAVING子句基本上是最后使用,只位于被發送給客戶端的條目之前,沒有進行優化。(LIMIT用于HAVING之后。)

SQL標準要求HAVING必須引用GROUP BY子句中的列或用于總計函數中的列。不過,MySQL支持對此工作性質的擴展,并允許HAVING因為SELECT清單中的列和外部子查詢中的列。

如果HAVING子句引用了一個意義不明確的列,則會出現警告。在下面的語句中,col2意義不明確,因為它既作為別名使用,又作為列名使用:

mysql> SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;

標準SQL工作性質具有優先權,因此如果一個HAVING列名既被用于GROUP BY,又被用作輸出列清單中的起了別名的列,則優先權被給予GROUP BY列中的列。

·         HAVING不能用于應被用于WHERE子句的條目。例如,不能編寫如下語句:

·                mysql> SELECT col_name FROM tbl_name HAVING col_name > 0;

而應這么編寫:

mysql> SELECT col_name FROM tbl_name WHERE col_name > 0;

·         HAVING子句可以引用總計函數,而WHERE子句不能引用:

·                mysql> SELECT user, MAX(salary) FROM users
·                    ->     GROUP BY user HAVING MAX(salary)>10;

(在有些較早版本的MySQL中,本語句不運行。)

·         LIMIT子句可以被用于限制被SELECT語句返回的行數。LIMIT取一個或兩個數字自變量,自變量必須是非負的整數常數(當使用已預備的語句時除外)。

使用兩個自變量時,第一個自變量指定返回的第一行的偏移量,第二個自變量指定返回的行數的最大值。初始行的偏移量為0(不是1):

mysql> SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

為了與PostgreSQL兼容,MySQL也支持LIMIT row_count OFFSET offset語法。

如果要恢復從某個偏移量到結果集合的末端之間的所有的行,您可以對第二個參數是使用比較大的數。本語句可以恢復從第96行到最后的所有行:

mysql> SELECT * FROM tbl LIMIT 95,18446744073709551615;

使用1個自變量時,該值指定從結果集合的開頭返回的行數:

mysql> SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

換句話說,LIMIT nLIMIT 0,n等價。

對于已預備的語句,您可以使用位置保持符。以下語句將從tb1表中返回一行:

mysql> SET @a=1;
mysql> PREPARE STMT FROM "SELECT * FROM tbl LIMIT ?";
mysql> EXECUTE STMT USING @a;

以下語句將從tb1表中返回第二到第六行:

mysql> SET @skip=1; SET @numrows=5;
mysql> PREPARE STMT FROM "SELECT * FROM tbl LIMIT ?, ?";
mysql> EXECUTE STMT USING @skip, @numrows;

·         SELECT...INTO OUTFILE 'file_name'形式的SELECT可以把被選擇的行寫入一個文件中。該文件被創建到服務器主機上,因此您必須擁有FILE權限,才能使用此語法。file_name不能是一個原有的文件。原有文件會阻止例如“/etc/passwd”的文件和數據庫表被銷毀。

SELECT...INTO OUTFILE語句的主要作用是讓您可以非常快速地把一個表轉儲到服務器機器上。如果您想要在服務器主機之外的部分客戶主機上創建結果文件,您不能使用SELECT...INTO OUTFILE。在這種情況下,您應該在客戶主機上使用比如“mysql e "SELECT ..." > file_name”的命令,來生成文件。

SELECT...INTO OUTFILELOAD DATA INFILE的補語;用于語句的exort_options部分的語法包括部分FIELDSLINES子句,這些子句與LOAD DATA INFILE語句同時使用。請參見13.2.5節,“LOAD DATA INFILE語法”

FIELDS ESCAPED BY用于控制如何寫入特殊字符。如果FIELDS ESCAPED BY字符不是空字符,則被用于在輸出中對以下字符設前綴:

o        FIELDS ESCAPED BY字符

o        FIELDS [OPTIONALLY] ENCLOSED BY字符

o        FIELDS TERMINATED BYLINES TERMINATED BY值的第一個字符

o        ASCII 0(在編寫時接在轉義符后面的是ASCII 0’,而不是一個零值字節)

如果FIELDS ESCAPED BY字符是空字符,則沒有字符被轉義,并且NULL被作為NULL輸出,而不是作為\N輸出。指定一個空的轉義符不是一個好的主意。特別是當您的數據中的字段值包含剛被給予的清單中的字符時,更是如此。

其原因是您必須對所有FIELDS TERMINATED BY, ENCLOSED BY, ESCAPED BYLINES TERMINATED BY字符進行轉義,才能可靠地讀取文件并返回。ASCII NUL被轉義,以便更容易地使用調頁程序觀看。

生成的文件不必符合SQL語法,所以沒有其它的字符需要被轉義。

在下面的例子中,生成一個文件,各值用逗號隔開。這種格式可以被許多程序使用。

SELECT a,b,a+b INTO OUTFILE '/tmp/result.text'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM test_table;

·         如果您使用INTO DUMPFILE代替INTO OUTFILE,則MySQL只把一行寫入到文件中,不對任何列或行進行終止,也不執行任何轉義處理。如果您想要把一個BLOB值存儲到文件中,則這個語句是有用的。

·         注釋:任何由INTO OUTFILEINTO DUMPFILE創建的文件都可以被服務器主機上的所有用戶編寫。原因是,MySQL服務器不能創建這樣的文件,即文件的所有者不是該文件運行時所屬的用戶(任何時候,您都不能出于此原因或出于其它原因把mysqld作為根段運行)。該文件必須是全局可寫的,這樣您就可以操作其中的內容。

·         有的過程應在結果集合內處理數據。PROCEDURE子句用于對這些過程進行命名。要了解示例,請參見27.3.1節,“步驟分析”

·         存儲引擎使用頁面或行鎖。如果您對存儲引擎使用FOR UPDATE,則受到查詢檢驗的行會被進行寫鎖定,直到當前事務結束為止。使用LOCK IN SHARE MODE可以設置一個共享鎖。共享鎖可以防止其它事務更新或刪除被檢驗的行。請參見15.2.10.5節,“鎖定讀取SELECT ... FOR UPDATE和SELECT ... LOCK IN SHARE MODE”

SELECT關鍵詞的后面,您可以使用許多選項。這些選項可以影響語句的運行。

ALL, DISTINCTDISTINCTROW選項指定是否重復行應被返回。如果這些選項沒有被給定,則默認值為ALL(所有的匹配行被返回)。DISTINCTDISTINCTROW是同義詞,用于指定結果集合中的重復行應被刪除。

HIGH_PRIORITY, STRAIGHT_JOIN和以SQL_為開頭的選項是MySQL相對于標準SQL的擴展。

·         HIGH_PRIORITY給予SELECT更高的優先權,高于用于更新表的語句。您應該只對查詢使用HIGH_PRIORITY。查詢速度非常快,而且立刻被執行。SELECT HIGH_PRIORITY查詢在表被鎖定用于讀取時被發出。即使有一個新的語句正在等待表變為空閑,查詢也會運行。

HIGH_PRIORITY不能和SELECT語句同時使用。SELECT語句是UNION的一部分。

·         STRAIGHT_JOIN用于促使優化符把表聯合在一起,順序按照這些表在FROM子句中排列的順序。如果優化符聯合表時順序不佳,您可以使用STRAIGHT_JOIN來加快查詢的速度。請參見7.2.1節,“EXPLAIN語法(獲取關于SELECT的信息)STRAIGHT_JOIN也可以被用于table_references清單中。請參見13.2.7.1節,“JOIN語法”

·         SQL_BIG_RESULT可以與GROUP BYDISTINCT同時使用,來告知優化符結果集合有很多行。在這種情況下,MySQL直接使用以磁盤為基礎的臨時表(如果需要的話)。在這種情況下,MySQL還會優先進行分類,不優先使用臨時表。臨時表對于GROUP BY組分帶有關鍵字。

·         SQL_BUFFER_RESULT促使結果被放入一個臨時表中。這可以幫助MySQL提前解開表鎖定,在需要花費較長時間的情況下,也可以幫助把結果集合發送到客戶端中。

·         SQL_SMALL_RESULT可以與GROUP BYDISTINCT同時使用,來告知優化符結果集合是較小的。在此情況下,MySAL使用快速臨時表來儲存生成的表,而不是使用分類。在MySQL 5.1中,通常不需要這樣。

·         SQL_CALC_FOUND_ROWS告知MySQL計算有多少行應位于結果集合中,不考慮任何LIMIT子句。行的數目可以使用SELECT FOUND_ROWS()恢復。請參見12.9.3節,“信息函數”

·         如果您正在使用一個query_cache_type值,值為2DEMAND,則SQL_CACHE告知MySQL把查詢結果存儲在查詢緩存中。對于使用UNION的查詢或子查詢,本選項會影響查詢中的所有SELECT。請參見5.13節,“MySQL查詢高速緩沖”

·         SQL_NO_CACHE告知MySQL不要把查詢結果存儲在查詢緩存中。請參見5.13節,“MySQL查詢高速緩沖”。對于一個使用UNION或子查詢的查詢,本選項會影響查詢中的SELECT

13.2.7.1.?JOIN語法

MySQL支持以下JOIN語法。這些語法用于SELECT語句的table_references部分和多表DELETEUPDATE語句:

table_references:
    table_reference [, table_reference] …

table_reference:
    table_factor
  | join_table

table_factor:
    tbl_name [[AS] alias]
        [{USE|IGNORE|FORCE} INDEX (key_list)]
  | ( table_references )
  | { OJ table_reference LEFT OUTER JOIN table_reference
        ON conditional_expr }

join_table:
    table_reference [INNER | CROSS] JOIN table_factor [join_condition]
  | table_reference STRAIGHT_JOIN table_factor
  | table_reference STRAIGHT_JOIN table_factor ON condition
  | table_reference LEFT [OUTER] JOIN table_reference join_condition
  | table_reference NATURAL [LEFT [OUTER]] JOIN table_factor
  | table_reference RIGHT [OUTER] JOIN table_reference join_condition
  | table_reference NATURAL [RIGHT [OUTER]] JOIN table_factor

join_condition:
    ON conditional_expr
  | USING (column_list)

一個表引用還被稱為一個聯合表達式。

SQL標準相比,table_factor的語法被擴展了。SQL標準只接受table_reference,而不是圓括號內的一系列條目。

如果我們把一系列table_reference條目中的每個逗號都看作相當于一個內部聯合,則這是一個穩妥的擴展。例如:

SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

相當于:

SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)

MySQL中,CROSS JOIN從語法上說與INNER JOIN等同(兩者可以互相替換。在標準SQL中,兩者是不等同的。INNER JOINON子句同時使用,CROSS JOIN以其它方式使用。

通常,在只含有內部聯合運行的聯合表達式中,圓括號可以被忽略。MySQL也支持嵌套的聯合(見7.2.10節,“MySQL如何優化嵌套Join”)。

通常,您不應對ON部分有任何條件。ON部分用于限定在結果集合中您想要哪些行。但是,您應在WHERE子句中指定這些條件。這條規則有一些例外。

在前面的清單中顯示的{ OJ ... LEFT OUTER JOIN ...}語法的目的只是為了保持與ODBC的兼容性。語法中的花括號應按字面書寫;該括號不是中間語法。中間語法用于語法描述的其它地方。

·         表引用可以使用tbl_name AS alias_nametbl_name 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;

·         ON條件句是可以被用于WHERE子句的格式的任何條件表達式。

·         如果對于在LEFT JOIN中的ONUSING部分中的右表沒有匹配的記錄,則所有列被設置為NULL的一個行被用于右表。如果一個表在其它表中沒有對應部分,您可以使用這種方法在這種表中查找記錄:

·                mysql> SELECT table1.* FROM table1
·                    ->        LEFT JOIN table2 ON table1.id=table2.id
·                    ->        WHERE table2.id IS NULL;

本例查找在table1中含有一個id值的所有行。同時,在table2中沒有此id值(即,table1中的所有行在table2中沒有對應的行)。本例假設table2.id被定義為NOT NULL。請參見7.2.9節,“MySQL如何優化LEFT JOIN和RIGHT JOIN”

·         USING(column_list)子句用于為一系列的列進行命名。這些列必須同時在兩個表中存在。如果表a和表b都包含列c1, c2c3,則以下聯合會對比來自兩個表的對應的列:

·                a LEFT JOIN b USING (c1,c2,c3)

·         兩個表的NATURAL [LEFT] JOIN被定義為與INNER JOIN語義相同,或與使用USING子句的LEFT JOIN語義相同。USING子句用于為同時存在于兩個表中的所有列進行命名。

·         INNER JOIN和,(逗號)在無聯合條件下是語義相同的:兩者都可以對指定的表計算出笛卡兒乘積(也就是說,第一個表中的每一行被聯合到第二個表中的每一行)。

·         RIGHT JOIN的作用與LEFT JOIN的作用類似。要使代碼可以在數據庫內移植,建議您使用LEFT JOIN代替RIGHT JOIN

·         STRAIGHT_JOINJOIN相同。除了有一點不一樣,左表會在右表之前被讀取。STRAIGH_JOIN可以被用于這樣的情況,即聯合優化符以錯誤的順序排列表。

您可以提供提示,當從一個表中恢復信息時,MySQL應使用哪個索引。通過指定USE INDEXkey_list),您可以告知MySQL只使用一個索引來查找表中的行。另一種語法IGNORE INDEXkey_list)可以被用于告知MySQL不要使用某些特定的索引。如果EXPLAIN顯示MySQL正在使用來自索引清單中的錯誤索引時,這些提示會有用處。

您也可以使用FORCE INDEX,其作用接近USE INDEXkey_list),不過增加了一項作用,一次表掃描被假設為代價很高。換句話說,只有當無法使用一個給定的索引來查找表中的行時,才使用表掃描。

USE KEYIGNORE KEYFORCE KEYUSE INDEXIGNORE INDEXFORCE INDEX的同義詞。

注釋:當MySQL決定如何在表中查找行并決定如何進行聯合時,使用USE INDEXIGNORE INDEXFORCE INDEX只會影響使用哪些索引。當分解一個ORDER BYGROUP BY時,這些語句不會影響某個索引是否被使用。

部分的聯合示例:

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;
mysql> SELECT * FROM table1 USE INDEX (key1,key2)
    ->          WHERE key1=1 AND key2=2 AND key3=3;
mysql> SELECT * FROM table1 IGNORE INDEX (key3)
    ->          WHERE key1=1 AND key2=2 AND key3=3;

7.2.9節,“MySQL如何優化LEFT JOIN和RIGHT JOIN”

注釋:自然聯合和使用USING的聯合,包括外部聯合變量,依據SQL:2003標準被處理。這些變更時MySQL與標準SQL更加相符。不過,對于有些聯合,這些變更會導致不同的輸出列。另外,有些查詢在舊版本(5.0.12以前)工作正常,但也必須重新編寫,以符合此標準。對于有關當前聯合處理和舊版本中的聯合處理的效果的對比,以下列表提供了更詳細的信息。

·         NATURAL聯合或USING聯合的列會與舊版本不同。特別是,不再出現冗余的輸出列,用于SELECT *擴展的列的順序會與以前不同。

示例:

CREATE TABLE t1 (i INT, j INT);
CREATE TABLE t2 (k INT, j INT);
INSERT INTO t1 VALUES(1,1);
INSERT INTO t2 VALUES(1,1);
SELECT * FROM t1 NATURAL JOIN t2;
SELECT * FROM t1 JOIN t2 USING (j);

對于舊版本,語句會產生以下輸出:

+------+------+------+------+
| i    | j    | k    | j    |
+------+------+------+------+
|    1 |    1 |    1 |    1 |
+------+------+------+------+
+------+------+------+------+
| i    | j    | k    | j    |
+------+------+------+------+
|    1 |    1 |    1 |    1 |
+------+------+------+------+

在第一個SELECT語句中,列i同時出現在兩個表中,為一個聯合列,所以,依據標準SQL,該列在輸出中只出現一次。與此類似,在第二個SELECT語句中,列jUSING子句中被命名,應在輸出中只出現一次。但是,在兩種情況下,冗余的列均沒被消除。另外,依據標準SQL,列的順序不正確。

現在,語句產生如下輸出:

+------+------+------+
| j    | i    | k    |
+------+------+------+
|    1 |    1 |    1 |
+------+------+------+
+------+------+------+
| j    | i    | k    |
+------+------+------+
|    1 |    1 |    1 |
+------+------+------+

冗余的列被消除,并且依據標準SQL,列的順序是正確的:

o        第一,兩表共有的列,按在第一個表中的順序排列

o        第二,第一個表中特有的列,按該表中的順序排列

o        第三,第二個表中特有的列,按該表中的順序排列

·         對多方式自然聯合的估算會不同。方式要求重新編寫查詢。假設您有三個表t1(a,b), t2(c,b)t3(a,c),每個表有一行:t1(1,2), t2(10,2)t3(7,10)。同時,假設這三個表具有NATURAL JOIN

·                SELECT  FROM t1 NATURAL JOIN t2 NATURAL JOIN t3;

在舊版本中,第二個聯合的左操作數被認為是t2,然而它應該為嵌套聯合(t1 NATURAL JOIN t2)。結果,對t3的列進行檢查時,只檢查其在t2中的共有列。如果t3t1有共有列,這些列不被用作equi-join列。因此,在舊版本的MySQL中,前面的查詢被轉換為下面的equi-join

SELECT  FROM t1, t2, t3
  WHERE t1.b = t2.b AND t2.c = t3.c;

此聯合又省略了一個equi-join謂語(t1.a = t3.a)。結果是,該聯合產生一個行,而不是空結果。正確的等價查詢如下:

SELECT  FROM t1, t2, t3
  WHERE t1.b = t2.b AND t2.c = t3.c AND t1.a = t3.a;

如果您要求在當前版本的MySQL中獲得和舊版本中相同的查詢結果,應把自然聯合改寫為第一個equi-join

·         在舊版本中,逗號操作符(,)和JOIN均有相同的優先權,所以聯合表達式t1, t2 JOIN t3被理解為((t1, t2) JOIN t3)。現在,JOIN有更高的優先權,所以表達式被理解為(t1, (t2 JOIN t3))。這個變更會影響使用ON子句的語句,因為該子句只參閱聯合操作數中的列。優先權的變更改變了對什么是操作數的理解。

示例:

CREATE TABLE t1 (i1 INT, j1 INT);
CREATE TABLE t2 (i2 INT, j2 INT);
CREATE TABLE t3 (i3 INT, j3 INT);
INSERT INTO t1 VALUES(1,1);
INSERT INTO t2 VALUES(1,1);
INSERT INTO t3 VALUES(1,1);
SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);

在舊版本中,SELECT是合法的,因為t1, t2被隱含地歸為(t1,t2)。現在,JOIN取得了優先權,因此用于ON子句的操作數是t2t3。因為t1.i1不是任何一個操作數中的列,所以結果是出現在'on clause'中有未知列't1.i1'的錯誤。要使聯合可以被處理,用使用圓括號把前兩個表明確地歸為一組,這樣用于ON子句的操作數為(t1,t2)t3

SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);

本變更也適用于INNER JOINCROSS JOINLEFT JOINRIGHT JOIN

·         在舊版本中,ON子句可以參閱在其右邊命名的表中的列。現在,ON子句只能參閱操作數。

示例:

CREATE TABLE t1 (i1 INT);
CREATE TABLE t2 (i2 INT);
CREATE TABLE t3 (i3 INT);
SELECT * FROM t1 JOIN t2 ON (i1 = i3) JOIN t3;

在舊版本中,SELECT語句是合法的。現在該語句會運行失敗,出現在'on clause'中未知列'i3'的錯誤。這是因為i3t3中的一個表,而t3不是ON子句中的操作數。本語句應進行如下改寫:

SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);

·         在舊版本中,一個USING子句可以被改寫為一個ON子句。ON子句對比了相應的列。例如,以下兩個子句具有相同的語義:

·                a LEFT JOIN b USING (c1,c2,c3)
·                a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3

現在,這兩個子句不再是一樣的:

o        在決定哪些行滿足聯合條件時,兩個聯合保持語義相同。

o        在決定哪些列顯示SELECT *擴展時,兩個聯合的語義不相同。USING聯合選擇對應列中的合并值,而ON聯合選擇所有表中的所有列。對于前面的USING聯合,SELECT *選擇這些值:

o                     COALESCE(a.c1,b.c1), COALESCE(a.c2,b.c2), COALESCE(a.c3,b.c3)

對于ON聯合,SELECT *選擇這些值:

a.c1, a.c2, a.c3, b.c1, b.c2, b.c3

使用內部聯合時,COALESCE(a.c1,b.c1)a.c1b.c1相同,因為兩列將具有相同的值。使用外部聯合時(比如LEFT JOIN),兩列中有一列可以為NULL。該列將會從結果中被忽略。

13.2.7.2.?UNION語法
 

SELECT ...
UNION [ALL | DISTINCT]
SELECT ...
[UNION [ALL | DISTINCT]
SELECT ...]

UNION用于把來自許多SELECT語句的結果組合到一個結果集合中。

列于每個SELECT語句的對應位置的被選擇的列應具有相同的類型。(例如,被第一個語句選擇的第一列應和被其它語句選擇的第一列具有相同的類型。)在第一個SELECT語句中被使用的列名稱也被用于結果的列名稱。

SELECT語句為常規的選擇語句,但是受到如下的限定:

·         只有最后一個SELECT語句可以使用INTO OUTFILE

·         HIGH_PRIORITY不能與作為UNION一部分的SELECT語句同時使用。如果您對第一個SELECT指定了HIGH_PRIORITY,則不會起作用。如果您對其它后續的SELECT語句指定了HIGH_PRIORITY,則會產生語法錯誤。

如果您對UNION不使用關鍵詞ALL,則所有返回的行都是唯一的,如同您已經對整個結果集合使用了DISTINCT。如果您指定了ALL,您會從所有用過的SELECT語句中得到所有匹配的行。

DISTINCT關鍵詞是一個自選詞,不起任何作用,但是根據SQL標準的要求,在語法中允許采用。(在MySQL中,DISTINCT代表一個共用體的默認工作性質。)

您可以在同一查詢中混合UNION ALLUNION DISTINCT。被混合的UNION類型按照這樣的方式對待,即DISTICT共用體覆蓋位于其左邊的所有ALL共用體。DISTINCT共用體可以使用UNION DISTINCT明確地生成,或使用UNION(后面不加DISTINCTALL關鍵詞)隱含地生成。

如果您想使用ORDER BYLIMIT子句來對全部UNION結果進行分類或限制,則應對單個地SELECT語句加圓括號,并把ORDER BYLIMIT放到最后一個的后面。以下例子同時使用了這兩個子句:

(SELECT a FROM tbl_name WHERE a=10 AND B=1)
UNION
(SELECT a FROM tbl_name WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

這種ORDER BY不能使用包括表名稱(也就是,采用tbl_name.col_name格式的名稱)列引用。可以在第一個SELECT語句中提供一個列別名,并在ORDER BY中參閱別名,或使用列位置在ORDER BY中參閱列。(首選采用別名,因為不建議使用列位置。)

另外,如果帶分類的一列有別名,則ORDER BY子句必須引用別名,而不能引用列名稱。以下語句中的第一個語句必須運行,但是第二個會運行失敗,出現在'order clause'中有未知列'a'的錯誤:

(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY b;
(SELECT a AS b FROM t) UNION (SELECT ...) ORDER BY a;

To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT:   為了對單個SELECT使用ORDER BYLIMIT,應把子句放入圓括號中。圓括號包含了SELECT

(SELECT a FROM tbl_name WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM tbl_name WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

圓括號中用于單個SELECT語句的ORDER BY只有當與LIMIT結合后,才起作用。否則,ORDER BY被優化去除。

UNION結果集合中的列的類型和長度考慮了被所有SELECT語句恢復的數值。例如,考慮如下語句:

mysql> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+---------------+
| REPEAT('a',1) |
+---------------+
| a             |
| bbbbbbbbbb    |
+---------------+

(在部分早期版本的MySQL中,第二行已被刪節到長度為1。)

13.2.8. Subquery語法

子查詢是另一個語句中的一個SELECT語句。

MySQL支持SQL標準要求的所有子查詢格式和操作,也支持MySQL特有的幾種特性。

以下是一個子查詢的例子:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

在本例中,SELECT * FROM t1...是外部查詢(或外部語句),SELECT column1 FROM t2)是子查詢。我們可以說子查詢嵌套在外部查詢中。實際上,子查詢也可以嵌套在其它子查詢中,嵌套程度可以很深。子查詢必須要位于圓括號中。

子查詢的主要優勢為:

·         子查詢允許結構化的查詢,這樣就可以把一個語句的每個部分隔離開。

·         有些操作需要復雜的聯合和關聯。子查詢提供了其它的方法來執行這些操作。

·         在許多人看來,子查詢是可讀的。實際上,子查詢給予人們調用早期SQL“結構化查詢語言”的原本的想法,這是子查詢的創新。

以下是一個示例語句。該語句顯示了有關子查詢語法的要點。子查詢語法由SQL標準指定并被MySQL支持。

DELETE FROM t1
WHERE s11 > ANY
(SELECT COUNT(*) /* no hint */ FROM t2
WHERE NOT EXISTS
(SELECT * FROM t3
WHERE ROW(5*t2.s1,77)=
(SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM
(SELECT * FROM t5) AS t5)));

一個子查詢會返回一個標量(單一值)、一個行、一個列或一個表(一行或多行及一列或多列)。這些子查詢被稱為標量、列、行和表子查詢。可返回一個特定種類結果的子查詢經常只被用于特定的語境中,在后面各節中有說明。

有些語句可以使用子查詢。對這些語句的類型基本沒有限定。子查詢可以包括普通SELECT可以包括的任何關鍵詞或子句:DISTINCT, GROUP BY, ORDER BY, LIMIT, 聯合, 索引提示, UNION結構化, 評注和函數等。

有一個限定是,一個子查詢的外部語句必須是以下語句之一:SELECT, INSERT, UPDATE, DELETE, SETDO。還有一個限定是,目前,您不能在一個子查詢中修改一個表,又在同一個表中選擇。這適用于DELETE, INSERT, REPLACEUPDATE語句。在附錄I:特性限制中給出了對子查詢使用的更綜合的討論。

13.2.8.1. 子查詢作為標量操作數

子查詢最簡單的形式是返回單一值的標量子查詢。標量子查詢是一個單一操作數。只要單一列值或文字是合法的,并且您希望子查詢具有所有操作數都具有的特性,則您就可以使用子查詢。操作數具有的特性包括:一個數據類型、一個長度、一個指示是否可以為NULL的標志等。舉例說明:
CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL);
INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);

在本SELECT中的子查詢返回一個單一值('abcde')。該單一值的數據類型為CHAR,長度為5,字符集和整序與在CREATE TABLE時有效的默認值相同,并有一個指示符號,指示列中的值可以為NULL。實際上,基本上所有的子查詢都為NULL。如果在本例中使用的表為空表,則子查詢的值應為NULL

在有些情況下,標量子查詢不能使用。如果一個語句只允許一個文字值,您不能使用子查詢。例如,LIMIT要求文字整數自變量,LOAD DATA要求一個文字字符串文件名。您不能使用子查詢來提供這些值。

后面各節包括更簡練的結構(SELECT column1 FROM t1)。當您在這些章節中觀看例子時,請設想一下您自己的代碼包含更多樣、更復雜的結構。

舉例說明,假設我們制作兩個表:

CREATE TABLE t1 (s1 INT);
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 (s1 INT);
INSERT INTO t2 VALUES (2);

然后執行一個SELECT

SELECT (SELECT s1 FROM t2) FROM t1;

結果為2,因為t2中有一行包含s1s1有一個值為2

一個標量子查詢可以為一個表達式的一部分。不要忘記圓括號。即使是子查詢是一個為函數提供自變量的操作數時,也不要忘記圓括號。舉例說明:

SELECT UPPER((SELECT s1 FROM t1)) FROM t2;

13.2.8.2. 使用子查詢進行比較

子查詢最常見的一種使用方式如下:

non_subquery_operand comparison_operator (subquery)

comparison_operator是以下 操作符之一時:

=  >  <  >=  <=  <>

例如:

  ... 'a' = (SELECT column1 FROM t1)

有時,子查詢的合法位置只能在比較式的右側,您可以發現,在有些舊的DBMSs中仍保持這一點。

以下是一個常見格式的子查詢比較的例子。您不能使用聯合進行此類比較。表t1中有些值與表t2中的最大值相同。該比較可以查找出所有這類值:

SELECT column1 FROM t1
WHERE column1 = (SELECT MAX(column2) FROM t2);

下面還有另一個例子,該例子也不可能使用聯合,因為該例子涉及對其中一個表進行總計。表t1中的有些行含有的值會在給定的列中出現兩次。該例子可以查找出所有這些行:

SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);

對于采用這些操作符之一進行的比較,子查詢必須返回一個標量。有一個例外,那就是=可以和行子查詢同時使用。請參見13.2.8.5節,“行子查詢”

13.2.8.3. 使用ANY, IN和SOME進行子查詢

語法:

operand comparison_operator ANY (subquery)
operand IN (subquery)
operand comparison_operator SOME (subquery)

ANY關鍵詞必須后面接一個比較操作符。ANY關鍵詞的意思是“對于在子查詢返回的列中的任一數值,如果比較結果為TRUE的話,則返回TRUE”。例如:

SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);

假設表t1中有一行包含(10)。如果表t2包含(21147),則表達式為TRUE,因為t2中有一個值為7,該值小于10。如果表t2包含(2010),或者如果表t2為空表,則表達式為FALSE。如果表t2包含(NULL, NULL, NULL),則表達式為UNKNOWN

詞語IN是=ANY的別名。因此,這兩個語句是一樣的:

SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN    (SELECT s1 FROM t2);

不過,NOT IN不是<> ANY的別名,但是是<> ALL的別名。請參見13.2.8.4節,“使用ALL進行子查詢

詞語SOMEANY的別名。因此,這兩個語句是一樣的:

SELECT s1 FROM t1 WHERE s1 <> ANY  (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);

使用詞語SOME的機會很少,但是本例顯示了為什么SOME是有用的。對于多數人來說,英語短語“a is not equal to any b”的意思是“沒有一個ba相等”,但是在SQL語法中不是這個意思。該語法的意思是“有部分ba不相等”。使用<> SOME有助于確認每個人都理解該查詢的真正含義。

13.2.8.4. 使用ALL進行子查詢

語法:
operand comparison_operator ALL (subquery)

詞語ALL必須接在一個比較操作符的后面。ALL的意思是“對于子查詢返回的列中的所有值,如果比較結果為TRUE,則返回TRUE。”例如:

SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);

假設表1中有一行包含(10)。如果表t2包含(-50,+5),則表達式為TRUE,因為10t2中的所有三個值都大。如果表t2包含(126NULL,-100),則表達式為FALSE,因為表t2中有一個值12大于10。如果表t2包含(0NULL1),則表達式為unknown

最后,如果表t2為空表,則結果為TRUE。因此,當表t2為空表時,以下語句為TRUE

SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);

但是,當表t2為空表時,本語句為NULL

SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);

另外,當表t2為空表時,以下語句為NULL

SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);

通常,包含NULL值的表和空表為“邊緣情況”。當編寫子查詢代碼時,都要考慮您是否把這兩種可能性計算在內。

NOT IN<> ALL的別名。因此,以下兩個語句是相同的:

SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);

13.2.8.5. 行子查詢

對于本點的討論屬于標量或列子查詢,即返回一個單一值或一列值的子查詢。行子查詢是一個能返回一個單一行的子查詢變量,因此可以返回一個以上的列值。以下是兩個例子:
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);

如果在表t2的一個行中,column1=1并且column2=2,則查詢結果均為TRUE

表達式(12)和ROW12)有時被稱為行構造符。兩者是等同的,在其它的語境中,也是合法的。例如,以下兩個語句在語義上是等同的(但是目前只有第二個語句可以被優化):

  SELECT * FROM t1 WHERE (column1,column2) = (1,1);
  SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

行構造符通常用于與對能返回兩個或兩個以上列的子查詢進行比較。例如,以下查詢可以答復請求,“在表t1中查找同時也存在于表t2中的所有的行”:

SELECT column1,column2,column3
FROM t1
WHERE (column1,column2,column3) IN
(SELECT column1,column2,column3 FROM t2);

13.2.8.6.?EXISTS和NOT EXISTS

如果一個子查詢返回任何的行,則EXISTS subqueryFALSE。例如:
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);

過去,EXISTS子查詢以SELECT *為開始,但是可以以SELECT 5SELECT column1或其它的為開始。MySQL在這類子查詢中忽略了SELECT清單,因此沒有區別。

對于前面的例子,如果t2包含任何行,即使是只含有NULL值的行,EXISTS條件也為TRUE。這實際上是一個不可能的例子,因為基本上所有的[NOT] EXISTS子查詢均包含關聯。以下是一些更現實的例子:

·         哪些種類的商店出現在一個或多個城市里?

·                SELECT DISTINCT store_type FROM stores
·                  WHERE EXISTS (SELECT * FROM cities_stores
·                                WHERE cities_stores.store_type = stores.store_type);

·         哪些種類的商店沒有出現在任何城市里?

·                SELECT DISTINCT store_type FROM stores
·                  WHERE NOT EXISTS (SELECT * FROM cities_stores
·                                    WHERE cities_stores.store_type = stores.store_type);

·         哪些種類的商店出現在所有城市里?

·                SELECT DISTINCT store_type FROM stores s1
·                  WHERE NOT EXISTS (
·                    SELECT * FROM cities WHERE NOT EXISTS (
·                      SELECT * FROM cities_stores
·                       WHERE cities_stores.city = cities.city
·                       AND cities_stores.store_type = stores.store_type));

最后一個例子是一個雙嵌套NOT EXISTS查詢。也就是,該查詢包含一個NOT EXISTS子句,該子句又包含在一個NOT EXISTS子句中。該查詢正式地回答了這個問題,“是否有某個城市擁有沒有列在Stores中的商店?”。可以比較容易的說,一個帶嵌套的NOT EXISTS可以回答這樣的問題,“是否對于所有的yx都為TRUE?”

13.2.8.7. 關聯子查詢

相關聯的子查詢是一個包含對表的引用的子查詢。該表也顯示在外部查詢中。例如:
SELECT * FROM t1 WHERE column1 = ANY
(SELECT column1 FROM t2 WHERE t2.column2 = t1.column2);

注意,即使子查詢的FROM子句不提及表t1,該子查詢也會包含一個對t1中一列的引用。所以,MySQL看上去位于子查詢的外部,并在外部查詢中查找t1

假設表t1包含一行,在此行中column1=5并且column2=6;同時,表t2包含一行,在此行中column1=5并且column2=7。簡單的表達式... WHERE column1 = ANY (SELECT column1 FROM t2)會為TRUE。但是在本例中,在子查詢中的WHERE子句為FALSE(因為(56)不等于(57)),所以子查詢總體上為FALSE

范圍劃分規則:MySQL從內到外進行評估。例如:

SELECT column1 FROM t1 AS x
WHERE x.column1 = (SELECT column1 FROM t2 AS x
WHERE x.column1 = (SELECT column1 FROM t3
WHERE x.column2 = t3.column1));

在本語句中,x.column2必須是表t2中的列,因為SELECT column1 FROM t2 AS x ...t2進行了重命名。它不是表t1中的列,因為SELECT column1 FROM t1 ...是一個更靠外的外部查詢。

對于HAVINGORDER BY子句中的子查詢,MySQL也會在外部選擇清單中尋找列名稱。

對于特定的情況,相關聯的子查詢被優化。例如:

val IN (SELECT key_val FROM tbl_name WHERE correlated_condition)

否則,這些子查詢效率不高,可能速度會慢。把查詢作為聯合進行改寫可能會改進效率。

相關聯的子查詢不能從外部查詢中引用總計函數的結果。

13.2.8.8. FROM子句中的子查詢

SELECT語句的FROM子句中,子查詢是合法的。實際的語法是:

SELECT ... FROM (subquery) [AS] name ...

[AS] name子句是強制性的,因為FROM子句中的每個表必須有一個名稱。在子查詢選擇列表中的任何列都必須有唯一的名稱。您可以在本手冊中的其它地方找到對本語法的說明。在該處,所用的詞語是“導出表”。

為了進行詳細說明,假設您有如下一個表:

CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);

下面使用了示例表,解釋了在FROM子句中如何使用子查詢:

INSERT INTO t1 VALUES (1,'1',1.0);
INSERT INTO t1 VALUES (2,'2',2.0);
SELECT sb1,sb2,sb3
FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb
WHERE sb1 > 1;

結果:2, '2', 4.0

下面是另一個例子:假設您想了解一個分類后的表的一組和的平均值。采用如下操作:

SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;

不過,本查詢提供所需的信息:

SELECT AVG(sum_column1)
FROM (SELECT SUM(column1) AS sum_column1
FROM t1 GROUP BY column1) AS t1;

注意,在子查詢中使用的列名稱(sum_column1)被整理到外部查詢中。

FROM子句中的子查詢可以返回標量、列、行或表。FROM子句中的子查詢不能為有關聯的子查詢。

即使對EXPLAIN語句(即建立臨時導出表),FROM子句中的子查詢也會被執行。這是因為在優化過程中,上一級的查詢需要有關所有表的信息。

13.2.8.9. 子查詢錯誤

以下錯誤只適用于子查詢。本節把這些錯誤歸在一起。

·         來自子查詢的列的數目不正確

·                ERROR 1241 (ER_OPERAND_COL)
·                SQLSTATE = 21000
·                Message = "Operand should contain 1 column(s)"

在出現以下情況時,發生此錯誤:

SELECT (SELECT column1, column2 FROM t2) FROM t1;

如果您的目的是進行比較,您可以使用能返回多個列的子查詢。請參見13.2.8.5節,“行子查詢”。不過,在其它的語境下,子查詢必須為標量操作數。

·         來自子查詢的行的數目不正確:

·                ERROR 1242 (ER_SUBSELECT_NO_1_ROW)
·                SQLSTATE = 21000
·                Message = "Subquery returns more than 1 row"

如果在語句中,子查詢返回的行多于一個,則發生此錯誤。請考慮以下例子:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

如果SELECT column1 FROM t2只返回一行,則將執行以前的查詢。如果子查詢返回的行多于一個,則將出現錯誤1242。在這種情況下,該查詢將被改寫為:

SELECT * FROM t1 WHERE column1 = ANY (SELECT column1 FROM t2);

·         在子查詢中表格使用不正確:

·                Error 1093 (ER_UPDATE_TABLE_USED)
·                SQLSTATE = HY000
·                Message = "You can't specify target table 'x'
·                for update in FROM clause"

在如下情況下,發生該錯誤:

UPDATE t1 SET column2 = (SELECT MAX(column1) FROM t1);

SELECT語句一樣,在UPDATEDELETE語句中,子查詢是合法的。所以您可以在UPDATE語句中使用子查詢進行賦值。不過,您不能把同一個表(在本例中為表t1)既用于子查詢的FROM子句,又用于更新目標。

對于事務存儲引擎,子查詢的錯誤會導致整個語句失效。對于非事務存儲引擎,在遇到錯誤之前進行的數據修訂會被保留。

13.2.8.10. 優化子查詢

開發過程不斷進展,所以從長遠來看,沒有一個可靠的優化技巧。有些技巧您可能會感興趣,并原意采用:

·         有些子句會影響在子查詢中的行的數量和順序。使用這類子句。例如:

·                SELECT * FROM t1 WHERE t1.column1 IN
·                (SELECT column1 FROM t2 ORDER BY column1);
·                SELECT * FROM t1 WHERE t1.column1 IN
·                (SELECT DISTINCT column1 FROM t2);
·                SELECT * FROM t1 WHERE EXISTS
·                (SELECT * FROM t2 LIMIT 1);

·         用子查詢替換聯合。例如,試進行如下操作:

·                SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN (
·                SELECT column1 FROM t2);

代替如下操作:

SELECT DISTINCT t1.column1 FROM t1, t2
WHERE t1.column1 = t2.column1;

·         部分子查詢可以被轉換為聯合,以便與不支持子查詢的舊版本的MySQL相兼容。不過,在有些情況下,把子查詢轉化為聯合可以提高效果。請參見13.2.8.11節,“把子查詢作為用于早期MySQL版本的聯合進行改寫”

·         把子句從子查詢的外部轉移到內部。例如,使用此查詢:

·                SELECT * FROM t1
·                WHERE s1 IN (SELECT s1 FROM t1 UNION ALL SELECT s1 FROM t2);

代替此查詢:

SELECT * FROM t1
WHERE s1 IN (SELECT s1 FROM t1) OR s1 IN (SELECT s1 FROM t2);

另一個例子是,使用此查詢:

SELECT (SELECT column1 + 5 FROM t1) FROM t2;

代替此查詢:

SELECT (SELECT column1 FROM t1) + 5 FROM t2;

·         使用行子查詢,代替關聯子查詢。舉例說明,使用此查詢:

·                SELECT * FROM t1
·                WHERE (column1,column2) IN (SELECT column1,column2 FROM t2);

代替此查詢:

SELECT * FROM t1
WHERE EXISTS (SELECT * FROM t2 WHERE t2.column1=t1.column1
AND t2.column2=t1.column2);

·         Use NOT (a = ANY (...)) rather than a <> ALL (...).

·         Use x = ANY (table containing (1,2)) rather than x=1 OR x=2.

·         Use = ANY rather than EXISTS.

·         對于只返回一行的無關聯子查詢,IN的速度慢于=。舉例說明,使用此查詢:

·                SELECT * FROM t1 WHERE t1.col_name
·                = (SELECT a FROM t2 WHERE b = some_const);

代替此查詢:

SELECT * FROM t1 WHERE t1.col_name
IN (SELECT a FROM t2 WHERE b = some_const);

使用這些技巧可以使程序更快或更慢。使用BENCHMARK()函數等MySQL工具,您可以了解到在您所處的情況下,哪些技巧會有幫助。

MySQL本身進行的部分優化包括:

·         MySQL只執行一次無關聯子查詢。使用EXPLAIN確認給定的子查詢確實是無關聯的。

·         MySQL改寫IN, ALL, ANYSOME子查詢,目的是如果子查詢中的select-list列已編制索引,則能發揮出此優勢。

·         MySQL使用index-lookup函數代替以下格式的子查詢。EXPLAIN把此函數描述為特殊的聯合類型(unique_subqueryindex_subquery):

·                ... IN (SELECT indexed_column FROM single_table ...)

·         當表達式中不包含NULL值或空集時,MySQL使用一個包含MIN()MAX()的表達式,對以下格式的表達式進行擴展:

·                value {ALL|ANY|SOME} {> | < | >= | <=} (non-correlated subquery)

例如,本WHERE子句:

WHERE 5 > ALL (SELECT x FROM t)

可以用優化符進行如下處理:

WHERE 5 > (SELECT MAX(x) FROM t)

MySQL內部手冊中有一章名為“MySQL如何轉換子查詢”,可以從http://dev.mysql.com/doc/獲取。

13.2.8.11. 把子查詢作為用于早期MySQL版本的聯合進行改寫

在較早版本的MySQL中(早于MySQL 4.1),只支持INSERT...SELECTREPLACE...SELECT...格式的帶嵌套的查詢。雖然在MySQL 5.1中沒有這種情況,但有時,仍然有其它的方法測試一組值的從屬關系。并且,在有些情況下,不僅可以在沒有子查詢時對查詢進行改寫,而且有時使用這些方法比使用子查詢效率更高。這些方法之一是IN()結構:

舉例說明,本查詢:

SELECT * FROM t1 WHERE id IN (SELECT id FROM t2);

可以被改寫為:

SELECT DISTINCT t1.* FROM t1, t2 WHERE t1.id=t2.id;

以下查詢:

SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2);
SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);

也可以使用IN()進行改寫:

SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id
WHERE table2.id IS NULL;

LEFT [OUTER] JOIN可以比對應的子查詢更快,因為服務器可能對其進行更好的優化——這一點對于單獨的MySQL服務器并不明確。在SQL-92之前,不存在外部聯合,因此在做某些事情時,子查詢是唯一的方法。現在,MySQL服務器和其它許多先進的數據庫系統都能提供多種的外部聯合類型。

MySQL支持multiple-table DELETE語句,該語句可以被用于高效地刪除行。刪除時依據來自一個表或同時來自多個表的信息。同時也支持Multiple-table UPDATE語句。

13.2.9.?TRUNCATE語法

TRUNCATE [TABLE] tbl_name

TRUNCATE TABLE用于完全清空一個表。從邏輯上說,該語句與用于刪除所有行的DELETE語句等同,但是在有些情況下,兩者在使用上有所不同。

對于InnoDB表,如果有需要引用表的外鍵限制,則TRUNCATE TABLE被映射到DELETE上;否則使用快速刪減(取消和重新創建表)。使用TRUNCATE TABLE重新設置AUTO_INCREMENT計數器,設置時不考慮是否有外鍵限制。

對于其它存儲引擎,在MySQL 5.1中,TRUNCATE TABLEDELETE FROM有以下幾處不同:

·         刪減操作會取消并重新創建表,這比一行一行的刪除行要快很多。

·         刪減操作不能保證對事務是安全的;在進行事務處理和表鎖定的過程中嘗試進行刪減,會發生錯誤。

·         被刪除的行的數目沒有被返回。

·         只要表定義文件tbl_name.frm是合法的,則可以使用TRUNCATE TABLE把表重新創建為一個空表,即使數據或索引文件已經被破壞。

·         表管理程序不記得最后被使用的AUTO_INCREMENT值,但是會從頭開始計數。即使對于MyISAMInnoDB也是如此。MyISAMInnoDB通常不再次使用序列值。

·         當被用于帶分區的表時,TRUNCATE TABLE會保留分區;即,數據和索引文件被取消并重新創建,同時分區定義(.par)文件不受影響。

TRUNCATE TABLE是在MySQL中采用的一個Oracle SQL擴展。

13.2.10.?UPDATE語法

Single-table語法:

UPDATE [LOW_PRIORITY] [IGNORE] tbl_name
    SET col_name1=expr1 [, col_name2=expr2 ...]
    [WHERE where_definition]
    [ORDER BY ...]
    [LIMIT row_count]

Multiple-table語法:

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1=expr1 [, col_name2=expr2 ...]
    [WHERE where_definition]

UPDATE語法可以用新值更新原有表行中的各列。SET子句指示要修改哪些列和要給予哪些值。WHERE子句指定應更新哪些行。如果沒有WHERE子句,則更新所有的行。如果指定了ORDER BY子句,則按照被指定的順序對行進行更新。LIMIT子句用于給定一個限值,限制可以被更新的行的數目。

UPDATE語句支持以下修飾符:

·         如果您使用LOW_PRIORITY關鍵詞,則UPDATE的執行被延遲了,直到沒有其它的客戶端從表中讀取為止。

·         如果您使用IGNORE關鍵詞,則即使在更新過程中出現錯誤,更新語句也不會中斷。如果出現了重復關鍵字沖突,則這些行不會被更新。如果列被更新后,新值會導致數據轉化錯誤,則這些行被更新為最接近的合法的值。

如果您在一個表達式中通過tbl_name訪問一列,則UPDATE使用列中的當前值。例如,以下語句把年齡列設置為比當前值多一:

mysql> UPDATE persondata SET age=age+1;

UPDATE賦值被從左到右評估。例如,以下語句對年齡列加倍,然后再進行增加:

mysql> UPDATE persondata SET age=age*2, age=age+1;

如果您把一列設置為其當前含有的值,則MySQL會注意到這一點,但不會更新。

如果您把被已定義為NOT NULL的列更新為NULL,則該列被設置到與列類型對應的默認值,并且累加警告數。對于數字類型,默認值為0;對于字符串類型,默認值為空字符串('');對于日期和時間類型,默認值為“zero”值。

UPDATE會返回實際被改變的行的數目。Mysql_info() C API函數可以返回被匹配和被更新的行的數目,以及在UPDATE過程中產生的警告的數量。

您可以使用LIMIT row_count來限定UPDATE的范圍。LIMIT子句是一個與行匹配的限定。只要發現可以滿足WHERE子句的row_count行,則該語句中止,不論這些行是否被改變。

如果一個UPDATE語句包括一個ORDER BY子句,則按照由子句指定的順序更新行。

您也可以執行包括多個表的UPDATE操作。table_references子句列出了在聯合中包含的表。該語法在13.2.7.1節,“JOIN語法”中進行了說明。以下是一個例子:

UPDATE items,month SET items.price=month.price
WHERE items.id=month.id;

以上的例子顯示出了使用逗號操作符的內部聯合,但是multiple-table UPDATE語句可以使用在SELECT語句中允許的任何類型的聯合,比如LEFT JOIN

注釋:您不能把ORDER BYLIMITmultiple-table UPDATE同時使用。

在一個被更改的multiple-table UPDATE中,有些列被引用。您只需要這些列的UPDATE權限。有些列被讀取了,但是沒被修改。您只需要這些列的SELECT權限。

如果您使用的multiple-table UPDATE語句中包含帶有外鍵限制的InnoDB表,則MySQL優化符處理表的順序可能與上下層級關系的順序不同。在此情況下,語句無效并被 回滾。同時,更新一個單一表,并且依靠ON UPDATE功能。該功能由InnoDB提供,用于對其它表進行相應的修改。請參見15.2.6.4節,“FOREIGN KEY約束”

目前,您不能在一個子查詢中更新一個表,同時從同一個表中選擇。

13.3. MySQL實用工具語句

13.3.1.?DESCRIBE語法(獲取有關列的信息)

{DESCRIBE | DESC} tbl_name [col_name | wild]

DESCRIBE可以提供有關表中各列的信息。它是SHOW COLUMNS FROM的快捷方式。這些語句也可以顯示語句,用于閱覽。

13.5.4.3節,“SHOW COLUMNS語法”

col_name可以是一個列名稱,或一個包含‘%’和‘_’的通配符的字符串,用于獲得對于帶有與字符串相匹配的名稱的各列的輸出。沒有必要在引號中包含字符串,除非其中包含空格或其它特殊字符。

mysql> DESCRIBE city;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name       | char(35) | NO   |     |         |                |
| Country    | char(3)  | NO   | UNI |         |                |
| District   | char(20) | YES  | MUL |         |                |
| Population | int(11)  | NO   |     | 0       |                |
+------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

NULL字段指示是否NULL可以被存儲在列中。

Key字段指示是否該列已編制索引。PRI的值指示該列是表的主鍵的一部分。UNI指示,該列是UNIQUE索引的一部分。MUL值指示,在列中某個給定值多次出現是允許的。

MUL將被顯示在UNIQUE索引中,原因之一是多個列會組合成一個復合UNIQUE索引;盡管列的組合是唯一的,但每個列仍可以多次出現同一個給定值。注意,在復合索引中,只有索引最左邊的列可以進入Key字段中。

默認字段指示,默認值被賦予該列。

Extra字段包含可以獲取的與給定列有關的附加信息。在我們的例子中,Extra字段指示,Id列使用AUTO_INCREMENT關鍵詞創建。

如果列類型與您預計的依據CREATE TABLE語句得出的列類型不同,則請注意,MySQL有時會改變列類型。請參見13.1.5.1節,“沉寂的列規格變更”

DESCRIBE語句被設立出來,用于與Oracle相兼容。

SHOW CREATE TABLESHOW TABLE STATUS語句也可以提供有關表的信息。請參見13.5.4節,“SHOW語法”

13.3.2.?USE語法

USE db_name

USE db_name語句可以通告MySQLdb_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數據庫訪問作者表,并從db2數據庫訪問編輯表:

mysql> USE db1;
mysql> SELECT author_name,editor_name FROM author,db2.editor
    ->        WHERE author.editor_id = db2.editor.editor_id;

USE語句被設立出來,用于與Sybase相兼容。

13.4. MySQL事務處理和鎖定語句

MySQL通過SET AUTOCOMMIT, START TRANSACTION, COMMITROLLBACK等語句支持本地事務(在給定的客戶端連接中)。請參見13.4.1節,“START TRANSACTION, COMMIT和ROLLBACK語法”XA事務支持還可以允許MySQL參與分布式事務。請參見13.4.7節,“XA事務”

13.4.1.?START TRANSACTION, COMMIT和ROLLBACK語法

START TRANSACTION | BEGIN [WORK]
COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE]
SET AUTOCOMMIT = {0 | 1}

START TRANSACTIONBEGIN語句可以開始一項新的事務。COMMIT可以提交當前事務,是變更成為永久變更。ROLLBACK可以 回滾當前事務,取消其變更。SET AUTOCOMMIT語句可以禁用或啟用默認的autocommit模式,用于當前連接。

自選的WORK關鍵詞被支持,用于COMMITRELEASE,與CHAINRELEASE子句。CHAINRELEASE可以被用于對事務完成進行附加控制。Completion_type系統變量的值決定了默認完成的性質。請參見5.3.3節,“服務器系統變量”

AND CHAIN子句會在當前事務結束時,立刻啟動一個新事務,并且新事務與剛結束的事務有相同的隔離等級。RELEASE子句在終止了當前事務后,會讓服務器斷開與當前客戶端的連接。包含NO關鍵詞可以抑制CHAINRELEASE完成。如果completion_type系統變量被設置為一定的值,使連鎖或釋放完成可以默認進行,此時NO關鍵詞有用。

默認情況下,MySQL采用autocommit模式運行。這意味著,當您執行一個用于更新(修改)表的語句之后,MySQL立刻把更新存儲到磁盤中。

如果您正在使用一個事務安全型的存儲引擎(如InnoDB, BDBNDB簇),則您可以使用以下語句禁用autocommit模式:

SET AUTOCOMMIT=0;

通過把AUTOCOMMIT變量設置為零,禁用autocommit模式之后,您必須使用COMMIT把變更存儲到磁盤中,或著如果您想要忽略從事務開始進行以來做出的變更,使用ROLLBACK

如果您想要對于一個單一系列的語句禁用autocommit模式,則您可以使用START TRANSACTION語句:

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET [email protected] WHERE type=1;
COMMIT;

使用START TRANSACTIONautocommit仍然被禁用,直到您使用COMMITROLLBACK結束事務為止。然后autocommit模式恢復到原來的狀態。

BEGINBEGIN WORK被作為START TRANSACTION的別名受到支持,用于對事務進行初始化。START TRANSACTION是標準的SQL語法,并且是啟動一個ad-hoc事務的推薦方法。BEGIN語句與BEGIN關鍵詞的使用不同。BEGIN關鍵詞可以啟動一個BEGIN...END復合語句。后者不會開始一項事務。請參見20.2.7節,“BEGIN ... END復合語句”

您也可以按照如下方法開始一項事務:

START TRANSACTION WITH CONSISTENT SNAPSHOT;

WITH CONSISTENT SNAPSHOT子句用于啟動一個一致的讀取,用于具有此類功能的存儲引擎。目前,該子句只適用于InnoDB。該子句的效果與發布一個START TRANSACTION,后面跟一個來自任何InnoDB表的SELECT的效果一樣。請參見15.2.10.4節,“一致的非鎖定讀”

開始一項事務會造成一個隱含的UNLOCK TABLES被執行。

為了獲得最好的結果,事務應只使用由單一事務存儲引擎管理的表執行。否則,會出現以下問題:

·         如果您使用的表來自多個事務安全型存儲引擎(例如InnoDBBDB),并且事務隔離等級不是SERIALIZABLE,則有可能當一個事務提交時,其它正在進行中的、使用同樣的表的事務將只會發生由第一個事務產生的變更。也就是,用混合引擎不能保證事務的原子性,并會造成不一致。(如果混合引擎事務不經常有,則您可以根據需要使用SET TRANSACTION ISOLATION LEVEL把隔離等級設置到SERIALIZABLE。)

·         如果您在事務中使用非事務安全型表,則對這些表的任何變更被立刻存儲,不論autocommit模式的狀態如何。

如果您在更新了事務中一個事務表之后,發布一個ROLLBACK語句,則會出現一個ER_WARNING_NOT_COMPLETE_ROLLBACK警告。對事務安全型表的變更被 回滾,但是對非事務安全型表沒有變更。

每個事務被存儲在一個組塊中的二進制日志中,在COMMIT之上。被回滾的事務不被計入日志。(例外情況:對非事務表的更改不會被 回滾。如果一個被回滾的事務包括對非事務表的更改,則整個事務使用一個在末端的ROLLBACK語句計入日志,以確保對這些表的更改進行復制。)見5.11.3節,“二進制日志”

您可以使用SET TRANSACTION ISOLATION LEVEL更改事務的隔離等級。請參見13.4.6節,“SET TRANSACTION語法”

回滾可以慢速運行。在用戶沒有明確要求時,也可以進行回滾(例如,當錯誤發生時)。因此,在明確地和隱含的(ROLLBACK SQL命令)回滾時,SHOW PROCESSLIST會在Stage列中顯示Rolling back,用于連接。

13.4.2. 不能回滾的語句

有些語句不能被回滾。通常,這些語句包括數據定義語言(DDL)語句,比如創建或取消數據庫的語句,和創建、取消或更改表或存儲的子程序的語句。

您在設計事務時,不應包含這類語句。如果您在事務的前部中發布了一個不能被回滾的語句,則后部的其它語句會發生錯誤,在這些情況下,通過發布ROLLBACK語句不能 回滾事務的全部效果。

13.4.3. 會造成隱式提交的語句

以下語句(以及同義詞)均隱含地結束一個事務,似乎是在執行本語句前,您已經進行了一個COMMIT

·         ALTER FUNCTION, ALTER PROCEDURE, ALTER TABLE, BEGIN, CREATE DATABASE, CREATE FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, DROP DATABASE, DROP FUNCTION, DROP INDEX, DROP PROCEDURE, DROP TABLE, LOAD MASTER DATA, LOCK TABLES, RENAME TABLE, SET AUTOCOMMIT=1, START TRANSACTION, TRUNCATE TABLE, UNLOCK TABLES.

·         當當前所有的表均被鎖定時,UNLOCK TABLES可以提交事務。

·         CREATE TABLE, CREATE DATABASE DROP DATABASE, TRUNCATE TABLE, ALTER FUNCTION, ALTER PROCEDURE, CREATE FUNCTION, CREATE PROCEDURE, DROP FUNCTIONDROP PROCEDURE等語句會導致一個隱含提交。

·         InnoDB中的CREATE TABLE語句被作為一個單一事務進行處理。這意味著,來自用戶的ROLLBACK不會撤銷用戶在事務處理過程中創建的CREATE TABLE語句。

事務不能被嵌套。這是隱含COMMIT的結果。當您發布一個START TRANSACTION語句或其同義詞時,該COMMIT被執行,用于任何當前事務。

13.4.4.?SAVEPOINT和ROLLBACK TO SAVEPOINT語法

SAVEPOINT identifier
ROLLBACK [WORK] TO SAVEPOINT identifier
RELEASE SAVEPOINT identifier

InnoDB支持SQL語句SAVEPOINT, ROLLBACK TO SAVEPOINT, RELEASE SAVEPOINT和自選的用于ROLLBACKWORK關鍵詞。

SAVEPOINT語句用于設置一個事務保存點,帶一個標識符名稱。如果當前事務有一個同樣名稱的保存點,則舊的保存點被刪除,新的保存點被設置。

ROLLBACK TO SAVEPOINT語句會向以命名的保存點回滾一個事務。如果在保存點被設置后,當前事務對行進行了更改,則這些更改會在 回滾中被撤銷。但是,InnoDB不會釋放被存儲在保存點之后的存儲器中的行鎖定。(注意,對于新插入的行,鎖定信息被存儲在行中的事務ID承載;鎖定沒有被分開存儲在存儲器中。在這種情況下,行鎖定在撤銷中被釋放。)在被命名的保存點之后設置的保存點被刪除。

如果語句返回以下錯誤,則意味著不存在帶有指定名稱的保存點:

ERROR 1181: Got error 153 during ROLLBACK

RELEASE SAVEPOINT語句會從當前事務的一組保存點中刪除已命名的保存點。不出現提交或 回滾。如果保存點不存在,會出現錯誤。

如果您執行COMMIT或執行不能命名保存點的ROLLBACK,則當前事務的所有保存點被刪除。

13.4.5.?LOCK TABLES和UNLOCK TABLES語法

LOCK TABLES
    tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}
    [, tbl_name [AS alias] {READ [LOCAL] | [LOW_PRIORITY] WRITE}] ...
UNLOCK TABLES

LOCK TABLES可以鎖定用于當前線程的表。如果表被其它線程鎖定,則造成堵塞,直到可以獲取所有鎖定為止。UNLOCK TABLES可以釋放被當前線程保持的任何鎖定。當線程發布另一個LOCK TABLES時,或當與服務器的連接被關閉時,所有由當前線程鎖定的表被隱含地解鎖。

  表鎖定只用于防止其它客戶端進行不正當地讀取和寫入。保持鎖定(即使是讀取鎖定)的客戶端可以進行表層級的操作,比如DROP TABLE

注意,下面是對事務表使用LOCK TABLES的說明:

·         在嘗試鎖定表之前,LOCK TABLES不是事務安全型的,會隱含地提交所有活性事務。同時,開始一項事務(例如,使用START TRANSACTION),會隱含地執行UNLOCK TABLES。(見13.4.3節,“會造成隱式提交的語句”

·         對事務表(如InnoDB)使用LOCK TABLES的正確方法是,設置AUTOCOMMIT=0并且不能調用UNLOCK TABLES,直到您明確地提交事務為止。當您調用LOCK TABLES時,InnoDB會內部地取其自己的表鎖定,MySQL取其自己的表鎖定。InnoDB在下一個提交時釋放其表鎖定,但是,對于MySQL,要釋放表鎖定,您必須調用UNLOCK TABLES。您不應該讓AUTOCOMMIT=1,因為那樣的話,InnoDB會在調用LOCK TABLES之后立刻釋放表鎖定,并且很容易形成死鎖定。注意,如果AUTOCOMMIT=1,我們根本不能獲取InnoDB表鎖定,這樣就可以幫助舊的應用軟件避免不必要的死鎖定。

·         ROLLBACK不會釋放MySQL的非事務表鎖定。

要使用LOCK TABLES,您必須擁有相關表的LOCK TABLES權限和SELECT權限。

使用LOCK TABLES的主要原因是仿效事務,或在更新表時加快速度。這將在后面進行更詳細的解釋。

如果一個線程獲得對一個表地READ鎖定,該線程(和所有其它線程)只能從該表中讀取。如果一個線程獲得對一個表的WRITE鎖定,只有保持鎖定的線程可以對表進行寫入。其它的線程被阻止,直到鎖定被釋放時為止。

READ LOCALREAD之間的區別是,READ LOCAL允許在鎖定被保持時,執行非沖突性INSERT語句(同時插入)。但是,如果您正打算在MySQL外面操作數據庫文件,同時您保持鎖定,則不能使用READ LOCAL。對于InnoDB表,READ LOCALREAD相同。

當您使用LOCK TABLES時,您必須鎖定您打算在查詢中使用的所有的表。雖然使用LOCK TABLES語句獲得的鎖定仍然有效,但是您不能訪問沒有被此語句鎖定的任何的表。同時,您不能在一次查詢中多次使用一個已鎖定的表——使用別名代替,在此情況下,您必須分別獲得對每個別名的鎖定。

mysql> LOCK TABLE t WRITE, t AS t1 WRITE;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;

如果您的查詢使用一個別名引用一個表,那么您必須使用同樣的別名鎖定該表。如果沒有指定別名,則不會鎖定該表。

mysql> LOCK TABLE t READ;
mysql> SELECT * FROM t AS myalias;
ERROR 1100: Table 'myalias' was not locked with LOCK TABLES

相反的,如果您使用一個別名鎖定一個表,您必須使用該別名在您的查詢中引用該表。

mysql> LOCK TABLE t AS myalias READ;
mysql> SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> SELECT * FROM t AS myalias;

WRITE鎖定通常比READ鎖定擁有更高的優先權,以確保更新被盡快地處理。這意味著,如果一個線程獲得了一個READ鎖定,則另一個線程會申請一個WRITE鎖定,后續的READ鎖定申請會等待,直到WRITE線程獲得鎖定并釋放鎖定。您可以使用LOW_PRIORITY WRITE鎖定來允許其它線程在該線程正在等待WRITE鎖定時獲得READ鎖定。只有當您確定最終將有一個時機,此時沒有線程擁有READ鎖定時,您才應該使用LOW_PRIORITY WRITE鎖定。

LOCK TABLES按照如下方式執行:

1.    按照內部定義的順序,對所有要被鎖定的表進行分類。從用戶的角度,此順序是未經定義的。

2.    如果使用一個讀取和一個寫入鎖定對一個表進行鎖定,則把寫入鎖定放在讀取鎖定之前。

3.    一次鎖定一個表,直到線程得到所有鎖定為止。

該規則確保表鎖定不會出現死鎖定。但是,對于該規則,您需要注意其它的事情:

如果您正在對一個表使用一個LOW_PRIORITY WRITE鎖定,這只意味著,MySQL等待特定的鎖定,直到沒有申請READ鎖定的線程時為止。當線程已經獲得WRITE鎖定,并正在等待得到鎖定表清單中的用于下一個表的鎖定時,所有其它線程會等待WRITE鎖定被釋放。如果這成為對于應用程序的嚴重的問題,則您應該考慮把部分表轉化為事務安全型表。

您可以安全地使用KILL來結束一個正在等待表鎖定的線程。請參見13.5.5.3節,“KILL語法”

注意,您不能使用INSERT DELAYED鎖定任何您正在使用的表,因為,在這種情況下,INSERT由另一個線程執行。

通常,您不需要鎖定表,因為所有的單個UPDATE語句都是原子性的;沒有其它的線程可以干擾任何其它當前正在執行的SQL語句。但是,在幾種情況下,鎖定表會有好處:

·         如果您正在對一組MyISAM表運行許多操作,鎖定您正在使用的表,可以快很多。鎖定MyISAM表可以加快插入、更新或刪除的速度。不利方面是,沒有線程可以更新一個用READ鎖定的表(包括保持鎖定的表),也沒有線程可以訪問用WRITE鎖定的表(除了保持鎖定的表以外)。

有些MyISAM操作在LOCK TABLES之下更快的原因是,MySQL不會清空用于已鎖定表的關鍵緩存,直到UNLOCK TABLE被調用為止。通常,關鍵緩存在每個SQL語句之后被清空。

·         如果您正在使用MySQL中的一個不支持事務的存儲引擎,則如果您想要確定在SELECTUPDATE之間沒有其它線程,您必須使用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,有可能另一個線程會在執行SELECTUPDATE語句之間在trans表中插入一個新行。

通過使用相對更新(UPDATE customer SET value=value+new_value)或LAST_INSERT_ID()函數,您可以在許多情況下避免使用LOCK TABLES。請參見1.8.5.3節,“事務和原子操作”

通過使用用戶層級的顧問式鎖定函數GET_LOCK()RELEASE_LOCK(),您也可以在有些情況下避免鎖定表。這些鎖定被保存在服務器中的一個混編表中,使用pthread_mutex_lock() pthread_mutex_unlock(),以加快速度。請參見12.9.4節,“其他函數”

要了解更多有關鎖定規則的說明,請參見7.3.1節,“鎖定方法”

您可以使用FLUSH TABLES WITH READ LOCK語句鎖定位于所有帶有讀取鎖定的數據庫中的所有表。請參見13.5.5.2節,“FLUSH語法”。如果您有一個可以及時拍攝快照的文件系統,比如Veritas,這是獲得備份的一個非常方便的方式。

注釋:如果您對一個已鎖定的表使用ALTER TABLE,該表可能會解鎖。請參見A.7.1節,“與ALTER TABLE有關的問題”

13.4.6.?SET TRANSACTION語法

SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }

本語句用于設置事務隔離等級,用于下一個事務,或者用于當前會話。

在默認情況下,SET TRANSACTION會為下一個事務(還未開始)設置隔離等級。如果您使用GLOBAL關鍵詞,則語句會設置全局性的默認事務等級,用于從該點以后創建的所有新連接。原有的連接不受影響。要進行此操作,您需要SUPER權限。使用SESSION關鍵測可以設置默認事務等級,用于對當前連接執行的所有將來事務。

要了解對每個InnoDB事務隔離等級的描述,請參見15.2.10.3節,“InnoDB和TRANSACTION ISOLATION LEVEL”InnoDB支持MySQL 5.1中的各個等級。默認的等級是REPEATABLE READ

您可以使用--transaction-isolation選項,對mysqld設置初始的默認全局隔離等級。請參見5.3.1節,“mysqld命令行選項”

13.4.7. XA事務

對于InnoDB存儲引擎,可以獲得對XA事務的支持。MySQL XA的執行依據X/Open CAE文件Distributed Transaction Processing: The XA Specification。本文件由Open Group出版,可以從http://www.opengroup.org/public/pubs/catalog/c193.htm獲取。在I.5節,“對XA事務的限制”對當前XA執行的限制進行了描述。

在客戶端方面,沒有特殊要求。連接MySQL服務器的XA接口由以XA關鍵詞開頭的SQL語句組成。MySQL客戶端必須能發送SQL語句,并能理解XA語句接口的語義,但是它們不需要被鏈接到特定的MySQL客戶庫上。

當前,在MySQL連接器當中,MySQL連接器/J 5.0.0直接支持XA(也就是,通過一個可以控制XA SQL語句接口的等級接口)。

XA支持分布式的事務,具備能力,讓多個獨立的事務資源參加全局的事務。事務資源通常是RDBMSs,不過也可以是其它種類的資源。

一個全局事務會涉及到多個行動,這些行動本身是事務性的。不過,所有行動都必須作為一個群組成功完成,或者作為一個群組被回滾。實際上,這會延伸ACID性質,“提高等級”,這樣,多個ACID事務就可以一起執行,相當于也擁有ACID性質的全局操作的組件。(但是,對于一個分布式事務,您必須使用SERAILIZABLE隔離等級,以實現ACID性質。對于一個非分布式事務,使用REPEATABLE READ就足夠了。但是對于分布式事務,使用REPEATABLE READ是不夠的。)

分布式事務的部分示例:

·         應用程序相當于一個把消息傳遞服務和RDBMS組合在一起的整合工具。應用程序可以確保,所有進行消息發送、回收和處理的事務(同時包含一個事務數據庫)均在一個全局事務中發生。您可以把這看作是“事務電子郵件。”

·         應用程序執行的行動會涉及到不同數據庫服務器,比如MySQL服務器和Oracle服務器(或多個MySQL服務器)。涉及到多個服務器的行動必須作為一個全局事務的一部分發生,而不是作為針對每個服務器的獨立的本地事務發生。

·         銀行把帳戶信息保存在RDBMS中,并通過自動取款機(ATMs)分發和收取欠款。必須要確保ATM行動被正確地反映到帳戶中,但是這不能只由RDBMS單獨完成。全局事務管理器會整合ATM和數據庫資源,以確保財務事務的整體一致性。

使用全局事務的應用程序涉及一個或多個資源管理器和一個事務管理器:

·         資源管理器(RM)用于提供通向事務資源的途徑。數據庫服務器是一種資源管理器。該管理器必須可以提交或 回滾由RM管理的事務。

·         事務管理器(TM)用于協調作為一個全局事務一部分的事務。TM與管理每個事務的RMs進行通訊。一個全局事務中各個單個事務均是全局事務的“分支”。全局事務和各分支通過一種命名方法進行標識。這種命名方法在后面進行講述。

MySQL執行XA MySQL時,MySQL服務器相當于一個用于管理全局事務中的XA事務的資源管理器。與MySQL服務器連接的客戶端相當于事務管理器。

要執行一個全局事務,必須知道涉及到了哪些組件,并且把每個組件引到一點,在此時,組件可以被提交或回滾時。根據每個組件報告的有關組件效能的內容,這些組件必須作為一個原子性群組全部提交或 回滾。即,要么所有的組件必須提交,要么所有的組件必須回滾。要管理一個全局事務,必須要考慮任何組件或連接網絡可能會故障。

用于執行全局事務的過程使用兩階段提交(2PC),發生時間在由全局事務的分支進行的行動已經被執行之后。

1.    在第一階段,所有的分支被預備好。即,它們被TM告知要準備提交。通常,這意味著用于管理分支的每個RM會記錄對于被穩定保存的分支的行動。分支指示是否它們可以這么做。這些結果被用于第二階段。

2.    在第二階段,TM告知RMs是否要提交或 回滾。如果在預備分支時,所有的分支指示它們將能夠提交,則所有的分支被告知要提交。如果在預備時,有任何分支指示它將不能提交,則所有分支被告知 回滾。

在有些情況下,一個全局事務可能會使用一階段提交(1PC)。例如,當一個事務管理器發現,一個全局事務只由一個事務資源組成(即,單一分支),則該資源可以被告知同時進行預備和提交。

13.4.7.1. XA事務SQL語法

要在MySQL中執行XA事務,應使用以下語句:

XA {START|BEGIN} xid [JOIN|RESUME]
 
XA END xid [SUSPEND [FOR MIGRATE]]
 
XA PREPARE xid
 
XA COMMIT xid [ONE PHASE]
 
XA ROLLBACK xid
 
XA RECOVER

對于XA STARTJOINRESUME子句不被支持。

對于XA ENDSUSPEND [FOR MIGRATE]子句不被支持。

每個XA語句以XA關鍵詞為開頭,多數語句要求一個xid值。 xid是一個XA事務標識符。它指示該語句適用于哪個事務。xid值由客戶端提供,或由MySQL服務器生成。xid值包含一到三個部分:

xid: gtrid [, bqual [, formatID ]]

gtrid是一個全局事務標識符,bqual是一個分支限定符,formatID是一個數字,用于標識由gtridbqual值使用的格式。根據語法的表示,bqualformatID是自選的。如果沒有給定,默認的bqual值是''。如果沒有給定,默認的fromatID值是1

gtridbqual必須為字符串文字,每個的長度最多為64字節(不是字符)。gtridbqual可以用多種方法指定。您可以使用帶引號的字符串('ab'),十六進制字符串(0x6162, X'ab'),或位值(b'nnnn')

formatID是一個無符號的整數。

通過MySQL服務器的帶下劃線的XA支持子程序,gtridbqual值被理解為以字節為單位。但是,在包含XA語句的SQL語句正在被分析的同時,服務器會去操作一些特定的字符集。為了安全,把gtridbqual作為十六進制字符串寫入。

通常,xid值由事務管理器生成。由一個TM生成的值必須與由其它TMs生成的值不同。一個給定的TM必須能識別自己的xid值。這些值位于由XA RECOVER語句返回的值清單中。

XA START xid用于啟動一個帶給定xid值的XA事務。每個XA事務必須有一個唯一的xid值,因此該值當前不能被其它的XA事務使用。使用gtridbqual值評估唯一性。所有下列的用于XA事務的XA語句必須使用與XA START語句中給定的相同的xid值進行指定。如果您使用這些語句,但是指定的xid值與部分原有的XA事務不對應的話,會發生錯誤。

一項或多項XA事務可以是同一個全局事務的一部分。在一個給定的全局事務中的所有XA事務必須在xid值中使用同樣的gtrid值。出于這個原因,gtrid值必須為全局唯一的,這樣,有關一個給定的XA事務是哪個全局事務的一部分的問題就不會含糊不清。對于一個全局事務中的每個XA事務,xid值中的bqual部分必須不一樣。(bqual值應不一樣,這個要求是當前執行MySQL XA的一個限制條件。這不是XA規約的一部分。)

對于在MySQL服務器上的處于PREPARED狀態的XA事務,XA RECOVER語句會返回信息。(見13.4.7.2節,“XA事務狀態”.。)輸出包括一個行,該行用于服務器上的每個這類XA事務,不論是哪個客戶端啟動了它。

XA RECOVER輸出行看上去像這樣(例如,xid值包括'abc', 'def'7等部分):

mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
|        7 |            3 |            3 | abcdef |
+----------+--------------+--------------+--------+

輸出列有以下意義:

·         formatID是事務xidformatID部分

·         gtrid_lengthxidgtrid部分的長度,以字節為單位

·         bqual_lengthxidbqual部分的長度,以字節為單位

·         dataxidgtrid部分和bqual部分的串聯

13.4.7.2. XA事務狀態

XA事務在以下狀態下進展:

1.    使用XA START來啟動一個XA事務,并把它放入ACTIVE狀態。

2.    對于一個ACTIVE XA事務,發布構成事務的SQL語句,然后發布一個XA END語句。XA END把事務放入IDLE狀態。

3.    對于一個IDLE XA事務,您可以發布一個XA PREPARE語句或一個XA COMMITONE PHASE語句:

·         XA PREPARE把事務放入PREPARED狀態。在此點上的XA RECOVER語句將在其輸出中包括事務的xid值,因為XA RECOVER會列出處于PREPARED狀態的所有XA事務。

·         XA COMMITONE PHASE用于預備和提交事務。xid值將不會被XA RECOVER列出,因為事務終止。

4.    對于一個PREPARED XA事務,您可以發布一個XA COMMIT語句來提交和終止事務,或者發布XA ROLLBACK來回滾并終止事務。

下面是一個簡單的XA事務,該事務把一行作為一個全局事務的一部分插入一個表中。

mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)
 
mysql> INSERT INTO mytable (i) VALUES(10);
Query OK, 1 row affected (0.04 sec)
 
mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)
 
mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.00 sec)
 
mysql> XA COMMIT 'xatest';
Query OK, 0 rows affected (0.00 sec)

根據一個給定的客戶端連接的語境,XA事務和本地(非XA)事務互相排斥。舉例說明,如果已經發布了XA START來開始一項XA事務,則本地事務不會被啟動,直到XA事務已經被提交或被 回滾為止。相反的,如果已經使用START TRANSACTION啟動一個本地事務,則XA語句不能被使用,直到該事務被提交或被 回滾為止。

13.5. 數據庫管理語句

13.5.1. 賬戶管理語句

13.5.1.1.?CREATE USER語法

CREATE USER user [IDENTIFIED BY [PASSWORD] 'password']
    [, user [IDENTIFIED BY [PASSWORD] 'password']] ...

CREATE USER用于創建新的MySQL賬戶。要使用CREATE USER,您必須擁有mysql數據庫的全局CREATE USER權限,或擁有INSERT權限。對于每個賬戶,CREATE USER會在沒有權限的mysql.user表中創建一個新記錄。如果 賬戶已經存在,則出現錯誤。

使用自選的IDENTIFIED BY子句,可以為賬戶給定一個密碼。user值和 密碼的給定方法和GRANT語句一樣。特別是,要在純文本中指定密碼,需忽略PASSWORD關鍵詞。要把 密碼指定為由PASSWORD()函數返回的混編值,需包含關鍵字PASSWORD。請參見13.5.1.3節,“GRANT和REVOKE語法”

13.5.1.2.?DROP USER語法

DROP USER user [, user] ...

DROP USER語句用于刪除一個或多個MySQL賬戶。要使用DROP USER,您必須擁有mysql數據庫的全局CREATE USER權限或DELETE權限。使用與GRANTREVOKE相同的格式為每個 賬戶命名;例如,'jeffrey'@'localhost'。 賬戶名稱的用戶和主機部分與用戶表記錄的UserHost列值相對應。

使用DROP USER,您可以取消一個賬戶和其權限,操作如下:

DROP USER user;

該語句可以刪除來自所有授權表的帳戶權限記錄。

要點:DROP USER不能自動關閉任何打開的用戶對話。而且,如果用戶有打開的對話,此時取消用戶,則命令不會生效,直到用戶對話被關閉后才生效。一旦對話被關閉,用戶也被取消,此用戶再次試圖登錄時將會失敗。這是有意設計的。

13.5.1.3.?GRANT和REVOKE語法

GRANT priv_type [(column_list)] [, priv_type [(column_list)]] ...
    ON [object_type] {tbl_name | * | *.* | db_name.*}
    TO user [IDENTIFIED BY [PASSWORD] 'password']
        [, user [IDENTIFIED BY [PASSWORD] 'password']] ...
    [REQUIRE
        NONE |
        [{SSL| X509}]
        [CIPHER 'cipher' [AND]]
        [ISSUER 'issuer' [AND]]
        [SUBJECT 'subject']]
    [WITH with_option [with_option] ...]

object_type =
    TABLE
  | FUNCTION
  | PROCEDURE

with_option =
    GRANT OPTION
  | MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONS count
REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ...
    ON [object_type] {tbl_name | * | *.* | db_name.*}
    FROM user [, user] ...

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...

GRANTREVOKE語句允許系統管理員創建MySQL用戶 賬戶,授予權限和撤銷權限。

MySQL賬戶信息存儲在mysql數據庫的表中。在第5章:數據庫管理中對本數據庫和訪問控制系統進行了詳盡的討論。要了解更多詳細信息,您應該查詢此章。

如果授權表擁有含有mixed-case數據庫或表名稱的權限記錄,并且lower_case_table_names系統變量已設置,則不能使用REVOKE撤銷權限,必須直接操縱授權表。(當lower_case_table_names已設置時,GRANT將不會創建此類記錄,但是此類記錄可能已經在設置變量之前被創建了。)

授予的權限可以分為多個層級:

·         全局層級

全局權限適用于一個給定服務器中的所有數據庫。這些權限存儲在mysql.user表中。GRANT ALL ON *.*REVOKE ALL ON *.*只授予和撤銷全局權限。

·         數據庫層級

數據庫權限適用于一個給定數據庫中的所有目標。這些權限存儲在mysql.dbmysql.host表中。GRANT ALL ON db_name.*REVOKE ALL ON db_name.*只授予和撤銷數據庫權限。

·         表層級

表權限適用于一個給定表中的所有列。這些權限存儲在mysql.talbes_priv表中。GRANT ALL ON db_name.tbl_nameREVOKE ALL ON db_name.tbl_name只授予和撤銷表權限。

·         列層級

列權限適用于一個給定表中的單一列。這些權限存儲在mysql.columns_priv表中。當使用REVOKE時,您必須指定與被授權列相同的列。

·         子程序層級

CREATE ROUTINE, ALTER ROUTINE, EXECUTEGRANT權限適用于已存儲的子程序。這些權限可以被授予為全局層級和數據庫層級。而且,除了CREATE ROUTINE外,這些權限可以被授予為子程序層級,并存儲在mysql.procs_priv表中。

當后續目標是一個表、一個已存儲的函數或一個已存儲的過程時,object_type子句應被指定為TABLEFUNCTIONPROCEDURE。當從舊版本的MySQL升級時,要使用本子句,您必須升級您的授權表。請參見2.10.2節,“升級授權表”

要使用GRANTREVOKE,您必須擁有GRANT OPTION權限,并且您必須用于您正在授予或撤銷的權限。

要撤銷所有權限,需使用以下語法。此語法用于取消對于已命名的用戶的所有全局層級、數據庫層級、表層級和列層級的權限。

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] ...

要使用本REVOKE語法,您必須擁有mysql數據庫的全局CREATE USER權限或UPDATE權限。

對于GRANTREVOKE語句,priv_type可以被指定為以下任何一種:

權限

意義

ALL [PRIVILEGES]

設置除GRANT OPTION之外的所有簡單權限

ALTER

允許使用ALTER TABLE

ALTER ROUTINE

更改或取消已存儲的子程序

CREATE

允許使用CREATE TABLE

CREATE ROUTINE

創建已存儲的子程序

CREATE TEMPORARY TABLES

允許使用CREATE TEMPORARY TABLE

CREATE USER

允許使用CREATE USER, DROP USER, RENAME USERREVOKE ALL PRIVILEGES

CREATE VIEW

允許使用CREATE VIEW

DELETE

允許使用DELETE

DROP

允許使用DROP TABLE

EXECUTE

允許用戶運行已存儲的子程序

FILE

允許使用SELECT...INTO OUTFILELOAD DATA INFILE

INDEX

允許使用CREATE INDEXDROP INDEX

INSERT

允許使用INSERT

LOCK TABLES

允許對您擁有SELECT權限的表使用LOCK TABLES

PROCESS

允許使用SHOW FULL PROCESSLIST

REFERENCES

未被實施

RELOAD

允許使用FLUSH

REPLICATION CLIENT

允許用戶詢問從屬服務器或主服務器的地址

REPLICATION SLAVE

用于復制型從屬服務器(從主服務器中讀取二進制日志事件)

SELECT

允許使用SELECT

SHOW DATABASES

SHOW DATABASES顯示所有數據庫

SHOW VIEW

允許使用SHOW CREATE VIEW

SHUTDOWN

允許使用mysqladmin shutdown

SUPER

允許使用CHANGE MASTER, KILL, PURGE MASTER LOGSSET GLOBAL語句,mysqladmin debug命令;允許您連接(一次),即使已達到max_connections

UPDATE

允許使用UPDATE

USAGE

“無權限”的同義詞

GRANT OPTION

允許授予權限

當從舊版本的MySQL升級時,要使用EXECUTE, CREATE VIEW, SHOW VIEW, CREATE USER, CREATE ROUTINEALTER ROUTINE權限,您必須首先升級您的授權表。請參見2.10.2節,“升級授權表”

REFERENCES權限目前未被使用。

當您想要創建一個沒有權限的用戶時,可以指定USAGE

使用SHOW GRANTS來確定帳戶擁有什么權限。請參見13.5.4.10節,“SHOW GRANTS語法”

您可以通過使用ON *.*語法賦予全局權限,或通過使用ON db_name.*語法賦予數據庫層級權限。如果您指定了ON *并且您已經選擇了一個默認數據庫,則權限被賦予到這個數據庫中。(警告:如果您指定了ON *同時您沒有選擇一個默認數據庫,則權限是全局的。)

FILE, PROCESS, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHOW DATABASES, SHUTDOWNSUPER權限是管理性權限,只能進行全局授權(使用ON *.*語法)。

其它權限可以被全局授權,或被賦予為其它層級。

對于一個表,您可以指定的priv_type值只能是SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT OPTION, INDEXALTER

對于一個列(也就是,當您使用一個column_list子句時),您可以指定的priv_type值只能是SELECT, INSERTUPDATE

在子程序層級,您可以指定的priv_type值只能是ALTER ROUTINE, EXECUTEGRANT OPTIONCREATE ROUTINE不是一個子程序層級的權限,因為您必須擁有此權限,才能創建一個子程序。

對于全局、數據庫、表和子程序層級,GRANT ALL只能賦予在您正在授權的層級中存在的權限。例如,如果您使用GRANT ALL ON db_name.*,這是一個數據庫層級語句,因此不會授予全局權限,如FILE等。

MySQL允許您對不存在的數據庫目標授予權限。在此情況下,將被授予的權限必須包括CREATE權限。這個性質是有意設計的,目的是允許數據庫管理員為將在此后被創建的數據庫目標預備用戶 賬戶和權限。

要點:當您取消一個表或數據庫時,MySQL不會自動撤銷任何權限。但是,如果您取消一個子程序,則被賦予該子程序的所有子程序層級的權限都被撤銷。

注意:GRANT語句用于在全局層級或數據庫層級賦予權限。當在GRANT語句中指定數據庫名稱時,允許使用‘_’和‘%’通配符。這意味著,如果您想要使用‘_’字符作為一個數據庫名稱的一部分,您應該在GRANT語句中指定它為‘\_’,以防止用戶可以訪問其它符合此通配符格式的數據庫;例如,GRANT ... ON `foo\_bar`.* TO ...

為了接納對來自任意主機的用戶授權的權利,MySQL支持以user_name@host_name的形式指定user值。如果一個user_namehost_name與一個不加引號的標識符一樣是合法的,那么您不需要對它加引號。不過,要指定一個包含特殊字符(如‘-’)的user_name字符串,或一個包含特殊字符或通配字符(如‘%’),則引號是必要的;例如,'test-user'@'test-hostname'。分別對usernamehostname加引號。

您可以在hostname中指定通配符。例如user_name@'%.loc.gov'適用于在loc.gov域中的任何主機的user_name。同時user_name@'144.155.166.%'適用于144.155.166 C級子網中的任何主機的user_name

簡單形式user_nameuser_name@'%'的同義詞。

MySQL不支持usernames中的通配符。通過把帶有User=''的登錄項插入到mysql.user表中,或通過使用GRANT語句創建一個帶有空名稱的用戶,可以定義匿名用戶:

mysql> GRANT ALL ON test.* TO ''@'localhost' ...

當把帶引號的值是,需使用反勾號(`)為數據庫、表、列和子程序名稱加引號。使用單引號(')hostnamesusernames和 密碼加引號。

警告:如果您允許匿名用戶連接到MySQL服務器,則您應該同時向所有本地用戶授予user_name@localhost權限。否則,當有名稱的用戶試圖從本地機器登錄MySQL服務器時,mysql.user表中的用于localhost的匿名用戶帳戶會被使用。

您可以通過執行以下查詢來確定是否這適合于您。以下查詢列舉了所有匿名用戶:

mysql> SELECT Host, User FROM mysql.user WHERE User='';

如果您想要刪除本地匿名用戶賬戶,以避免出現剛才談到的問題,則需使用以下語句:

mysql> DELETE FROM mysql.user WHERE Host='localhost' AND User='';
mysql> FLUSH PRIVILEGES;

GRANT支持最長為60個字符的hostnames。數據庫、表、列和子程序名稱最長可為64個字符。Usernames最長可為16個字符。 注釋:不能通過更改mysql.user表來改變usernames的允許長度。如果試圖這么做,會導致出現不可預見的問題,可能會造成用戶無法登錄MySQL服務器。除了采用由MySQL公司提供的用于升級MySQL服務器的mysql_fix_privilege_tables原稿之外,請您不要以任何方式變更授權表。

對于表或列的權限是作為各個權限層級的邏輯OR權限被附加形成的。例如,如果mysql.user表指定一個用戶擁有全局SELECT權限,則該權限不能被數據庫、表或列層級的登錄項定義。

可以按下列方法計算列權限:

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges

在多數情況下,您只在一個權限層級下向用戶授予權利,所以壽命通常不是那么復雜。有關權限檢查規程的細節,請參見5.7節,“MySQL訪問權限系統”

如果您對一個在mysql.user表中不存在的username/hostname組合授予權限,則增加一個登錄項并保持在此處,直到使用DELETE語句刪除為止。換句話說,GRANT可以創建用戶表登錄項,但是REVOKE不會取消它們;您必須使用DROP USERDELETE明確地操作。

如果創建了一個新的用戶,或者如果您擁有全局授權權限,則用戶密碼被設置為由IDENTIFIED BY子句指定的密碼(如果給定了一個)。如果用戶已擁有了一個密碼,則此密碼被新密碼替代。

警告:如果您創建了一個新用戶,但是不指定IDENTIFIED BY子句,則用戶沒有 密碼。這是很不安全的。不過,您可以啟用NO_AUTO_CREATE_USER SQL模式,來防止GRANT創建一個新用戶(否則GRANT會這么做),除非給定了IDENTIFIED BY來為新用戶提供一個密碼。

使用SET PASSWORD語句也可以設置密碼。請參見13.5.1.5節,“SET PASSWORD語法”

IDENTIFIED BY子句中,密碼應被作為文字密碼只被給定。沒有必要使用PASSWORD()函數,因為該函數用于SET PASSWORD語句。例如:

GRANT ... IDENTIFIED BY 'mypass';

如果您不想以明白的文字發送密碼,并且您知道PASSWORD()返回給密碼的混編值,則您可以指定混編值,前面加入關鍵詞PASSWORD

GRANT ...
IDENTIFIED BY PASSWORD '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4';

在一個C程序中,您可以通過使用make_scrambled_password() C API函數得到混編值。

如果您為一個數據庫授予權限,則在mysql.db表中,會根據需要創建登錄項。如果使用REVOKE刪除了所有的數據庫權限,則本登錄項被刪除。

如果一個用戶不擁有表權限,則當用戶申請表清單時(例如,使用SHOW TABLES語句),表名稱不顯示。

SHOW DATABASES權限允許賬戶通過發布SHOW DATABASE語句來觀看數據名稱。不擁有此權限的賬戶只能看到他們擁有部分權限的數據庫,并且如果使用--skip-show-database選項啟動服務器,則根本不能使用本語句。

WITH GRANT OPTION子句給予用戶能力,可以在指定的權限層級,向其它用戶給定其擁有的任何權限。您應該留心您給予了誰GRANT OPTION權限,因為擁有不同權限的兩個用戶可以聯合使用權限!

您不能向其它用戶授予您自己沒有的權限;GRANT OPTION權限只允許您賦予您自己擁有的權限。

要注意,當您在某個特定權限層級向一個用戶授予GRANT OPTION權限時,用戶擁有的該層級的任何權限(或未來將被給定的權限)也可以由該用戶授予。假設您向一個用戶賦予了數據庫INSERT權限。如果您然后賦予數據庫SELECT權限,并指定了WITH GRANT OPTION,則該用戶不僅可以向其它用戶給予SELECT權限,還可以給予INSERT。如果您然后向用戶授予數據庫UPDATE權限,則用戶可以授予INSERT, SELECTUPDATE

您不應該向一個常規用戶授予ALTER權限。如果您這么做,則該用戶可以嘗試通過對表重新命名來破壞授權系統!

The MAX_QUERIES_PER_HOUR count, MAX_UPDATES_PER_HOUR count, and MAX_CONNECTIONS_PER_HOUR count options limit the number of queries, updates, and logins a user can perform during any given one-hour period. If count is 0 (the default), this means that there is no limitation for that user.      MAX_QUERIES_PER_HOUR count, MAX_UPDATES_PER_HOUR countMAX_CONNECTIONS_PER_HOUR count選項限制了在任何給定的一小時期間,用戶可以執行的查詢、更新和登錄的數目。如果count0(默認值),這意味著,對該用戶沒有限制。

MAX_USER_CONNECTIONS count選項限制了賬戶可以同時進行的連接的最大數目。如果count0(默認值),則max_user_connections系統可以決定該 賬戶同時連接的數目。

注釋:要對一個原有的用戶指定任何這類資源限制型選項,同時又不影響原有的權限,需使用GRANT USAGE ON *.* ... WITH MAX_...

5.8.4節,“限制賬戶資源”

除了根據username和密碼進行常規鑒定外,MySQL還可以檢查X509證明屬性。要為MySQL賬戶指定與SSL有關的選項,需使用GRANT語句的REQUIRE子句。(要了解有關在MySQL中使用SSL的背景信息,請參見5.8.7節,“使用安全連接”。)

對于一個給定的賬戶,有多種可能性可以限制連接類型:

·         如果賬戶沒有SSLX509要求,并且如果username和 密碼是有效的,則允許不加密連接。但是,如果客戶端有正確的證明和關鍵文件,則根據客戶端的選擇,也可以使用加密連接。

·         REQUIRE SSL選項用于告知服務器,對于該賬戶只允許SSL加密連接。注意,如果有允許任何非SSL連接的訪問控制記錄,則本選項可以被忽略。

·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
·                    -> IDENTIFIED BY 'goodsecret' REQUIRE SSL;

·         REQUIRE X509意味著客戶端必須擁有一個有效證明,除非不需要確切的證明、發布者和主題。唯一的要求是,應可以使用CA證明其中之一來驗證簽名。

·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
·                    -> IDENTIFIED BY 'goodsecret' REQUIRE X509;

·         REQUIRE ISSUER 'issuer'用于對連接嘗試進行限定,客戶端必須出示一個由CAissuer’發布的有效的X509證明。如果客戶端出示的證明是有效的,但是有一個不同的發布者,則服務器會拒絕連接。使用X509證明就意味著要加密,所以在這種情況下,SSL選項是不必要的。

·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
·                    -> IDENTIFIED BY 'goodsecret'
·                    -> REQUIRE ISSUER '/C=FI/ST=Some-State/L=Helsinki/
·                       O=MySQL Finland AB/CN=Tonu Samuel/[email protected]';

注意,ISSUER值應被作為一個單一字符串輸入。

·         REQUIRE SUBJECT 'subject'用于對連接嘗試進行限定,客戶端必須出示一個包含主題subject的有效的X509證明。如果客戶端出示的證明是有效的,但是有一個不同的主題,則服務器會拒絕連接。

·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
·                    -> IDENTIFIED BY 'goodsecret'
·                    -> REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/
·                       O=MySQL demo client certificate/
·                       CN=Tonu Samuel/[email protected]';

注意,SUBJECT值應被作為一個單一字符串輸入。

·         需要REQUIRE CIPHER 'cipher'來確認使用了密碼和足夠長度的關鍵字。如果使用了采用短型加密關鍵字的舊算法,SSL本身會比較脆弱。使用本選項,您可以要求使用特定的密碼方法來許可一個連接。

·                mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
·                    -> IDENTIFIED BY 'goodsecret'
·                    -> REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA';

SUBJECT, ISSUERCIPHER選項可以在REQUIRE子句中結合,如下:

mysql> GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'
    -> IDENTIFIED BY 'goodsecret'
    -> REQUIRE SUBJECT '/C=EE/ST=Some-State/L=Tallinn/
       O=MySQL demo client certificate/
       CN=Tonu Samuel/[email protected]'
    -> AND ISSUER '/C=FI/ST=Some-State/L=Helsinki/
       O=MySQL Finland AB/CN=Tonu Samuel/[email protected]'
    -> AND CIPHER 'EDH-RSA-DES-CBC3-SHA';

注意,SUBJECTISSUER值各自應被作為一個單一字符串輸入。

REQUIRE各選項之間,AND關鍵詞是自選的。

選項的順序無所謂,但是選項不能被指定兩次。

mysqld啟動后,所有的權限被讀入存儲器中。要了解詳細說明,請參見5.7.7節,“權限更改何時生效”

注意,如果您正在使用表權限或列權限,即使只對一個用戶使用,服務器也會對所有用戶檢查表權限和列權限,這會略微降低MySQL的速度。與此類似,如果您對某些用戶限制查詢、更新或連接的數目,則服務器必須監測這些值。

標準SQL版本和MySQL版本的GRANT之間的最大區別是:

·         MySQL中,權限與hostnameusername的組合有關,與 單一的username無關。

·         標準SQL不擁有全局層級或數據庫層級權限,也不支持MySQL支持的所有權限類型。

·         MySQL不支持標準SQL TRIGGERUNDER權限。

·         標準SQL權限以一種分等級的方式進行組織。如果您取消一個用戶,則用戶被授予的所有權限都被撤銷。在MySQL中,如果您使用DROP USER,也會如此。請參見13.5.1.2節,“DROP USER語法”

·         在標準SQL中,當您取消一個表時,對一個表的所有權限會被撤銷。在標準SQL中,當您撤銷一個權限時,根據該權限被授予的所有權限也會被撤銷。在MySQL中,只有使用明確的REVOKE語句,或通過操作存儲在MySQL授權表中的值,才能取消權限。

·         MySQL中,可以只對一個表中的部分列擁有INSERT權限。在此情況下,如果您忽略您不擁有INSERT權限的那些列,,您仍然可以對表執行INSERT語句。如果沒有啟用嚴格的SQL模式,則被忽略的列被設置為各自隱含的默認值。在嚴格模式下,如果某個被忽略的列沒有默認值,則該語句被拒絕。5.3.2節,“SQL服務器模式”對嚴格模式進行了討論。13.1.5節,“CREATE TABLE語法”對隱含默認值進行了討論。

您不擁有INSERT權限的列被設置為各自的默認值。標準SQL要求您擁有所有列的INSERT權限。

MySQL中,如果您只擁有一個表中的部分列的INSERT權限,同時,如果您從INSERT語句中忽略您不擁有權限的列,則您仍然可以對表執行INSERT語句;那些列將被設置為各自的默認值。在嚴格模式下(即當sql_mode='traditional'時,如果某些被忽略的列沒有默認值,則INSERT語句將被拒絕。

13.5.1.4.?RENAME USER語法

RENAME USER old_user TO new_user
    [, old_user TO new_user] ...

RENAME USER語句用于對原有MySQL賬戶進行重命名。要使用RENAME USER,您必須擁有全局CREATE USER權限或mysql數據庫UPDATE權限。如果舊 賬戶不存在或者新賬戶已存在,則會出現錯誤。old_usernew_user值的給定方法與GRANT語句一樣。

13.5.1.5.?SET PASSWORD語法

SET PASSWORD = PASSWORD('some password')
SET PASSWORD FOR user = PASSWORD('some password')

SET PASSWORD語句用于向一個原有MySQL用戶 賬戶賦予一個密碼。

第一個語法為當前用戶設置密碼。已使用一個非匿名賬戶連接到服務器上的任何客戶即都可以更改該賬戶的密碼。

第二個語法為當前服務器主機上的一個特定賬戶設置密碼。只有擁有mysql數據庫UPDATE權限的客戶端可以這么做。user值應以user_name@host_name的格式被給定,此處user_namehost_namemysql.user表登錄項的UserHost列中列出的完全一樣。舉例說明,如果您有一個登錄項,UserHost列值為'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';
mysql> FLUSH PRIVILEGES;

注釋:如果您正在使用一個4.1以前的客戶端連接到一個MySQL 4.1MySQL 4.1以后的服務器,則在閱讀5.7.9節,“MySQL 4.1中的密碼哈希處理”之前,不能使用前面的SET PASSWORDUPDATE語句。 密碼格式在MySQL 4.1中變更了,并且在特定情況下,如果您更改密碼,您可能無法在連接到服務器上。

您可以通過執行SELECT CURRENT_USER()觀看您當前的鑒定[email protected]登錄項。

13.5.2. 表維護語句

13.5.2.1.?ANALYZE TABLE語法

ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

本語句用于分析和存儲表的關鍵字分布。在分析期間,使用一個讀取鎖定對表進行鎖定。這對于MyISAM, BDBInnoDB表有作用。對于MyISAM表,本語句與使用myisamchk -a相當。

MySQL使用已存儲的關鍵字分布來決定,當您對除常數以外的對象執行聯合時,表按什么順序進行聯合。

本語句會返回一個含有以下列的表:

Table

表名稱

Op

進行分析

Msg_type

狀態、錯誤、信息或警告之一

Msg_text

消息

您可以使用SHOW INDEX語句檢查已存儲的關鍵字分布。請參見13.5.4.11節,“SHOW INDEX語法”

如果從上一個ANALYZE TABLE語句開始,表沒有變化,則不再分析該表。

ANALYZE TABLE語句被寫入二進制日志中,除非使用了自選的NO_WRITE_TO_BINLOG關鍵詞(或其別名LOCAL)。

13.5.2.2.?BACKUP TABLE語法

BACKUP TABLE tbl_name [, tbl_name] ... TO '/path/to/backup/directory'

注釋:本語句不理想。我們正在努力尋找一種更好的替代方式,該方式將提供在線備份能力。同時,也可以使用mysqlhotcopy原本替代。

BACKUP TABLE用于在刷新了所有對磁盤的緩沖變更后,把恢復表所需的最少數目的表文件拷貝到備份目錄中。本語句只對MyISAM表起作用。它可以拷貝.frm定義文件和.MYD數據文件。.MYI索引文件可以從這兩個文件中重建。本目錄應被指定為一個完整的路徑名。

在使用本語句前,請參見5.9.1節,“數據庫備份”

在備份期間,為每個表保持一個讀取鎖定,每次一個,在正在備份時鎖定。如果您想要把多個表作為一個快照來備份(防止它們在備份操作過程中被更改),您必須實現發布一個LOCK TABLES語句,以獲得對一個組群中的每個表的讀取鎖定。

該語句會返回一個含有以下列的表:

Table

表名稱

Op

進行備份

Msg_type

狀態、錯誤、信息或警告之一

Msg_text

消息

13.5.2.3.?CHECK TABLE語法

CHECK TABLE tbl_name [, tbl_name] ... [option] ...
 
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

檢查一個或多個表是否有錯誤。CHECK TABLEMyISAMInnoDB表有作用。對于MyISAM表,關鍵字統計數據被更新。

CHECK TABLE也可以檢查視圖是否有錯誤,比如在視圖定義中被引用的表已不存在。

CHECK TABLE語句會返回一個含有以下列的表:

Table

表名稱

Op

進行檢查

Msg_type

狀態、錯誤、信息或錯誤之一

Msg_text

消息

注意,該語句可能會為每個被檢查的表產生多行信息。最后一行有一個Msg_type狀態值。Msg_text通常應為OK。如果您沒有得到OK,或表已經更新了,則您通常應該運行修復后的表。請參見5.9.4節,“表維護和崩潰恢復”。表已經更新了,這意味著表的存儲引擎指示沒有必要檢查表。

可以給予的不同的檢查選項列于下表中。這些選項只適用于檢查MyISAM表。對于InnoDB表和視圖,這些選項被忽略。

類型

意義

QUICK

不掃描行,不檢查錯誤的鏈接。

FAST

只檢查沒有被正確關閉的表。

CHANGED

只檢查上次檢查后被更改的表,和沒有被正確關閉的表。

MEDIUM

掃描行,以驗證被刪除的鏈接是有效的。也可以計算各行的關鍵字校驗和,并使用計算出的校驗和驗證這一點。

EXTENDED

對每行的所有關鍵字進行一個全面的關鍵字查找。這可以確保表是100%一致的,但是花的時間較長。

如果沒有指定QUICK, MEDIUMEXTENDED選項,則對于動態格式MyISAM表,默認檢查類型是MEDIUM。這與對表運行myisamchk --medium-check tbl_name的結果相同。對于靜態格式MyISAM表,默認檢查類型也是MEDIUM,除非CHANGEDFAST已被指定。在此情況下,默認值為QUICK。對于CHANGEDFAST,行掃描被跳過,因為行極少被破壞。

您可以組合檢查選項,如下面的例子所示。該例子對表進行了一個快速檢查,來查看該表是否被正確關閉:

CHECK TABLE test_table FAST QUICK;

注釋:在有些情況下,CHECK TABLE會更改表。如果表被標記為“corrupted”或“not closed properly”,則出現這種情況。但是CHECK TABLE不會找出表中的問題。在這種情況下,CHECK TABLE會把表標記為良好。

如果一個表被破壞,很有可能問題在索引中,而不在數據部分中。所有前述的檢查類型都可以徹底地檢查索引,因此,可以找出多數的錯誤。

如果您只想要檢查您假定的表是良好的,您應該不使用檢查選項或QUICK選項。當您時間匆忙時,應使用QUICKQUICK無法找出數據文件中的錯誤的風險非常小。(在多數情況下,在正常使用中,MySQL應能在數據文件中找出錯誤。如果找出了錯誤,表被標記為“corrupted”,并不能被使用,直到修復為止。)

如果您想要時常檢查表,FASTCHANGED多數情況下從原本中被使用(例如,從cron中被執行)。在多數情況下,FAST優先于CHANGED。(只有一種情況FAST不優先于CHANGED,那就是當您懷疑您在MyISAM代碼中發現了錯誤。)

MySQL試圖通過關鍵字更新一行或查找一行時,如果您已經運行了一個常規檢查后但仍得到來自表的奇怪的錯誤,此時使用EXTENDED。(如果常規的檢查運行成功,則基本用不著EXTENDED。)

CHECK TABLE報告的部分問題不會被自動修正:

·         發現行。此行中,auto_increment列有0值。

這意味著,您在表中有一行,該行的AUTO_INCREMENT索引列包含0值。(可以通過使用UPDATE語句,明確地把列設置為0,以創建一個AUTO_INCREMENT列為0的行。)

這本身不是一個錯誤,但是如果您決定轉儲表并恢復表,或對表進行ALTER TABLE,那么會導致出現麻煩。在此情況下,AUTO_INCREMENT列會根據AUTO_INCREMENT列的結果更改值,這會導致出現問題,如重復關鍵字錯誤等。

要消除警告,只需執行一個UPDATE語句,把列設置為除0以外的值。

13.5.2.4.?CHECKSUM TABLE語法

CHECKSUM TABLE tbl_name [, tbl_name] ... [ QUICK | EXTENDED ]

報告一個表校驗和。

如果指定了QUICK,則報告活性表校驗和,否則報告NULL。這是非常快的。活性表通過指定CHECKSUM1表選項啟用,目前只支持用于MyISAM表。請參見13.1.5節,“CREATE TABLE語法”

EXTENDED模式下,整個表被一行一行地讀取,并計算校驗和。對于大型表,這是非常慢的。

默認情況下,如果既沒有指定QUICK,也沒有指定EXTENDED,并且如果表存儲引擎支持,則MySQL返回一個活性校驗和,否則會對表進行掃描。

CHECKSUM TABLE對于不存在的表會返回NULL。對于這種情況,會生成一個警告。

13.5.2.5.?OPTIMIZE TABLE語法

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

如果您已經刪除了表的一大部分,或者如果您已經對含有可變長度行的表(含有VARCHAR, BLOBTEXT列的表)進行了很多更改,則應使用OPTIMIZE TABLE。被刪除的記錄被保持在鏈接清單中,后續的INSERT操作會重新使用舊的記錄位置。您可以使用OPTIMIZE TABLE來重新利用未使用的空間,并整理數據文件的碎片。

在多數的設置中,您根本不需要運行OPTIMIZE TABLE。即使您對可變長度的行進行了大量的更新,您也不需要經常運行,每周一次或每月一次即可,只對特定的表運行。

OPTIMIZE TABLE只對MyISAM, BDBInnoDB表起作用。

對于MyISAM表,OPTIMIZE TABLE按如下方式操作:

1.    如果表已經刪除或分解了行,則修復表。

2.    如果未對索引頁進行分類,則進行分類。

3.       如果表的統計數據沒有更新(并且通過對索引進行分類不能實現修復),則進行更新。

對于BDB表,OPTIMIZE TABLE目前被映射到ANALYZE TABLE上。對于InnoDB表,OPTIMIZE TABLE被映射到ALTER TABLE上,這會重建表。重建操作能更新索引統計數據并釋放成簇索引中的未使用的空間。請參見13.5.2.1節,“ANALYZE TABLE語法”

使用—skip-new或—safe-mode選項可以啟動mysqld。通過啟動mysqld,您可以使OPTIMIZE TABLE對其它表類型起作用。

注意,在OPTIMIZE TABLE運行過程中,MySQL會鎖定表。

OPTIMIZE TABLE語句被寫入到二進制日志中,除非使用了自選的NO_WRITE_TO_BINLOG關鍵詞(或其別名LOCAL)。已經這么做了,因此,用于MySQL服務器的OPTIMIZE TABLE命令的作用相當于一個復制主服務器,在默認情況下,這些命令將被復制到復制從屬服務器中。

13.5.2.6.?REPAIR TABLE語法

REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE
    tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]

REPAIR TABLE用于修復被破壞的表。默認情況下,REPAIR TABLEmyisamchk --recover tbl_name具有相同的效果。REPAIR TABLEMyISAMARCHIVE表起作用。請參見15.1節,“MyISAM存儲引擎”, 15.8節,“ARCHIVE存儲引擎”

通常,您基本上不必運行此語句。但是,如果災難發生,REPAIR TABLE很有可能從MyISAM表中找回所有數據。如果您的表經常被破壞,您應該盡力找到原因,以避免使用REPAIR TALBE。請參見A.4.2節,“如果MySQL依然崩潰,應作些什么”。同時也見15.1.4節,“MyISAM表方面的問題”

本語句會返回一個含有以下列的表:

Table

表名稱

Op

進行修復

Msg_type

狀態、錯誤、信息或警告之一

Msg_text

消息

對于每個被修復的表,REPAIR TABLE語句會產生多行的信息。上一行含有一個Msg_type狀態值。Msg_test通常應為OK。如果您沒有得到OK,您應該嘗試使用myisamchk --safe-recover修復表,因為REPAIR TABLE尚不會執行所有的myisamchk選項。我們計劃在將來使它的靈活性更強。

如果給定了QUICK,則REPAIR TABLE會嘗試只修復索引樹。這種類型的修復與使用myisamchk --recover --quick相似。

如果您使用EXTENDED,則MySQL會一行一行地創建索引行,代替使用分類一次創建一個索引。這種類型的修復與使用myisamchk --safe-recover相似。

對于REPAIR TABLE,還有一種USE_FRM模式可以利用。如果.MYI索引文件缺失或標題被破壞,則使用此模式。在這種模式下,MySQL可以使用來自.frm文件重新創建.MYI文件。這種修復不能使用myisamchk來完成。 注釋:只能在您不能使用常規REPAIR模式是,才能使用此模式。.MYI標題包含重要的表元數據(特別是,當前的AUTO_INCREMENT值和Delete鏈接)。這些元數據在REPAIR...USE_FRM中丟失。如果表被壓縮,則不能使用USE_FRM。因為本信息也存儲在.MYI文件中。

REPAIR TABLE語句被寫入二進制日志中,除非使用了自選的NO_WRITE_TO_BINLOG關鍵詞(或其別名LOCAL)。

警告:如果在REPAIR TABLE運行過程中,服務器停機,則在重新啟動之后,在執行其它操作之前,您必須立刻對表再執行一個REPAIR TABLE語句。(通過制作一個備份來啟動是一個好辦法。)再最不利情況下,您可以有一個新的干凈的索引文件,不含有關數據文件的信息。然后,您執行的下一個操作會覆蓋數據文件。這很少發生,但是是有可能的。

13.5.2.7.?RESTORE TABLE語法

RESTORE TABLE tbl_name [, tbl_name] ... FROM '/path/to/backup/directory'

用于恢復來自用BACKUP TABLE制作的備份的表。原有的表不會被覆蓋;如果您試圖覆蓋一個原有的表,會發生錯誤。和BACKUP TABLE一樣,RESTORE TABLE目前只對MyISAM表起作用。目錄應被指定為一個完整路徑名。

每個表的備份包括其.frm格式文件和.MYD數據文件。恢復操作會恢復這些文件,然后使用這些文件來重建.MYI索引文件。恢復操作比備份操作花的時間更長,這是因為需要重建索引。表含有的索引越多,花的時間就越長。

該語句會返回一個含有以下列的表:

Table

表名稱

Op

進行恢復

Msg_type

狀態、錯誤、信息或警告之一

Msg_text

消息

13.5.3.?SET語法

SET variable_assignment [, variable_assignment] ...
 
variable_assignment:
      user_var_name = expr
    | [GLOBAL | SESSION] system_var_name = expr
    | @@[global. | session.]system_var_name = expr

SET用于設置不同類型的變量。這些變量會影響服務器或客戶端的操作。SET可以用于向用戶變量或系統變量賦值。

用于分配賬戶密碼的SET PASSWORD語句在13.5.1.5節,“SET PASSWORD語法”中進行了討論。

多數系統變量可以在運行時間被更改。可以被動態設置的系統變量在5.3.3.1節,“動態系統變量”中進行了討論。

注釋:舊版本的MySQL采用SET OPTION作為這個命令,但是由于有了SET,現在不贊成使用SET OPTION

以下例子顯示了您可以用于設置變量的不同語法。

用戶變量可以被寫作@var_name,并可以進行如下設置:

SET @var_name = expr;

9.3節,“用戶變量”中給出了有關用戶變量的更多信息。

系統變量可以被作為var_name引用到SET語句中。在名稱的前面可以自選地添加GLOBAL@@global,以明確地指示該變量是全局變量。或者在名稱前面添加SESSION, @@session,或@@,以指示它是一個會話變量。LOCAL@@localSESSION@@session地同義詞。如果沒有修改符,則SET設置會話變量。

支持系統變量的@@var_name語法,以便使MySQL語法與其它數據庫系統相兼容。

如果您在同一個語句中設置多個系統變量,則最后一個GLOBALSESSION選項被用于沒有指定模式的變量。

SET sort_buffer_size=10000;
SET @@local.sort_buffer_size=10000;
SET GLOBAL sort_buffer_size=1000000, SESSION sort_buffer_size=1000000;
SET @@sort_buffer_size=1000000;
SET @@global.sort_buffer_size=1000000, @@local.sort_buffer_size=1000000;

如果您使用SESSION(默認情況)設置一個系統變量,則該值仍然有效,直到當前會話結束為止,或者直到您吧變量設置為一個不同的值為止。如果您使用GLOBAL(要求SUPER權限)來設置一個系統變量,則該值被記住,并被用于新的連接,直到服務器重新啟動為止。如果您想要進行永久式變量設置,您應該把它放入一個選項文件。請參見4.3.2節,“使用選項文件”

為了防止不正確的使用,如果您使用SET GLOBAL時同時使用了一個只能與SET SESSION同時使用的變量,或者如果您在設置一個全局變量時未指定GLOBAL(或@@),則MySQL會產生一個錯誤。

如果您想要把一個SESSION變量設置為GLOBAL值或把一個GLOBAL值設置為內部MySQL默認值,需使用DEFAULT關鍵詞。例如,在把max_join_size會話值設置為全局值時,以下兩個語句是一樣的:

SET max_join_size=DEFAULT;
SET @@[email protected]@global.max_join_size;

您可以使用SHOW VARIABLES來得到系統變量清單。(見13.5.4.21節,“SHOW VARIABLES語法”。)要獲得與樣式匹配的一個具體的變量名稱或者名稱清單,需使用LIKE子句,使用方法如下:

SHOW VARIABLES LIKE 'max_join_size';
SHOW GLOBAL VARIABLES LIKE 'max_join_size';

要得到名稱與樣式匹配的變量的清單,需使用通配符‘%’:

SHOW VARIABLES LIKE 'have%';
SHOW GLOBAL VARIABLES LIKE 'have%';

通配符可以被用于相匹配的樣式中的任何位置。

您也可以通過使用@@[global.|local.]var_name語法和SELECT來得到值:

SELECT @@max_join_size, @@global.max_join_size;

當您使用SELECT @@var_name(即您不指定全局、會話或本地)來恢復一個變量時,則MySQL會返回SESSION值(如果存在)或者GLOBAL值。

以下清單用于描述帶有非標準語法的變量,或描述在系統變量清單中(見5.3.3節,“服務器系統變量”。)中沒有描述的變量。盡管這些變量沒有被SHOW VARIABLES顯示,但是您可以使用SELECT來獲得它們的值(例外情況是,使用CHARACTER SETSET NAMES)。例如:

mysql> SELECT @@AUTOCOMMIT;
+--------------+
| @@AUTOCOMMIT |
+--------------+
|            1 |
+--------------+

·         AUTOCOMMIT = {0 | 1}

設置autocommit模式。如果設置為1,則所有對表的更改會立刻生效。如果設置為0,則您必須使用COMMIT來接受一個事務,或使用ROLLBACK來取消它。如果您把AUTOCOMMIT模式從0改為1,則MySQL會對開放事務執行一個自動COMMIT。開始一個事務的另一種方法是使用一個START TRANSACTIONBEGIN語句。請參見13.4.1節,“START TRANSACTION, COMMIT和ROLLBACK語法”

·         BIG_TABLES = {0 | 1}

如果設置為1,所有的臨時表被存儲在磁盤中,而不是存儲在儲存期中。這樣會稍微慢些,但是對于需要一個大型臨時表的SELECT操作,不會發生The table tbl_name is full錯誤。對于一個新連接,默認值為0(使用存儲器內部臨時表)。通常,您不必設置此變量,因為根據需要,存儲器內部表會被自動轉換為以磁盤為基礎的表。( 注釋:本變量以前被命名為SQL_BIG_TABLES。)

·         CHARACTER SET {charset_name | DEFAULT}

本語句使用給定的映射為所有來自客戶端和指向客戶端的字符串建立映射。您可以通過在MySQL源分布中編輯sql/convert.cc來添加新的映射。SET CHARACTER SET用于設定三個會話系統變量:character_set_clientcharacter_set_results被設置為給定的字符集,character_set_connection被設置為character_set_database值。

可以通過使用DEFAULT值恢復默認的映射。

注意,SET CHARACTER SET的語法與設置其它選項的語法不同。

·         FOREIGN_KEY_CHECKS = {0 | 1}

如果設置為1(默認情況),則檢查InnoDB表的外鍵限制條件。如果設置為0,則限制條件被忽略。如果重新載入InnoDB表時按照的順序與上級/下級目錄所要求的順序不同,此時禁用外鍵檢查是有用的。請參見15.2.6.4節,“FOREIGN KEY約束”

·         IDENTITY = value

該變量是LAST_INSERT_ID變量的同義詞。該變量的作用是保持與其它數據庫兼容。您可以使用SELECT @@IDENTITY讀取其值,并可以使用SET IDENTITY設置它。

·         INSERT_ID = value

用于設置將被以下INSERTALTER TABLE語句使用的值。此值在插入一個AUTO_INCREMENT值時使用。本語句主要和二進制日志同時使用。

·         LAST_INSERT_ID = value

用于設定將從LAST_INSERT_ID()被返回的值。當您在用于更新表的語句中使用LAST_INSERT_ID()時,它被存儲在二進制日志中。設置此變量不會更新由mysql_insert_id() C API函數返回的值。

·         NAMES {'charset_name' | DEFAULT}

SET NAMES用于把三個會話系統變量character_set_client, character_set_connectioncharacter_set_results設置為給定的字符集。把character_set_connection設置為charset_name時,同時把collation_connection設置為charset_name的默認整序。

使用一個DEFAULT值可以恢復默認的映射。

注意,SET NAMES的語法與用于設置其它選項的語法不同。

·         ONE_SHOT

這不是一個服務器系統變量,但是它可以被用來影響用于設置字符集、整序和時區的變量的效果。ONE_SHOT主要被用于復制:mysqlbinlog使用SET ONE_SHOT來暫時地修改字符集、整序和時區變量的值,以反映出它們原先的值。

您不能在使用ONE_SHOT時使用除允許的變量以外的變量;如果您這么做,您會得到如下錯誤:

mysql> SET ONE_SHOT max_allowed_packet = 1;
ERROR 1382 (HY000): The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server 

如果同時使用ONE_SHOT和被允許的變量,則會根據要求更改變量,但是會在下一個語句后,重新設置所有的字符集、整序和與時區有關的服務器系統變量。唯一的例外是,當下一個語句是SET語句時,不會進行重新設置。換句話說,在下一個非SET語句之后,才會進行重新設置。例如:

mysql> SET ONE_SHOT character_set_connection = latin5;
 
mysql> SET ONE_SHOT collation_connection = latin5_turkish_ci;
 
mysql> SHOW VARIABLES LIKE '%_connection';
+--------------------------+-------------------+
| Variable_name            | Value             |
+--------------------------+-------------------+
| character_set_connection | latin5            |
| collation_connection     | latin5_turkish_ci |
+--------------------------+-------------------+
 
mysql> SHOW VARIABLES LIKE '%_connection';
+--------------------------+-------------------+
| Variable_name            | Value             |
+--------------------------+-------------------+
| character_set_connection | latin1            |
| collation_connection     | latin1_swedish_ci |
+--------------------------+-------------------+

·         SQL_NOTES = {0 | 1}

當設置為1時(默認情況),“注意”一級的警報被記錄下來。當設置為0時,“注意”警告被壓制。Mysqldump包含輸出,用于把此變量設置為0,這樣,對于不會影響重新載入操作整體性的事件,重新載入轉儲文件時不會產生警告。

·         SQL_AUTO_IS_NULL = {0 | 1}

如果設置為1(默認情況),您可以通過使用以下結構查找包含一個AUTO_INCREMENT列的表的最后插入的行:

WHERE auto_increment_column IS NULL

此性質被有些ODBC程序,比如Access使用。

·         SQL_BIG_SELECTS = {0 | 1}

如果設定為0,則MySQL會放棄有可能會花很長時間來執行的SELECT語句(也就是,對于這些語句,優化程序估算被檢查的行的數目超過了max_join_size的值)。當一個不妥當的WHERE語句被發布后,本語句有用。一個新連接的默認值為1,這可以允許所有的SELECT語句。

如果您把max_join_size系統變量設置為除DEFAULT以外的值,則SQL_BIG_SELECTS被設置為0

·         SQL_BUFFER_RESULT = {0 | 1}

SQL_BUFFER_RESULT會迫使來自SELECT語句的結果被放入臨時表中。這可以幫助MySQL早點解除表鎖定。當需要花較長時間把結果發送給客戶端時,這是有好處的。

·         SQL_LOG_BIN = {0 | 1}

如果設置為0,則客戶端的二進制日志中不會記錄日志。客戶端必須擁有SUPER權限來設置此選項。

·         SQL_LOG_OFF = {0 | 1}

如果設置為1,則此客戶端的總查詢日志中不會記錄日志。客戶端必須擁有SUPER權限來設置此選項。

·         SQL_LOG_UPDATE = {0 | 1}

不贊成使用本變量。本變量被映射到SQL_LOG_BIN

·         SQL_QUOTE_SHOW_CREATE = {0 | 1}

如果設置為1,則SHOW CREATE TABLE會對表和列的名稱加引號。如果設置為0,則加引號操作被禁用。默認情況下,本選項被啟用,因此對于含有需要加引號的名稱的表,復制操作起作用。請參見13.5.4.5節,“SHOW CREATE TABLE語法”

·         SQL_SAFE_UPDATES = {0 | 1}

如果設置為1,則MySQL會放棄在WHERE子句或LIMIT子句中不使用關鍵字的UPDATEDELETE語句。這樣,當關鍵字使用不正確時,也有可能理解UPDATEDELETE語句。這樣就可以更改或刪除大量的行。

·         SQL_SELECT_LIMIT = {value | DEFAULT}

SELECT語句返回的記錄的最大數目。對于一個新連接,默認值是“unlimited”。如果您更改了限值,可以使用SQL_SELECT_LIMIT DEFAULT值恢復默認值。

如果SELECT有一個LIMIT子句,則LIMIT優先于SQL_SELECT_LIMIT值。

SQL_SELECT_LIMT不適用于在被存儲的子程序中執行的SELECT語句。它也不適用于不會產生將被返回到客戶端的結果集合的SELECT語句。這些包括子查詢中的SELECT語句,CREATE TABLE...SELECTINSERT INTO...SELECT

·         SQL_WARNINGS = {0 | 1}

本變量用于控制當出現警告時,單行INSERT語句是否產生一個信息字符串。默認值為0。把值設置為1,來產生一個信息字符串。

·         TIMESTAMP = {timestamp_value | DEFAULT}

用于為此客戶端設置時間。當您使用二進制日志來恢復行時,本語句用于得到原始的時間標記。timestamp_value應為一個Unix時間標記,而不是MySQL時間標記。

·         UNIQUE_CHECKS = {0 | 1}

如果設置為1(默認情況),則會對InnoDB表中的二級索引執行唯一性檢查。如果設置為0,則對于被插入到InnoDB的插入緩沖器中的索引登錄項,不執行唯一性檢查。如果您可以肯定您的數據不違反唯一性要求,則您可以把此值設定為0,以加快向InnoDB導入大型表的速度。

13.5.4.?SHOW語法

SHOW有多種形式,可以提供有關數據庫、表、列或服務器狀態的信息。本節敘述以下內容:

SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']
SHOW CREATE DATABASE db_name
SHOW CREATE TABLE tbl_name
SHOW DATABASES [LIKE 'pattern']
SHOW ENGINE engine_name {LOGS | STATUS }
SHOW [STORAGE] ENGINES
SHOW ERRORS [LIMIT [offset,] row_count]
SHOW GRANTS FOR user
SHOW INDEX FROM tbl_name [FROM db_name]
SHOW INNODB STATUS
SHOW [BDB] LOGS
SHOW PRIVILEGES
SHOW [FULL] PROCESSLIST
SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern']
SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
SHOW [OPEN] TABLES [FROM db_name] [LIKE 'pattern']
SHOW TRIGGERS
SHOW [GLOBAL | SESSION] VARIABLES [LIKE 'pattern']
SHOW WARNINGS [LIMIT [offset,] row_count]

SHOW語句還有一些形式,可以提供有關復制型主服務器和從屬服務器的信息。這些形式在13.6節,“復制語句”中進行了敘述。

SHOW BINLOG EVENTS
SHOW MASTER LOGS
SHOW MASTER STATUS
SHOW SLAVE HOSTS
SHOW SLAVE STATUS

如果一個給定的SHOW語句的語法包括一個LIKE 'pattern'部分,則'pattern'是一個可以包含SQL %’和‘_’通配符的字符串。對于把語句輸出值限定為匹配值,本樣式是有用的。

13.5.4.1.?SHOW CHARACTER SET語法

SHOW CHARACTER SET [LIKE 'pattern']

SHOW CHARACTER SET語句用于顯示所有可用的字符集。該語句取一個自選的LIKE子句。該子句指示哪些字符集名稱可以匹配。舉例說明:

mysql> SHOW CHARACTER SET LIKE 'latin%';
+---------+-----------------------------+-------------------+--------+
| Charset | Description                 | Default collation | Maxlen |
+---------+-----------------------------+-------------------+--------+
| latin1  | cp1252 West European        | latin1_swedish_ci |      1 |
| latin2  | ISO 8859-2 Central European | latin2_general_ci |      1 |
| latin5  | ISO 8859-9 Turkish          | latin5_turkish_ci |      1 |
| latin7  | ISO 8859-13 Baltic          | latin7_general_ci |      1 |
+---------+-----------------------------+-------------------+--------+

Maxlen列顯示用于存儲一個字符的最大的字節數目。

13.5.4.2.?SHOW COLLATION語法

SHOW COLLATION [LIKE 'pattern']

來自SHOW COLLATION的輸出包括所有可用的字符集。該語句取一個自選的LIKE子句。該子句的pattern指示哪些整序名稱可以匹配。舉例說明:

mysql> SHOW COLLATION LIKE 'latin1%';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1  |  5 |         |          |       0 |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      |       0 |
| latin1_danish_ci  | latin1  | 15 |         |          |       0 |
| latin1_german2_ci | latin1  | 31 |         | Yes      |       2 |
| latin1_bin        | latin1  | 47 |         | Yes      |       0 |
| latin1_general_ci | latin1  | 48 |         |          |       0 |
| latin1_general_cs | latin1  | 49 |         |          |       0 |
| latin1_spanish_ci | latin1  | 94 |         |          |       0 |
+-------------------+---------+----+---------+----------+---------+

Default列指示對于其字符集,整序值是否是默認值。Compiled指示字符集是否被編輯到服務器中。Sortlen與對字符串(在字符集中表達)分類所需的存儲器的數量有關。

13.5.4.3.?SHOW COLUMNS語法

SHOW [FULL] COLUMNS FROM tbl_name [FROM db_name] [LIKE 'pattern']

SHOW COLUMNS顯示在一個給定表中的各列的信息。對于試圖,本語句也起作用。

如果列類型與根據您的CREATE TABLE語句所預期的列類型不同,則需注意,當您創建或更改表時,MySQL有時會更改列類型。出現這種情況的條件在13.1.5.1節,“沉寂的列規格變更”中進行了描述。

FULL關鍵詞會使得輸出中包含您擁有的權限,并包含對每一列各自的評注。

您可以使用db_name.tbl_name作為tbl_name FROM db_name語法的另一種形式。換句話說,這兩個語句是等價的:

mysql> SHOW COLUMNS FROM mytable FROM mydb;
mysql> SHOW COLUMNS FROM mydb.mytable;

SHOW FIELDSSHOW COLUMNS的同義詞。您也可以使用mysqlshow db_name tbl_name命令列舉表的各列。

DESCRIBE語句提供與SHOW COLUMNS相近的信息。請參見13.3.1節,“DESCRIBE語法(獲取關于列的信息)”

13.5.4.4.?SHOW CREATE DATABASE語法

SHOW CREATE {DATABASE | SCHEMA} db_name

顯示用于創建給定數據庫CREATE DATABASE語句。也可以使用SHOW CREATE SCHEMA

mysql> SHOW CREATE DATABASE test\G
*************************** 1. row ***************************
       Database: test
Create Database: CREATE DATABASE `test`
                 /*!40100 DEFAULT CHARACTER SET latin1 */
 
mysql> SHOW CREATE SCHEMA test\G
*************************** 1. row ***************************
       Database: test
Create Database: CREATE DATABASE `test` 
                 /*!40100 DEFAULT CHARACTER SET latin1 */

13.5.4.5.?SHOW CREATE TABLE語法

SHOW CREATE TABLE tbl_name

顯示用于創建給定表的CREATE TABLE語句。本語句對視圖也起作用。

mysql> SHOW CREATE TABLE t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE t (
  id INT(11) default NULL auto_increment,
  s char(60) default NULL,
  PRIMARY KEY (id)
) ENGINE=MyISAM
 

根據SQL_QUOTE_SHOW_CREATE選項,SHOW CREATE TABLE會對表名稱和列名稱加引號。請參見13.5.3節,“SET語法”

13.5.4.6.?SHOW DATABASES語法

SHOW {DATABASES | SCHEMAS} [LIKE 'pattern']

SHOW DATABASES可以在MySQL服務器主機上列舉數據庫。您也可以使用mysqlshow命令得到此清單。您只能看到您擁有某些權限的數據庫,除非您擁有全局SHOW DATABASES權限。

如果服務器以--skip-show-database選項為起始,則您根本不能使用本語句,除非您擁有SHOW DATABASES權限。

也可以使用SHOW SCHEMAS

13.5.4.7.?SHOW ENGINE語法

SHOW ENGINE engine_name {LOGS | STATUS }

SHOW ENGINE顯示存儲引擎的日志或狀態信息。目前支持以下語句:

SHOW ENGINE BDB LOGS
SHOW ENGINE INNODB STATUS

SHOW ENGINE BDB LOGS顯示原有BDB日志文件的狀態信息。它會返回以下字段:

·         File

通向日志文件的完整路徑。

·         Type

日志文件類型(用于Berkeley DB日志文件的BDB)。

·         Status

日志文件的狀態(如果文件可以被取消,則為FREE。如果文件被事務子系統需要,則為IN USE

SHOW ENGINE INNODB STATUS顯示InnoDB存儲引擎狀態的全面信息。

這些語句的舊的同義詞(現在不贊成使用)是SHOW [BDB] LOGSSHOW INNODB STATUS

SHOW ENGINE可以從MySQL 4.1.2起使用。

13.5.4.8.?SHOW ENGINES語法

SHOW [STORAGE] ENGINES

SHOW ENGINES顯示存儲引擎的狀態信息。對于檢查一個存儲引擎是否被支持,或者對于查看默認引擎是什么,本語句十分有用。SHOW TABLE TYPES是同義詞,但不贊成使用。

mysql> SHOW ENGINES\G
*************************** 1. row ***************************
 Engine: MyISAM
Support: DEFAULT
Comment: Default engine as of MySQL 3.23 with great performance
*************************** 2. row ***************************
 Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
*************************** 3. row ***************************
 Engine: HEAP
Support: YES
Comment: Alias for MEMORY
*************************** 4. row ***************************
 Engine: MERGE
Support: YES
Comment: Collection of identical MyISAM tables
*************************** 5. row ***************************
 Engine: MRG_MYISAM
Support: YES
Comment: Alias for MERGE
*************************** 6. row ***************************
 Engine: ISAM
Support: NO
Comment: Obsolete storage engine, now replaced by MyISAM
*************************** 7. row ***************************
 Engine: MRG_ISAM
Support: NO
Comment: Obsolete storage engine, now replaced by MERGE
*************************** 8. row ***************************
 Engine: InnoDB
Support: YES
Comment: Supports transactions, row-level locking, and foreign keys
*************************** 9. row ***************************
 Engine: INNOBASE
Support: YES
Comment: Alias for INNODB
*************************** 10. row ***************************
 Engine: BDB
Support: NO
Comment: Supports transactions and page-level locking
*************************** 11. row ***************************
 Engine: BERKELEYDB
Support: NO
Comment: Alias for BDB
*************************** 12. row ***************************
 Engine: NDBCLUSTER
Support: DISABLED
Comment: Clustered, fault-tolerant, memory-based tables
*************************** 13. row ***************************
 Engine: NDB
Support: DISABLED
Comment: Alias for NDBCLUSTER
*************************** 14. row ***************************
 Engine: EXAMPLE
Support: NO
Comment: Example storage engine
*************************** 15. row ***************************
 Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
*************************** 16. row ***************************
 Engine: CSV
Support: YES
Comment: CSV storage engine
*************************** 17. row ***************************
 Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
*************************** 18. row ***************************
 Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)

Support值指示某個存儲引擎是否被支持,并指示哪個是默認引擎。例如,如果服務器以--default-table-type=InnoDB選項為起始,則InnoDB行的Support值為DEFAULT值。請參見第15章:存儲引擎和表類型

13.5.4.9.?SHOW ERRORS語法

SHOW ERRORS [LIMIT [offset,] row_count]
SHOW COUNT(*) ERRORS

本語句與SHOW WARNINGS接近,不過該語句只顯示錯誤,不同時顯示錯誤、警告和注意。

LIMIT子句與SELECT語句具有相同的語法,請參見13.2.7節,“SELECT語法”

SHOW COUNT(*) ERRORS語句顯示錯誤的數目。您也可以從error_count變量中找回此數目:

SHOW COUNT(*) ERRORS;
SELECT @@error_count;

要了解更多信息,請參見13.5.4.22節,“SHOW WARNINGS語法”

13.5.4.10.?SHOW GRANTS語法

SHOW GRANTS FOR user

本語句列出了在為MySQL用戶賬戶復制權限時必須發布的GRANT語句。

mysql> SHOW GRANTS FOR 'root'@'localhost';
+---------------------------------------------------------------------+
| Grants for [email protected]                                           |
+---------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION |
+---------------------------------------------------------------------+

要對當前的會話列出權限,您可以使用以下語句之一:

SHOW GRANTS;
SHOW GRANTS FOR CURRENT_USER;
SHOW GRANTS FOR CURRENT_USER();

13.5.4.11.?SHOW INDEX語法

SHOW INDEX FROM tbl_name [FROM db_name]

SHOW INDEX會返回表索引信息。其格式與ODBC中的SQLStatistics調用相似。

SHOW INDEX會返回以下字段:

·         Table

表的名稱。

·         Non_unique

如果索引不能包括重復詞,則為0。如果可以,則為1

·         Key_name

索引的名稱。

·         Seq_in_index

索引中的列序列號,從1開始。

·         Column_name

列名稱。

·         Collation

列以什么方式存儲在索引中。在MySQL中,有值‘A’(升序)或NULL(無分類)。

·         Cardinality

索引中唯一值的數目的估計值。通過運行ANALYZE TABLEmyisamchk -a可以更新。基數根據被存儲為整數的統計數據來計數,所以即使對于小型表,該值也沒有必要是精確的。基數越大,當進行聯合時,MySQL使用該索引的機會就越大。

·         Sub_part

如果列只是被部分地編入索引,則為被編入索引的字符的數目。如果整列被編入索引,則為NULL

·         Packed

指示關鍵字如何被壓縮。如果沒有被壓縮,則為NULL

·         Null

如果列含有NULL,則含有YES。如果沒有,則該列含有NO

·         Index_type

用過的索引方法(BTREE, FULLTEXT, HASH, RTREE)。

·         Comment

多種評注。

您可以使用db_name.tbl_name作為tbl_name FROM db_name語法的另一種形式。這兩個語句是等價的:

mysql> SHOW INDEX FROM mytable FROM mydb;
mysql> SHOW INDEX FROM mydb.mytable;

SHOW KEYSSHOW INDEX的同義詞。您也可以使用mysqlshow -k db_name tbl_name命令列舉一個表的索引。

13.5.4.12.?SHOW INNODB STATUS語法

SHOW INNODB STATUS

MySQL 5.1中,這是SHOW ENGINE INNODB STATUS的同義詞,但不贊成使用。請參見13.5.4.7節,“SHOW ENGINE語法”

13.5.4.13.?SHOW LOGS語法

SHOW [BDB] LOGS

MySQL 5.1中,這是SHOW ENGINE BDB LOGS的同義詞,但是不贊成使用。請參見13.5.4.7節,“SHOW ENGINE語法”

13.5.4.14.?SHOW OPEN TABLES語法

SHOW OPEN TABLES [FROM db_name] [LIKE 'pattern']

SHOW OPEN TABLES列舉在表緩存中當前被打開的非TEMPORARY表。請參見7.4.9節,“MySQL如何打開和關閉表”

SHOW OPEN TABLES會返回以下字段:

·         Database

含有該表的數據庫。

·         Table

表名稱。

·         In_use

表當前被查詢使用的次數。如果該數為零,則表是打開的,但是當前沒有被使用。

·         Name_locked

表名稱是否被鎖定。名稱鎖定用于取消表或對表進行重命名等操作。

13.5.4.15.?SHOW PRIVILEGES語法

SHOW PRIVILEGES

SHOW PRIVILEGES顯示MySQL服務器支持的系統權限清單。確切的輸出根據您的服務器的版本而定。

mysql> SHOW PRIVILEGES\G
*************************** 1. row ***************************
Privilege: Alter
Context: Tables
Comment: To alter the table
*************************** 2. row ***************************
Privilege: Alter routine
Context: Functions,Procedures
Comment: To alter or drop stored functions/procedures
*************************** 3. row ***************************
Privilege: Create
Context: Databases,Tables,Indexes
Comment: To create new databases and tables
*************************** 4. row ***************************
Privilege: Create routine
Context: Functions,Procedures
Comment: To use CREATE FUNCTION/PROCEDURE
*************************** 5. row ***************************
Privilege: Create temporary tables
Context: Databases
Comment: To use CREATE TEMPORARY TABLE
*************************** 6. row ***************************
Privilege: Create view
Context: Tables
Comment: To create new views
*************************** 7. row ***************************
Privilege: Create user
Context: Server Admin
Comment: To create new users
*************************** 8. row ***************************
Privilege: Delete
Context: Tables
Comment: To delete existing rows
*************************** 9. row ***************************
Privilege: Drop
Context: Databases,Tables
Comment: To drop databases, tables, and views
*************************** 10. row ***************************
Privilege: Execute
Context: Functions,Procedures
Comment: To execute stored routines
*************************** 11. row ***************************
Privilege: File
Context: File access on server
Comment: To read and write files on the server
*************************** 12. row ***************************
Privilege: Grant option
Context: Databases,Tables,Functions,Procedures
Comment: To give to other users those privileges you possess
*************************** 13. row ***************************
Privilege: Index
Context: Tables
Comment: To create or drop indexes
*************************** 14. row ***************************
Privilege: Insert
Context: Tables
Comment: To insert data into tables
*************************** 15. row ***************************
Privilege: Lock tables
Context: Databases
Comment: To use LOCK TABLES (together with SELECT privilege)
*************************** 16. row ***************************
Privilege: Process
Context: Server Admin
Comment: To view the plain text of currently executing queries
*************************** 17. row ***************************
Privilege: References
Context: Databases,Tables
Comment: To have references on tables
*************************** 18. row ***************************
Privilege: Reload
Context: Server Admin
Comment: To reload or refresh tables, logs and privileges
*************************** 19. row ***************************
Privilege: Replication client
Context: Server Admin
Comment: To ask where the slave or master servers are
*************************** 20. row ***************************
Privilege: Replication slave
Context: Server Admin
Comment: To read binary log events from the master
*************************** 21. row ***************************
Privilege: Select
Context: Tables
Comment: To retrieve rows from table
*************************** 22. row ***************************
Privilege: Show databases
Context: Server Admin
Comment: To see all databases with SHOW DATABASES
*************************** 23. row ***************************
Privilege: Show view
Context: Tables
Comment: To see views with SHOW CREATE VIEW
*************************** 24. row ***************************
Privilege: Shutdown
Context: Server Admin
Comment: To shut down the server
*************************** 25. row ***************************
Privilege: Super
Context: Server Admin
Comment: To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.
*************************** 26. row ***************************
Privilege: Update
Context: Tables
Comment: To update existing rows
*************************** 27. row ***************************
Privilege: Usage
Context: Server Admin
Comment: No privileges - allow connect only

13.5.4.16.?SHOW PROCESSLIST語法

SHOW [FULL] PROCESSLIST

SHOW PROCESSLIST顯示哪些線程正在運行。您也可以使用mysqladmin processlist語句得到此信息。如果您有SUPER權限,您可以看到所有線程。否則,您只能看到您自己的線程(也就是,與您正在使用的MySQL賬戶相關的線程)。請參見13.5.5.3節,“KILL語法”。如果您不使用FULL關鍵詞,則只顯示每個查詢的前100個字符。

本語句報告TCP/IP連接的主機名稱(采用host_name:client_port格式),以方便地判定哪個客戶端正在做什么。

如果您得到“too many connections”錯誤信息,并且想要了解正在發生的情況,本語句是非常有用的。MySQL保留一個額外的連接,讓擁有SUPER權限的 賬戶使用,以確保管理員能夠隨時連接和檢查系統(假設您沒有把此權限給予所有的用戶)。

在來自SHOW PROCESSLIST的輸出中常見的一些狀態:

·         Checking table

線程正在執行(自動)表格檢查。

·         Closing tables

意味著線程正在刷新更改后的表數據,并正在關閉使用過的表。這應該是一個快速的操作。如果不快,則您應該驗證您的磁盤沒有充滿,并且磁盤沒有被超負荷使用。

·         Connect Out

連接到主服務器上的從屬服務器。

·         Copying to tmp table on disk

臨時結果集合大于tmp_table_size。線程把臨時表從存儲器內部格式改變為磁盤模式,以節約存儲器。

·         Creating tmp table

線程正在創建一個臨時表,以保持部分結果。

·         deleting from main table

服務器正在執行多表刪除的第一部分,只從第一個表中刪除。

·         deleting from reference tables

服務器正在執行多表刪除的第二部分,從其它表中刪除匹配的行。

·         Flushing tables

線程正在執行FLUSH TABLES,并正在等待所有線程,以關閉表。

·         FULLTEXT initialization

服務器正在準備執行一個自然語言全文本搜索。

·         Killed

有人已經向線程發送了一個KILL命令。在下一次檢查終止標記時,應放棄。該標記在MySQL的每個大循環中都檢查,但是在有些情況下,線程終止只需要較短的時間。如果該線程被其它線程鎖定,則只要其它線程接觸鎖定,終止操作就會生效。

·         Locked

該查詢被其它查詢鎖定。

·         Sending data

線程正在為SELECT語句處理行,同時正在向客戶端發送數據。

·         Sorting for group

線程正在進行分類,以滿足GROUP BY要求。

·         Sorting for order

線程正在進行分類,以滿足ORDER BY要求。

·         Opening tables

線程正在試圖打開一個表。這應該是非常快的過程,除非打開操作受到阻止。例如,一個ALTER TABLE或一個LOCK TABLE語句可以阻止打開一個表,直到語句完成為止。

·         Removing duplicates

查詢正在使用SELECT DISTINCT。使用時,在早期階段,MySQL不能優化不同的操作。因此,MySQL要求一個額外的階段,以便在把結果發送給客戶端之前取消所有的復制行。

·         Reopen table

線程得到一個表鎖定,但是在得到鎖定后被通知帶下方的表結構已更改了。它已經釋放了鎖定,關閉了表,并試圖重新打開它。

·         Repair by sorting

修復代碼正在使用一個分類來創建索引。

·         Repair with keycache

修復代碼正在通過關鍵緩存一個接一個地使用創建關鍵字。這比通過分類修復要慢很多。

·         Searching rows for update

線程正在進行第一階段,以在更新之前,查找所有匹配的行。如果UPDATE正在更改用于查找相關行的索引,則必須這么做。

·         Sleeping

線程正在等待客戶端,以向它發送一個新語句。

·         System lock

線程正在等待得到一個用于表的外部系統鎖定。如果您沒有正在使用多個正在訪問同一個表的mysqld服務器,則您可以使用--skip-external-locking選項禁用系統鎖定。

·         Upgrading lock

INSERT DELAYED管理程序正在試圖得到一個表鎖定,以插入行。

·         Updating

線程正在搜索行,并正在更新這些行。

·         User Lock

線程正在等待GET_LOCK()

·         Waiting for tables

線程得到一個通知,表的底層結構已經改變,需要重新打開表以得到新的結構。但是,為了能重新打開表,必須等待,直到所有其它的線程已經關閉了正在被質詢的表。

如果其它線程已經對正在被質詢的表使用了FLUSH TABLES或以下語句之一:FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLEOPTIMIZE TABLE;則會出現通知。

·         waiting for handler insert

INSERT DELAYED管理程序已經處理了所有處于等待狀態的插入,并正在等待新插入。

多數狀態對應于非常快的操作。如果一個線程在這些狀態下停留了數秒,則可能是有問題,需要進行調查。

有一些其它的狀態,在前面的清單中沒有提及,但是其中有很多狀態對于查找服務器中的程序錯誤是有用的。

13.5.4.17.?SHOW STATUS語法

SHOW [GLOBAL | SESSION] STATUS [LIKE 'pattern']

SHOW STATUS提供服務器狀態信息。此信息也可以使用mysqladmin extended-status命令獲得。

此處顯示了局部的輸出。對于您的服務器,變量和值的清單可以是不同的。在5.3.4節,“服務器狀態變量”中給出了每個變量的意義。

mysql> SHOW STATUS;
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| Aborted_clients          | 0          |
| Aborted_connects         | 0          |
| Bytes_received           | 155372598  |
| Bytes_sent               | 1176560426 |
| Connections              | 30023      |
| Created_tmp_disk_tables  | 0          |
| Created_tmp_tables       | 8340       |
| Created_tmp_files        | 60         |
...                       ...          ...
| Open_tables              | 1          |
| Open_files               | 2          |
| Open_streams             | 0          |
| Opened_tables            | 44600      |
| Questions                | 2026873    |
...                       ...          ...
| Table_locks_immediate    | 1920382    |
| Table_locks_waited       | 0          |
| Threads_cached           | 0          |
| Threads_created          | 30022      |
| Threads_connected        | 1          |
| Threads_running          | 1          |
| Uptime                   | 80380      |
+--------------------------+------------+

使用LIKE子句,該語句只顯示匹配該樣式的那些變量:

mysql> SHOW STATUS LIKE 'Key%';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| Key_blocks_used    | 14955    |
| Key_read_requests  | 96854827 |
| Key_reads          | 162040   |
| Key_write_requests | 7589728  |
| Key_writes         | 3813196  |
+--------------------+----------+

使用GLOBAL選項,您可以得到所有MySQL連接的狀態值。使用SESSION,您可以得到所有當前連接的狀態值。如果您兩個選項都不使用,則默認值為SESSIONLOCALSESSION的同義詞。

注意,有些狀態變量只有一個全局值。對于這些變量,使用GLOBALSESSION會得到同樣的值。

13.5.4.18.?SHOW TABLE STATUS語法

SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']

SHOW TABLE STATUS的性質與SHOW TABLE類似,不過,可以提供每個表的大量信息。您也可以使用mysqlshow --status db_name命令得到此清單。

本語句也顯示視圖信息。

對于NDB Cluster表,本語句的輸出顯示Avg_row_lengthData_length列的適當值,不過BLOB列沒有被考慮進來。另外,復制數量在Comment列中顯示(作為number_of_replicas)。

SHOW TABLE STATUS會返回以下字段:

·         Name

表的名稱。

·         Engine

表的存儲引擎。在MySQL 4.1.2之前,本值被標記為Type。請參見第15章:存儲引擎和表類型

·         Version

表的.frm文件的版本號。

·         Row_format

行存儲格式(Fixed, Dynamic, Compressed, Redundant, Compact)。InnoDB表的格式被報告為RedundantCompact

·         Rows

行的數目。部分存儲引擎,如MyISAM,存儲精確的數目。

對于其它存儲引擎,比如InnoDB,本值是一個大約的數,與實際值相差可達4050%。在這些情況下,使用SELECT COUNT(*)來獲得準確的數目。

對于在INFORMATION_SCHEMA數據庫中的表,Rows值為NULL

·         Avg_row_length

平均的行長度。

·         Data_length

數據文件的長度。

·         Max_data_length

數據文件的最大長度。如果給定了數據指針的大小,這是可以被存儲在表中的數據的字節總數。

·         Index_length

索引文件的長度。

·         Data_free

被整序,但是未使用的字節的數目。

·         Auto_increment

下一個AUTO_INCREMENT值。

·         Create_time

什么時候表被創建。

·         Update_time

什么時候數據文件被最后一次更新。

·         Check_time

什么時候表被最后一次檢查。不是所有的存儲引擎此時都更新,在此情況下,值為NULL

·         Collation

表的字符集和整序。

·         Checksum

活性校驗和值。

·         Create_options

CREATE TABLE同時使用的額外選項。

·         Comment

創建表時使用的評注(或者有關為什么MySQL可以訪問表信息的說明)。

在表評注中,InnoDB表報告表所屬的表空間的空閑空間。對于一個位于共享表空間中的表,這是共享表空間中的空閑空間。如果您正在使用多個表空間,并且該表有自己的表空間,則空閑空間只用于此表。

對于MEMORY (HEAP)表,Data_length, Max_data_lengthIndex_length值近似于被整序的存儲器的實際值。整序算法預留了大量的存儲器,以減少整序操作的數量。

對于視圖,由SHOW TABLE STATUS顯示的所有字段均為NULL。例外情況是Name指示為視圖名稱同時Comment稱為視圖。

13.5.4.19.?SHOW TABLES語法

SHOW [FULL] TABLES [FROM db_name] [LIKE 'pattern']

SHOW TABLES列舉了給定數據庫中的非TEMPORARY表。您也可以使用mysqlshow db_name命令得到此清單。

本命令也列舉數據庫中的其它視圖。支持FULL修改符,這樣SHOW FULL TABLES就可以顯示第二個輸出列。對于一個表,第二列的值為BASE TABLE;對于一個視圖,第二列的值為VIEW

注釋:如果您對于一個表沒有權限,則該表不會在來自SHOW TABLES或的mysqlshow db_name輸出中顯示。

13.5.4.20.?SHOW TRIGGERS語法

SHOW TRIGGERS [FROM db_name] [LIKE expr]

SHOW TRIGGERS列出了目前被MySQL服務器定義的觸發程序。

對于在21.3節,“使用觸發程序”中定義的觸發程序ins_sum,本語句的輸出顯示如下:

mysql> SHOW TRIGGERS LIKE 'acc%';
+---------+--------+---------+-------------------------------+--------+---------+
| Trigger | Event  | Table   | Statement                     | Timing | Created |
+---------+--------+---------+-------------------------------+--------+---------+
| ins_sum | INSERT | account |  SET @sum = @sum + NEW.amount | BEFORE | NULL    |
+---------+--------+---------+-------------------------------+--------+---------+

注釋:當使用一個含有SHOW TRIGGERSLIKE子句時,待匹配的表達式(expr)會與觸發程序定義時所在的表的名稱相比較,而不與觸發程序的名稱相比較:

mysql> SHOW TRIGGERS LIKE 'ins%';
Empty set (0.01 sec)

對本語句輸出中的各列的簡要解釋如下:

·         Trigger: 觸發程序的名稱。

·         Event: 調用觸發程序的時間。必須為'INSERT', 'UPDATE''DELETE'.之一。

·         Table: 觸發程序定義時對應的表。

·         Statement: 當觸發程序被調用時執行的語句。這與在INFORMATION_SCHEMA.TRIGGERSACTION_STATEMENT列中顯示的文本一樣。

·         Timing: 'BEFORE''AFTER'兩個值之一。

·         Created: 目前,本列的值為NULL

為了執行SHOW TRIGGERS,您必須擁有SUPER權限。

同時也見23.1.16節,“INFORMATION_SCHEMA TRIGGERS表”

13.5.4.21.?SHOW VARIABLES語法

SHOW [GLOBAL | SESSION] VARIABLES [LIKE 'pattern']

SHOW VARIABLES顯示了部門MySQL系統變量的值。本信息也可以使用mysqladmin variables命令獲得。

使用GLOBAL選項,您可以獲得被用于MySQL新連接的值。使用SESSION,您可以得到對于當前連接起效的值。如果您兩個選項都不使用,默認值為SESSION

LOCALSESSION的同義詞。

如果默認值不合適,當mysqld啟動時或在SET語句運行過程中,您可以使用命令行選項設置多數的這類變量。請參見5.3.1節,“mysqld命令行選項”13.5.3節,“SET語法

此處顯示了部分的輸出。對于您的服務器,變量和值的清單會有所不同。在5.3.3節,“服務器系統變量”中給出了每個變量的意義。在7.5.2節,“調節服務器參數”中提供了有關調整變量的信息。

mysql> SHOW VARIABLES;
+---------------------------------+-----------------------------------------------+
| Variable_name                   | Value                                         |
+---------------------------------+-----------------------------------------------+
| auto_increment_increment        | 1                                             |
| auto_increment_offset           | 1                                             |
| automatic_sp_privileges         | ON                                            |
| back_log                        | 50                                            |
| basedir                         | /home/jon/bin/mysql-5.1/                      |
| binlog_cache_size               | 32768                                         |
| bulk_insert_buffer_size         | 8388608                                       |
| character_set_client            | latin1                                        |
| character_set_connection        | latin1                                        |
...                               ...                                              
| max_user_connections            | 0                                             |
| max_write_lock_count            | 4294967295                                    |
| multi_range_count               | 256                                           |
| myisam_data_pointer_size        | 6                                             |
| myisam_max_sort_file_size       | 2147483647                                    |
| myisam_recover_options          | OFF                                           |
| myisam_repair_threads           | 1                                             |
| myisam_sort_buffer_size         | 8388608                                       |
| ndb_autoincrement_prefetch_sz   | 32                                            |
| ndb_cache_check_time            | 0                                             |
| ndb_force_send                  | ON                                            |
...                               ...                                                       ...    
| time_zone                       | SYSTEM                                        |
| timed_mutexes                   | OFF                                           |
| tmp_table_size                  | 33554432                                      |
| tmpdir                          |                                               |
| transaction_alloc_block_size    | 8192                                          |
| transaction_prealloc_size       | 4096                                          |
| tx_isolation                    | REPEATABLE-READ                               |
| updatable_views_with_limit      | YES                                           |
| version                         | 5.1.2-alpha-log                               |
| version_comment                 | Source distribution                           |
| version_compile_machine         | i686                                          |
| version_compile_os              | suse-linux                                    |
| wait_timeout                    | 28800                                         |
+---------------------------------+-----------------------------------------------+

使用LIKE子句,本語句只顯示與樣式相匹配的變量:

mysql> SHOW VARIABLES LIKE 'have%';
+-----------------------+----------+
| Variable_name         | Value    |
+-----------------------+----------+
| have_archive          | YES      |
| have_bdb              | NO       |
| have_blackhole_engine | YES      |
| have_compress         | YES      |
| have_crypt            | YES      |
| have_csv              | YES      |
| have_example_engine   | NO       |
| have_federated_engine | NO       |
| have_geometry         | YES      |
| have_innodb           | YES      |
| have_isam             | NO       |
| have_ndbcluster       | DISABLED |
| have_openssl          | NO       |
| have_partition_engine | YES      |
| have_query_cache      | YES      |
| have_raid             | NO       |
| have_rtree_keys       | YES      |
| have_symlink          | YES      |
+-----------------------+----------+

13.5.4.22.?SHOW WARNINGS語法

SHOW WARNINGS [LIMIT [offset,] row_count]
SHOW COUNT(*) WARNINGS

SHOW WARNINGS顯示由上一個生成消息的語句導致的錯誤、警告和注意消息。如果上一個使用表的語句未生成消息,則什么也不顯示。SHOW ERRORS是其相關語句,只顯示錯誤。請參見13.5.4.9節,“SHOW ERRORS語法”

對于使用一個表的每個新語句,消息清單均重新設置。

SHOW COUNT(*) WARNINGS語句顯示錯誤、警告和注意的總數。您也可以從warning_count變量中找回此數目。

SHOW COUNT(*) WARNINGS;
SELECT @@warning_count;

如果max_error_count系統變量設置得過低,以致于有的消息沒有被存儲,則warning_count值可能比由SHOW WARNINGS顯示的消息數目要大。本節后部顯示的例子展示了這類情況是如何發生的。

LIMIT子句具有與SELECT語句相同的語法。請參見13.2.7節,“SELECT語法”

MySQL服務器會發回由上一個語句引起的錯誤、警告和注意的總數。如果您正在使用C API,則此值可以通過調用mysql_warning_count()來獲得。請參見25.2.3.69節,“mysql_warning_count()”

對于如LOAD DATA INFILE等語句和如INSERT, UPDATE, CREATE TABLEALTER TABLEDML語句,會生成警告。

以下DROP TABLE語句會導致一個注意:

mysql> DROP TABLE IF EXISTS no_such_table;
mysql> SHOW WARNINGS;
+-------+------+-------------------------------+
| Level | Code | Message                       |
+-------+------+-------------------------------+
| Note  | 1051 | Unknown table 'no_such_table' |
+-------+------+-------------------------------+

以下是一個簡單的例子,顯示了對于CREATE TABLE的一個語法警告,和對于INSERT的轉換警告:

mysql> CREATE TABLE t1 (a TINYINT NOT NULL, b CHAR(4)) TYPE=MyISAM;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1287
Message: 'TYPE=storage_engine' is deprecated, use
         'ENGINE=storage_engine' instead
1 row in set (0.00 sec)
 
mysql> INSERT INTO t1 VALUES(10,'mysql'),(NULL,'test'),
    -> (300,'Open Source');
Query OK, 3 rows affected, 4 warnings (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 4
 
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1265
Message: Data truncated for column 'b' at row 1
*************************** 2. row ***************************
  Level: Warning
   Code: 1263
Message: Data truncated, NULL supplied to NOT NULL column 'a' at row 2
*************************** 3. row ***************************
  Level: Warning
   Code: 1264
Message: Data truncated, out of range for column 'a' at row 3
*************************** 4. row ***************************
  Level: Warning
   Code: 1265
Message: Data truncated for column 'b' at row 3
4 rows in set (0.00 sec)

要存儲的錯誤、警告和注意消息的最大數目由max_error_count系統變量控制。默認情況下,該值為64。要更改您想要存儲的信息的數目,需更改max_error_count值。在下面的例子中,ALTER TABLE語句會產生三個警告消息,但是只有一個被存儲,因為max_error_count被設置為1

mysql> SHOW VARIABLES LIKE 'max_error_count';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_error_count | 64    |
+-----------------+-------+
1 row in set (0.00 sec)
 
mysql> SET max_error_count=1;
Query OK, 0 rows affected (0.00 sec)
 
mysql> ALTER TABLE t1 MODIFY b CHAR;
Query OK, 3 rows affected, 3 warnings (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 3
 
mysql> SELECT @@warning_count;
+-----------------+
| @@warning_count |
+-----------------+
|               3 |
+-----------------+
1 row in set (0.01 sec)
 
mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1263 | Data truncated for column 'b' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

要禁用警告,需把max_error_count設置為0。在此情況下,warning_count仍然指示有多少警告已經發生,但是這些消息不被存儲。

您可以把SQL_NOTES會話變量設置為0,使“注意”級別的警告不被記錄。

13.5.5. 其它管理語句

13.5.5.1.?CACHE INDEX語法

CACHE INDEX
  tbl_index_list [, tbl_index_list] ...
  IN key_cache_name
 
tbl_index_list:
  tbl_name [[INDEX|KEY] (index_name[, index_name] ...)]

CACHE INDEX語句把表索引分配給某個關鍵緩存。該語句只用于MyISAM表。

下列語句把索引從表t1, t2t3分配到名為hot_cache的關鍵緩存:

mysql> CACHE INDEX t1, t2, t3 IN hot_cache;
+---------+--------------------+----------+----------+
| Table   | Op                 | Msg_type | Msg_text |
+---------+--------------------+----------+----------+
| test.t1 | assign_to_keycache | status   | OK       |
| test.t2 | assign_to_keycache | status   | OK       |
| test.t3 | assign_to_keycache | status   | OK       |
+---------+--------------------+----------+----------+

CACHE INDEX語法允許您指定,只有來自表的特定索引應被分配給緩存。但是,當前的實施會把所有的表索引分配給緩存,所以必須指定表名稱,不能指定其它的。

被引用到CACHE INDEX語句中的關鍵緩存可以這樣創建,即通過使用一個參數設置語句或在服務器參數設置中設置其大小。舉例說明:

mysql> SET GLOBAL keycache1.key_buffer_size=128*1024;

關鍵緩存參數可以被作為一個結構化系統變量的成分進行訪問。請參見9.4.1節,“結構式系統變量”

在您可以把索引分配給一個關鍵緩存以前,緩存必須存在:

mysql> CACHE INDEX t1 IN non_existent_cache;
ERROR 1284 (HY000): Unknown key cache 'non_existent_cache'

默認情況下,表索引被分配給在服務器啟動時被創建的主(默認)鍵緩存。當一個鍵高速緩沖被破壞時,所有被分配到此緩存中的索引會再次被分配給默認的 鍵高速緩沖。

索引的分配會對服務器產生全局性影響:如果一個客戶端把一個索引分配給一個給定的緩存,則不論什么客戶端發布查詢,本緩存都被用于所有涉及索引的查詢。

13.5.5.2.?FLUSH語法

FLUSH [LOCAL | NO_WRITE_TO_BINLOG] flush_option [, flush_option] ...

如果您想要清除MySQL使用的部分內部緩存,您應該使用FLUSH語句。要執行FLUSH,您必須擁有RELOAD權限。

flush_option可以為以下的任何一個:

·         HOSTS

用于清空主機緩存表。如果有的主機更改了IP號或如果您得到了錯誤信息Host host_name is blocked,則您應該刷新主機表。當在連接到MySQL服務器時,如果對于一個給定的主機,接連出現錯誤“多于max_connect_errors”,此時,MySQL會假定出現了錯誤,并阻止主機后續的連接申請。刷新主機表允許主機嘗試再次連接。請參見A.2.5節,“主機的host_name被屏蔽。您可以使用max_connect_errors=999999999啟動mysqld,以避免此錯誤信息。

·         DES_KEY_FILE

用于在服務器啟動時,從采用--des-key-file選項指定的文件重新載入DES關鍵字。

·         LOGS

用于關閉并重新打開所有的日志文件。如果您已經指定了一個更新日志文件或一個二進制日志文件,同時沒有擴展,則相對于前一個文件,日志文件的擴展號增加1。如果您在文件名稱中使用了一個擴展,則MySQL會關閉并重新打開日志文件。在Unix中,當相mysqld服務器發送一個SIGHUP信號時,也會如此(例外情況是部分Mac OS X 10.3版本。在這些版本中,mysqld忽略SIGHUPSIGQUIT)。

如果服務器使用--log-error選項,則FLUSH LOGS會導致錯誤日志被重命名(使用后綴-old),同時mysqld會創建一個新的空日志文件。如果沒有給定--log-error選項,則不會進行重命名。

·         PRIVILEGES

用于從mysql數據庫中的授權表重新載入權限。

·         QUERY CACHE

對查詢緩存進行整理碎片,以更好得利用存儲器。與RESET QUERY CACHE不同,本語句不會從緩存中取消任何查詢。

·         STATUS

用于把多數狀態變量重新設置為零。只在當調試查詢時,您才應該使用此項。請參見1.7.1.3節,“如何通報缺陷和問題”

·         {TABLE | TABLES} [tbl_name [, tbl_name] ...]

當沒有表被命名時,關閉所有打開的表,并迫使所有正在使用的表關閉。這也會刷新查詢緩存。此項含有一個或多個表名稱,只刷新給定的表。和RESET QUERY CACHE語句一樣,FLUSH TABLES還會取消來自查詢緩存的所有查詢結果。

·         TABLES WITH READ LOCK

對于所有帶讀取鎖定的數據庫,關閉所有打開的表,并鎖定所有的表,直到您執行UNLOCK TABLES為止。如果您擁有一個可以及時進行快照的文件系統,比如Veritas,則這是進行備份的非常方便的方法。

·         USER_RESOURCES

用于把所有每小時用戶資源重新設置為零。這可以使已經達到了每小時連接、查詢或更新限值的客戶端立刻重新恢復活性。FLUSH USER_RESOURCES不適用于同時連接的最大限值。請參見13.5.1.3節,“GRANT和REVOKE語法”

FLUSH語句被寫入二進制日志,除非使用了自選的NO_WRITE_TO_BINLOG關鍵字(或其別名LOCAL)。 注釋:在任何情況下,FLUSH LOGS, FLUSH MASTER, FLUSH SLAVEFLUSH TABLES WITH READ LOCK都不會被記入日志,因為如果它們被復制到一個從屬服務器上,會導致出現問題。

您也可以使用flush-hosts, flush-logs, flush-privileges, flush-statusflush-tables命令訪問含有mysqladmin應用程序的語句。

注釋:在MySQL 5.1.2-alpha中,不可能在已存儲的函數或觸發程序中發布FLUSH語句。不過,您可以在已存儲的過程中使用FLUSH,只要它們不會從已存儲的函數或觸發程序中被調用。請參見I.1節,“對存儲子程序和觸發程序的限制”

要了解有關RESET語句與復制同時使用的信息,也可以見13.5.5.5節,“RESET語法”

13.5.5.3.?KILL語法

KILL [CONNECTION | QUERY] thread_id

每個與mysqld的連接都在一個獨立的線程里運行,您可以使用SHOW PROCESSLIST語句查看哪些線程正在運行,并使用KILL thread_id語句終止一個線程。

KILL允許自選的CONNECTIONQUERY修改符:

·         KILL CONNECTION與不含修改符的KILL一樣:它會終止與給定的thread_id有關的連接。

·         KILL QUERY會終止連接當前正在執行的語句,但是會保持連接的原狀。

如果您擁有PROCESS權限,則您可以查看所有線程。如果您擁有SUPER權限,您可以終止所有線程和語句。否則,您只能查看和終止您自己的線程和語句。

您也可以使用mysqladmin processlistmysqladmin kill命令來檢查和終止線程。

注釋:您不能同時使用KILLEmbedded MySQL Server庫,因為內植的服務器只運行主機應用程序的線程。它不能創建任何自身的連接線程。

當您進行一個KILL時,對線程設置一個特有的終止標記。在多數情況下,線程終止可能要花一些時間,這是因為終止標記只會在在特定的間隔被檢查:

·         SELECT, ORDER BYGROUP BY循環中,在讀取一組行后檢查標記。如果設置了終止標記,則該語句被放棄。

·         ALTER TABLE過程中,在每組行從原來的表中被讀取前,檢查終止標記。如果設置了終止標記,則語句被放棄,臨時表被刪除。

·         UPDATEDELETE運行期間,在每個組讀取之后以及每個已更行或已刪除的行之后,檢查終止標記。如果終止標記被設置,則該語句被放棄。注意,如果您正在使用事務,則變更不會被 回滾。

·         GET_LOCK()會放棄和返回NULL

·         INSERT DELAYED線程會快速地刷新(插入)它在存儲器中的所有的行,然后終止。

·         如果線程在表鎖定管理程序中(狀態:鎖定),則表鎖定被快速地放棄。

·         如果在寫入調用中,線程正在等待空閑的磁盤空間,則寫入被放棄,并伴隨"disk full"錯誤消息。

·         警告:對MyISAM表終止一個REPAIR TABLEOPTIMIZE TABLE操作會導致出現一個被損壞的沒有用的表。對這樣的表的任何讀取或寫入都會失敗,直到您再次優化或修復它(不中斷)。

13.5.5.4.?LOAD INDEX INTO CACHE語法

LOAD INDEX INTO CACHE
  tbl_index_list [, tbl_index_list] ...
 
tbl_index_list:
  tbl_name
    [[INDEX|KEY] (index_name[, index_name] ...)]
    [IGNORE LEAVES]

LOAD INDEX INTO CACHE語句會把一個表索引預載入到某個關鍵緩存中。它已經被一個明確的CACHE INDEX語句分配到此關鍵緩存中。或者,表索引被預載入到默認的關鍵緩存中。LOAD INDEX INTO CACHE只用于MyISAM表。

IGNORE LEAVES修改符只會導致索引的非葉子節點被預載入。

對于表t1t2,以下語句會預載入索引的節點(索引組):

mysql> LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
+---------+--------------+----------+----------+
| Table   | Op           | Msg_type | Msg_text |
+---------+--------------+----------+----------+
| test.t1 | preload_keys | status   | OK       |
| test.t2 | preload_keys | status   | OK       |
+---------+--------------+----------+----------+

本語句會預載入所有來自t1的索引組。它只預載入來自t2的非葉子節點的組。

LOAD INDEX INTO CACHE語法允許您指定,只有來自表的特定的索引應被預載入。但是,當前實施會把所有的表索引預載入緩存中,所以一定要指定表名稱,不能指定其它的。

13.5.5.5.?RESET語法

RESET reset_option [, reset_option] ...

RESET語句被用于清除不同的服務器操作的狀態。它也作為FLUSH語句的更強大的版本。請參見13.5.5.2節,“FLUSH語法”

為了執行RESET,您必須擁有RELOAD權限。

reset_option可以為以下的任何一項:

·         MASTER

可以刪除列于索引文件中的所有二進制日志,把二進制日志索引文件重新設置為空,并創建一個新的二進制日志文件。(在以前版本的MySQL中,被稱為FLUSH MASTER。)見13.6.1節,“用于控制主服務器的SQL語句”

·         QUERY CACHE

從查詢緩存中取消所有的查詢結果。

·         SLAVE

可以使從屬服務器忘記其在主服務器二進制日志中的復制位置,另外,也可以通過刪除原有的中繼日志文件和開始一個新文件來重新設置中繼日志。請參見13.6.2節,“用于控制從服務器的SQL語句”

13.6. 復制語句

本節敘述了與復制有關的SQL語句。一組語句被用于控制主服務器。其它的被用于控制從屬服務器。

13.6.1. 用于控制主服務器的SQL語句

可以通過SQL界面控制復制。本節討論了用于管理主復制服務器的語句。13.6.2節,“用于控制從服務器的SQL語句”討論了用于管理從屬服務器的語句。

13.6.1.1.?PURGE MASTER LOGS語法

PURGE {MASTER | BINARY} LOGS TO 'log_name'
PURGE {MASTER | BINARY} LOGS BEFORE 'date'

用于刪除列于在指定的日志或日期之前的日志索引中的所有二進制日志。這些日志也會從記錄在日志索引文件中的清單中被刪除,這樣被給定的日志成為第一個。

例如:

PURGE MASTER LOGS TO 'mysql-bin.010';
PURGE MASTER LOGS BEFORE '2003-04-02 22:46:26';

BEFORE變量的date自變量可以為'YYYY-MM-DD hh:mm:ss'格式。MASTERBINARY是同義詞。

如果您有一個活性的從屬服務器,該服務器當前正在讀取您正在試圖刪除的日志之一,則本語句不會起作用,而是會失敗,并伴隨一個錯誤。不過,如果從屬服務器是休止的,并且您碰巧清理了其想要讀取的日志之一,則從屬服務器啟動后不能復制。當從屬服務器正在復制時,本語句可以安全運行。您不需要停止它們。

要清理日志,需按照以下步驟:

1.    在每個從屬服務器上,使用SHOW SLAVE STATUS來檢查它正在讀取哪個日志。

2.    使用SHOW MASTER LOGS獲得主服務器上的一系列日志。

3.    在所有的從屬服務器中判定最早的日志。這個是目標日志。如果所有的從屬服務器是更新的,這是清單上的最后一個日志。

4.    制作您將要刪除的所有日志的備份。(這個步驟是自選的,但是建議采用。)

5.    清理所有的日志,但是不包括目標日志。

13.6.1.2.?RESET MASTER語法

RESET MASTER

可以刪除列于索引文件中的所有二進制日志,把二進制日志索引文件重新設置為空,并創建一個新的二進制日志文件。

13.6.1.3.?SET SQL_LOG_BIN語法

SET SQL_LOG_BIN = {0|1}

如果客戶端使用一個有SUPER權限的賬戶連接,則可以禁用或啟用當前連接的二進制日志記錄。如果客戶端沒有此權限,則語句被拒絕,并伴隨有錯誤。

13.6.1.4.?SHOW BINLOG EVENTS語法

SHOW BINLOG EVENTS
   [IN 'log_name'] [FROM pos] [LIMIT [offset,] row_count]

用于在二進制日志中顯示事件。如果您不指定'log_name',則顯示第一個二進制日志。

LIMIT子句和SELECT語句具有相同的語法。請參見13.2.7節,“SELECT語法”

注釋:當服務器把二進制日志的完整內容(該日志包括多數的由MySQL執行的查詢)轉儲到stdout時,發布一個不含LIMIT子句的SHOW BINLOG EVENTS可以啟動一個過程,該過程非常消耗時間并消耗資源。要把二進制日志保存到一個文本文件中,用于以后的檢查和分析,需使用mysqlbinlog應用程序。請參見8.6節,“mysqlbinlog:用于處理二進制日志文件的實用工具”

13.6.1.5.?SHOW MASTER LOGS語法

SHOW MASTER LOGS
SHOW BINARY LOGS

用于列出服務器中的二進制日志文件。本語句被用作13.6.1.1節,“PURGE MASTER LOGS語法”中所述的過程的一部分,用于確定哪些日志可以被清理。

mysql> SHOW BINARY LOGS;
+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000015 |    724935 |
| binlog.000016 |    733481 |
+---------------+-----------+

SHOW BINARY LOGSSHOW MASTER LOGS相當。

13.6.1.6.?SHOW MASTER STATUS語法

SHOW MASTER STATUS

用于提供主服務器二進制日志文件的狀態信息。例如:

mysql > SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+
| File          | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| mysql-bin.003 | 73       | test         | manual,mysql     |
+---------------+----------+--------------+------------------+

13.6.1.7.?SHOW SLAVE HOSTS語法

SHOW SLAVE HOSTS

用于顯示當前使用主服務器注冊的復制從屬服務器的清單。不以--report-host=slave_name選項為開頭的從屬服務器不會顯示在本清單中。

13.6.2. 用于控制從服務器的SQL語句

復制操作可以通過SQL界面控制。本節討論了用于管理從屬復制服務器的語句。13.6.1節,“用于控制主服務器的SQL語句”討論了用于管理主服務器的語句。

13.6.2.1.?CHANGE MASTER TO語法

  CHANGE MASTER TO master_def [, master_def] ...
 
master_def:
      MASTER_HOST = 'host_name'
    | MASTER_USER = 'user_name'
    | MASTER_PASSWORD = 'password'
    | MASTER_PORT = port_num
    | MASTER_CONNECT_RETRY = count
    | MASTER_LOG_FILE = 'master_log_name'
    | MASTER_LOG_POS = master_log_pos
    | RELAY_LOG_FILE = 'relay_log_name'
    | RELAY_LOG_POS = relay_log_pos
    | MASTER_SSL = {0|1}
    | MASTER_SSL_CA = 'ca_file_name'
    | MASTER_SSL_CAPATH = 'ca_directory_name'
    | MASTER_SSL_CERT = 'cert_file_name'
    | MASTER_SSL_KEY = 'key_file_name'
    | MASTER_SSL_CIPHER = 'cipher_list'

可以更改從屬服務器用于與主服務器進行連接和通訊的參數。

MASTER_USER, MASTER_PASSWORD, MASTER_SSL, MASTER_SSL_CA, MASTER_SSL_CAPATH, MASTER_SSL_CERT, MASTER_SSL_KEYMASTER_SSL_CIPHER用于向從屬服務器提供有關如何與主服務器連接的信息。

即使對于在編譯時沒有SSL支持的從屬服務器,SSL選項(MASTER_SSL, MASTER_SSL_CA, MASTER_SSL_CAPATH, MASTER_SSL_CERT, MASTER_SSL_KEYMASTER_SSL_CIPHER)也可以被更改。它們被保存到master.info文件中,但是會被忽略,直到您使用一個SSL支持已啟用的服務器。

如果您不指定一個給定的參數,則它會保持其原有的值。例外情況在后面的討論中進行了說明。舉例說明,如果用于連接到您的MySQL主服務器的 密碼被更改了,您只需發布這些語句,就可以告知從屬服務器新的密碼:

mysql> STOP SLAVE; -- if replication was running
mysql> CHANGE MASTER TO MASTER_PASSWORD='new3cret';
mysql> START SLAVE; -- if you want to restart replication

沒有必要指定沒有改變的參數(主機、接口、用戶等)。

MASTER_HOSTMASTER_PORT是主服務器主機和其TCP/IP接口的主機名(或IP地址)。注意,如果MASTER_HOSTlocalhost相等,那么,和MySQL的其它部分一樣,接口可以被忽略(例如,如果可以使用Unix插槽文件)。

如果您指定了MASTER_HOSTMASTER_PORT,則從屬服務器會假定主服務器與以前不一樣(即使您指定的主機或接口值與當前值是一樣的。)在此情況下,主服務器二進制日志的名稱和位置的原有值不再適用,因此,如果您不指定語句中的MASTER_LOG_FILEMASTER_LOG_POSMASTER_LOG_FILE=''MASTER_LOG_POS=4會被靜默地添加。

MASTER_LOG_FILEMASTER_LOG_POS坐標點,從屬服務器I/O線程在啟動之后從主服務器讀取。如果您只指定了其中一個,則從屬服務器不能指定RELAY_LOG_FILERELAY_LOG_POS。如果MSATER_LOG_FILEMASTER_LOG_POS都沒有被指定,則從屬服務器會使用在CHANGE MASTER被發布前的最后一個slave SQL thread坐標。當您只想改變要使用的 密碼時,這可以確保復制的連續性。即使從屬服務器SQL線程落后于從屬服務器I/O線程,也可以確保復制的連續性。

CHANGE MASTER會刪除所有的中繼日志文件并啟動一個新的日志,除非您指定了RELAY_LOG_FILERELAY_LOG_POS。在此情況下,中繼日志被保持;relay_log_purge全局變量被靜默地設置為0

CHANGE MASTER TO可以更新master.inforelay-log.info文件的內容。

當您擁有主服務器快照并擁有日志和對應的偏移量時,CHANGE MASTER對于設置從屬服務器是有用的。在把快照載入從屬服務器之后,您可以在從屬服務器上運行CHANGE MASTER TO MASTER_LOG_FILE='log_name_on_master', MASTER_LOG_POS=log_offset_on_master

舉例說明:

mysql> CHANGE MASTER TO
    ->     MASTER_HOST='master2.mycompany.com',
    ->     MASTER_USER='replication',
    ->     MASTER_PASSWORD='bigs3cret',
    ->     MASTER_PORT=3306,
    ->     MASTER_LOG_FILE='master2-bin.001',
    ->     MASTER_LOG_POS=4,
    ->     MASTER_CONNECT_RETRY=10;
 
mysql> CHANGE MASTER TO
    ->     RELAY_LOG_FILE='slave-relay-bin.006',
    ->     RELAY_LOG_POS=4025;

第一個例子可以更改主服務器及其二進制日志坐標。當想要設置從屬服務器來復制主服務器時使用。

第二個例子顯示了較少被使用的一個操作。當從屬服務器含有中繼日志,并且您出于某種原因想要執行此日志時使用。要這么做時,不需要連接主服務器。您只需要使用CHANGE MASTER TO并啟動SQL線程(START SLAVE SQL_THREAD)。

您甚至可以在一個用于獨立非從屬服務器的非復制型設置中使用第二種操作,在崩潰之后進行復原。假設您的服務器已崩潰,同時您已恢復了備份。您想要重新播放服務器自己的二進制日志(不是中繼日志,而是正規的二進制文件),例如名為myhost-bin.*。首先,應在安全的地方制作這些二進制日志的備份,以防您沒有完全遵守以下步驟,意外地讓服務器清理了二進制文件。使用SET GLOBAL relay_log_purge=0,進一步增加安全性。然后啟動不含--log-bin選項的服務器。使用--replicate-same-server-id, --relay-log=myhost-bin(讓服務器相信,這些正規的二進制日志是中繼日志)和--skip-slave-start options選項。當服務器啟動后,發布以下語句:

mysql> CHANGE MASTER TO
    ->     RELAY_LOG_FILE='myhost-bin.153',
    ->     RELAY_LOG_POS=410,
    ->     MASTER_HOST='some_dummy_string';
mysql> START SLAVE SQL_THREAD;

服務器會讀取并執行自己的二進制日志,完成崩潰復原。當復原完成后,運行STOP SLAVE,關閉服務器,刪除master.inforelay-log.info,并使用原來的選項重新啟動服務器。

要讓服務器認為它是一個從屬服務器,需要指定MASTER_HOST(甚至使用假值)。

13.6.2.2.?LOAD DATA FROM MASTER語法

LOAD DATA FROM MASTER

本命令用于對主服務器進行快照,并拷貝到從屬服務器上。它可以更新MASTER_LOG_FILEMASTER_LOG_POS的值,這樣,從屬服務器就可以從正確的位置開始進行復制。使用--replicate-*-do-*--replicate-*-ignore-*選項指定的表和數據庫排除規則均被兌現。--replicate-rewrite-db沒有被考慮。這是因為使用本選項,用戶就可以設置一個例如--replicate-rewrite-db=db1->db3--replicate-rewrite-db=db2->db3的非唯一映射。當從主服務器載入表時,該映射會使從屬服務器發生混淆。

本語句的使用受以下條件的制約:

·         只對MyISAM表起作用。如果試圖載入一個非MyISAM表,會導致以下錯誤:

·                ERROR 1189 (08S01): Net error reading from master

·         當拍攝快照時,會獲得對主服務器的全局讀取鎖定。在載入操作期間,該鎖定會阻止對主服務器的更新。

如果您正在載入大表,您可能必須對主服務器和從屬服務器均增加net_read_timeoutnet_write_timeout值。請參見5.3.3節,“服務器系統變量”

注意,LOAD DATA FROM MASTER不從mysql數據庫拷貝任何表。這可以更容易地讓主服務器和從屬服務器擁有不同的用戶和權限。

LOAD DATA FROM MASTER語句要求用于連接主服務器的復制帳戶,以便讓主服務器擁有RELOADSUPER權限,并讓所有您想要載入的主服務器表擁有SELECT權限。所有的用戶不擁有SELECT權限的主服務器表均被LOAD DATA FROM MASTER忽略。這是因為主服務器會對用戶隱藏它們:LOAD DATA FROM MASTER會調用SHOW DATABASES以了解要載入的主服務器數據庫,但是SHOW DATABASES只會返回用戶有部分權限的數據庫。請參見13.5.4.6節,“SHOW DATABASES語法”。在從屬服務器方面,發布LOAD DATA FROM MASTER的用戶應擁有授權,以取消或創建被復制的數據庫和表。

13.6.2.3.?LOAD TABLE tbl_name FROM MASTER語法

LOAD TABLE tbl_name FROM MASTER

用于把表的拷貝從主服務器轉移到從屬服務器。本語句的主要作用是調試LOAD DATA FROM MASTER。它要求用于連接主服務器的帳戶擁有對主服務器的RELOADSUPER權限,并擁有對要載入的主服務器表的SELECT權限。在從屬服務器方面,發布LOAD TABLE FROM MASTER的用戶應擁有取消和創建表的權限。

用于LOAD DATA FROM MASTER的條件也適用于這里。舉例說明,LOAD TABLE FROM MASTER僅對于MyISAM表起作用。對LOAD DATA FROM MASTER的暫停注意也適用。

13.6.2.4.?MASTER_POS_WAIT()語法

SELECT MASTER_POS_WAIT('master_log_file', master_log_pos)
這實際上是一個函數,而不是一個語句。它被用于確認,從屬服務器已讀取并執行了到達主服務器二進制日志的給定位置。要了解完整的描述,請參見12.9.4節,“其他函數”

13.6.2.5.?RESET SLAVE語法

RESET SLAVE

用于讓從屬服務器忘記其在主服務器的二進制日志中的復制位置。本語句被用于進行一個明確的啟動:它會刪除master.inforelay-log.info文件,以及所有的中繼日志,并啟動一個新的中繼日志。

注釋:所有的中繼日志被刪除,即使它們沒有被從屬服務器SQL線程完全的執行。(如果您已經發布了一個SLAVE語句或如果從屬服務器的載入量很大,則這對于一個復制從屬服務器是一個很可能出現的情況。)

存儲在master.info文件中的連接信息通過使用在對應的啟動選項中指定的值,被立即重新設置了。此信息包括主服務器主機、主服務器接口、主服務器用戶和主服務器 密碼等值。當從屬服務器SQL線程被中止時,它位于正在復制的臨時表的中間,并且發布了RESET SLAVE,則已被復制的臨時表在從屬服務器中被刪除。

13.6.2.6.?SET GLOBAL SQL_SLAVE_SKIP_COUNTER語法

SET GLOBAL SQL_SLAVE_SKIP_COUNTER = n

從主服務器中跳過后面的n個事件。要復原由語句導致的復制中止,這是有用的。

僅當從屬線程沒有正在運行時,本語句時有效的。否則,會產生一個錯誤。

13.6.2.7.?SHOW SLAVE STATUS語法

SHOW SLAVE STATUS

用于提供有關從屬服務器線程的關鍵參數的信息。如果您使用mysql客戶端發布此語句,則您可以使用一個\G語句終止符來獲得更便于閱讀的豎向版面,而不是使用分號:

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
       Slave_IO_State: Waiting for master to send event
          Master_Host: localhost
          Master_User: root
          Master_Port: 3306
        Connect_Retry: 3
      Master_Log_File: gbichot-bin.005
  Read_Master_Log_Pos: 79
       Relay_Log_File: gbichot-relay-bin.005
        Relay_Log_Pos: 548
Relay_Master_Log_File: gbichot-bin.005
     Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
      Replicate_Do_DB:
  Replicate_Ignore_DB:
           Last_Errno: 0
           Last_Error:
         Skip_Counter: 0
  Exec_Master_Log_Pos: 79
      Relay_Log_Space: 552
      Until_Condition: None
       Until_Log_File:
        Until_Log_Pos: 0
   Master_SSL_Allowed: No
   Master_SSL_CA_File:
   Master_SSL_CA_Path:
      Master_SSL_Cert:
    Master_SSL_Cipher:
       Master_SSL_Key:
Seconds_Behind_Master: 8

SHOW SLAVE STATUS會返回以下字段:

·         Slave_IO_State

SHOW PROCESSLIST輸出的State字段的拷貝。SHOW PROCESSLIST用于從屬I/O線程。如果線程正在試圖連接到主服務器,正在等待來自主服務器的時間或正在連接到主服務器等,本語句會通知您。在6.3節,“復制實施細節”中列出了可能的狀態。舊版本的MySQL在連接主服務器不成功時,允許線程繼續運行。對于舊版本的MySQL,觀看此字段是必須的。如果它正在運行,則無問題;如果它沒有運行,則您會在Last_Error字段中發現錯誤(后面有說明)。

·         Master_Host

當前的主服務器主機。

·         Master_User

被用于連接主服務器的當前用戶。

·         Master_Port

當前的主服務器接口。

·         Connect_Retry

--master-connect-retry選項的當前值

·         Master_Log_File

I/O線程當前正在讀取的主服務器二進制日志文件的名稱。

·         Read_Master_Log_Pos

在當前的主服務器二進制日志中,I/O線程已經讀取的位置。

·         Relay_Log_File

SQL線程當前正在讀取和執行的中繼日志文件的名稱。

·         Relay_Log_Pos

在當前的中繼日志中,SQL線程已讀取和執行的位置。

·         Relay_Master_Log_File

SQL線程執行的包含多數近期事件的主服務器二進制日志文件的名稱。

·         Slave_IO_Running

I/O線程是否被啟動并成功地連接到主服務器上。對于舊版本的MySQL(在4.1.145.0.12之前),如果I/O線程已被啟動,即使從屬服務器仍沒有連接到主服務器上,Slave_IO_Running也將被設置到YES

·         Slave_SQL_Running

SQL線程是否被啟動。

·         Replicate_Do_DB, Replicate_Ignore_DB

使用--replicate-do-db--replicate-ignore-db選項指定的數據庫清單。

·         Replicate_Do_Table, Replicate_Ignore_Table, Replicate_Wild_Do_Table, Replicate_Wild_Ignore_Table

使用--replicate-do-table, --replicate-ignore-table, --replicate-wild-do-table--replicate-wild-ignore_table選項指定的表清單。

·         Last_Errno, Last_Error

被多數最近被執行的查詢返回的錯誤數量和錯誤消息。錯誤數量為0并且消息為空字符串意味著“沒有錯誤”。如果Last_Error值不是空值,它也會在從屬服務器的錯誤日志中作為消息顯示。

舉例說明:

Last_Errno: 1051
Last_Error: error 'Unknown table 'z'' on query 'drop table z'

該消息指示,表z曾經存在于在主服務器中并已被取消了,但是它沒有在從屬服務器中存在過,因此對于從屬服務器,DROP TABLE失敗。(舉例說明,在設置復制時,如果您忘記了把此表拷貝到從屬服務器中,則這有可能發生。)

·         Skip_Counter

最近被使用的用于SQL_SLAVE_SKIP_COUNTER的值。

·         Exec_Master_Log_Pos

來自主服務器的二進制日志的由SQL線程執行的上一個時間的位置(Relay_Master_Log_File)。在主服務器的二進制日志中的(Relay_Master_Log_File, Exec_Master_Log_Pos)對應于在中繼日志中的(Relay_Log_File, Relay_Log_Pos)

·         Relay_Log_Space

所有原有的中繼日志結合起來的總大小。

·         Until_Condition, Until_Log_File, Until_Log_Pos

START SLAVE語句的UNTIL子句中指定的值。

Until_Condition具有以下值:

o        如果沒有指定UNTIL子句,則沒有值

o        如果從屬服務器正在讀取,直到達到主服務器的二進制日志的給定位置為止,則值為Master

o        如果從屬服務器正在讀取,直到達到其中繼日志的給定位置為止,則值為Relay

Until_Log_FileUntil_Log_Pos用于指示日志文件名和位置值。日志文件名和位置值定義了SQL線程在哪個點中止執行。

·         Master_SSL_Allowed, Master_SSL_CA_File, Master_SSL_CA_Path, Master_SSL_Cert, Master_SSL_Cipher, Master_SSL_Key

這些字段顯示了被從屬服務器使用的參數。這些參數用于連接主服務器。

Master_SSL_Allowed具有以下值:

o        如果允許對主服務器進行SSL連接,則值為Yes

o        如果不允許對主服務器進行SSL連接,則值為No

o        如果允許SSL連接,但是從屬服務器沒有讓SSL支持被啟用,則值為Ignored

SSL有關的字段的值對應于--master-ca, --master-capath, --master-cert, --master-cipher--master-key選項的值。

·         Seconds_Behind_Master

本字段是從屬服務器“落后”多少的一個指示。當從屬SQL線程正在運行時(處理更新),本字段為在主服務器上由此線程執行的最近的一個事件的時間標記開始,已經過的秒數。當此線程被從屬服務器I/O線程趕上,并進入閑置狀態,等待來自I/O線程的更多的事件時,本字段為零。總之,本字段測量從屬服務器SQL線程和從屬服務器I/O線程之間的時間差距,單位以秒計。

如果主服務器和從屬服務器之間的網絡連接較快,則從屬服務器I/O線程會非常接近主服務器,所以本字段能夠十分近似地指示,從屬服務器SQL線程比主服務器落后多少。如果網絡較慢,則這種指示不準確;從屬SQL線程經常會趕上讀取速度較慢地從屬服務器I/O線程,因此,Seconds_Behind_Master經常顯示值為0。即使I/O線程落后于主服務器時,也是如此。換句話說,本列只對速度快的網絡有用。

即使主服務器和從屬服務器不具有相同的時鐘,時間差計算也會起作用(當從屬服務器I/O線程啟動時,計算時間差。并假定從此時以后,時間差保持不變)。如果從屬SQL線程不運行,或者如果從屬服務器I/O線程不運行或未與主服務器連接,則Seconds_Behind_MasterNULL(意義為“未知”)。舉例說明,如果在重新連接之前,從屬服務器I/O線程休眠了master-connect-retry秒,則顯示NULL,因為從屬服務器不知道主服務器正在做什么,也不能有把握地說落后多少。

本字段有一個限制。時間標記通過復制被保留,這意味著,如果一個主服務器M1本身是一個從屬服務器M0,則來自M1binlog的任何事件(通過復制來自M0binlog的事件而產生),與原事件具有相同的時間標記。這可以使MySQL成功地復制TIMESTAMP。但是,Seconds_Behind_Master的缺點是,如果M1也收到來自客戶端的直接更新,則值會隨機變化,因為有時最近的M1時間來自M0,有時來自直接更新,最近的時間標記也是如此。

13.6.2.8.?START SLAVE語法

START SLAVE [thread_type [, thread_type] ... ]
START SLAVE [SQL_THREAD] UNTIL
    MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos
START SLAVE [SQL_THREAD] UNTIL
    RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos
 
thread_type: IO_THREAD | SQL_THREAD

不含選項的START SLAVE會同時啟動兩個從屬服務器線程。I/O線程從主服務器中讀取查詢,并把它們存儲在中繼日志中。SQL線程讀取中繼日志并執行查詢。START SLAVE要求SUPER權限。

如果START SLAVE成功地啟動了從屬服務器線程,則會返回,不會出現錯誤。但是,即使在此情況下,也有可能出現這樣的現象——服務器線程啟動了,然后又停止了(例如,因為它們沒有成功地連接到主服務器上,或者沒有能讀取二進制日志,或者出現了其它問題)。START SLAVE對此不會發出警告。您必須檢查從屬服務器的錯誤日志,查看是否有由從屬服務器線程產生的錯誤消息,或者使用SHOW SLAVE STATUS檢查它們是否運行正常。

您可以把IO_THREADSQL_THREAD選項添加到語句中,指明哪些線程將要啟動。

可以添加一個UNTIL子句,指定從屬服務器應啟動并運行,直到SQL線程達到主服務器二進制日志中的一個給定點為止。當SQL線程達到此點時,它會停止。如果在該語句中指定了SQL_THREAD選項,則它只會啟動SQL線程。否則,它會同時啟動兩個從屬服務器線程。如果SQL線程正在運行,則UNTIL子句被忽略,并發布一個警告。

對于一個UNTIL子句,您必須同時指定一個日志文件名和位置。不要把主服務器和中繼日志選項混合在一起。

UNTIL條件由一個后續的STOP SLAVE語句,或一個不包括UNTIL子句的START SLAVE語句,或一個服務器重啟命令重新設置。

UNTIL子句對于調試復制操作是有用的,或者可用于促使復制操作繼續,直到接近一個特定的點時為止,在此點,您想要避免讓從屬服務器復制一個語句。舉例說明,如果在主服務上執行了一個不明智的DROP TABLE語句,您可以使用UNTIL來告知從屬服務器,執行到此點就停止,不要再繼續了。要查找該事件是什么,需對主服務器日志或從屬中繼日志使用mysqlbinlog,或通過使用SHOW BINLOG EVENTS語句。

如果您正在使用UNTIL,讓從屬服務器成段地處理已復制的查詢,則建議您使用--skip-slave-start選項來啟動從屬服務器,以防止當從屬服務器啟動時,SQL線程運行。最好在一個選項文件中使用此選項,而不是在命令行中使用,這樣,如果發生了意料外的服務器重新啟動,它也不會被忘記。

SHOW SLAVE STATUS語句包括了輸出字段。這些字段顯示了UNTIL條件的當前值。

在以前版本的MySQL中,本語句被稱為SLAVE START。在MySQL 5.1中仍然接受這種用法,以便與以前版本兼容。但現在不贊成使用。

13.6.2.9.?STOP SLAVE語法
 

STOP SLAVE [thread_type [, thread_type] ... ]
 
thread_type: IO_THREAD | SQL_THREAD

用于中止從屬服務器線程。STOP SLAVE要求SUPER權限。

START SLAVE相似,本語句在使用時可以加IO_THREADSQL_THREAD選項,指明將被中止的線程。

在以前版本的MySQL中,本語句被稱為SLAVE STOP。在MySQL 5.1中仍然接受這種用法,以便與以前版本兼容。但是現在不贊成使用。

13.7. 用于預處理語句的SQL語法

MySQL 5.1對服務器一方的預制語句提供支持。如果您使用合適的客戶端編程界面,則這種支持可以發揮在MySQL 4.1中實施的高效客戶端/服務器二進制協議的優勢。候選界面包括MySQL C API客戶端庫(用于C程序)、MySQL Connector/J(用于Java程序)和MySQL Connector/NET。例如,C API可以提供一套能組成預制語句API的函數調用。請參見25.2.4節,“C API預處理語句”。其它語言界面可以對使用了二進制協議(通過在C客戶端庫中鏈接)的預制語句提供支持。有一個例子是PHP 5.0中的mysqli擴展

對預制語句,還有一個SQL界面可以利用。與在整個預制語句API中使用二進制協議相比,本界面效率沒有那么高,但是它不要求編程,因為在SQL層級,可以直接利用本界面:

·         當您無法利用編程界面時,您可以使用本界面。

·         有些程序允許您發送SQL語句到將被執行的服務器中,比如mysql客戶端程序。您可以從這些程序中使用本界面。

·         即使客戶端正在使用舊版本的客戶端庫,您也可以使用本界面。唯一的要求是,您能夠連接到一個支持預制語句SQL語法的服務器上。

預制語句的SQL語法在以下情況下使用:

·         在編代碼前,您想要測試預制語句在您的應用程序中運行得如何。或者也許一個應用程序在執行預制語句時有問題,您想要確定問題是什么。

·         您想要創建一個測試案例,該案例描述了您使用預制語句時出現的問題,以便您編制程序錯誤報告。

·         您需要使用預制語句,但是您無法使用支持預制語句的編程API

預制語句的SQL語法基于三個SQL語句:

PREPARE stmt_name FROM preparable_stmt;
 
EXECUTE stmt_name [USING @var_name [, @var_name] ...];
 
{DEALLOCATE | DROP} PREPARE stmt_name;

PREPARE語句用于預備一個語句,并賦予它名稱stmt_name,借此在以后引用該語句。語句名稱對案例不敏感。preparable_stmt可以是一個文字字符串,也可以是一個包含了語句文本的用戶變量。該文本必須展現一個單一的SQL語句,而不是多個語句。使用本語句,‘?’字符可以被用于制作參數,以指示當您執行查詢時,數據值在哪里與查詢結合在一起。‘?’字符不應加引號,即使您想要把它們與字符串值結合在一起,也不要加引號。參數制作符只能被用于數據值應該出現的地方,不用于SQL關鍵詞和標識符等。

如果帶有此名稱的預制語句已經存在,則在新的語言被預備以前,它會被隱含地解除分配。這意味著,如果新語句包含一個錯誤并且不能被預備,則會返回一個錯誤,并且不存在帶有給定名稱語句。

預制語句的范圍是客戶端會話。在此會話內,語句被創建。其它客戶端看不到它。

在預備了一個語句后,您可使用一個EXECUTE語句(該語句引用了預制語句名稱)來執行它。如果預制語句包含任何參數制造符,則您必須提供一個列舉了用戶變量(其中包含要與參數結合的值)的USING子句。參數值只能有用戶變量提供,USING子句必須準確地指明用戶變量。用戶變量的數目與語句中的參數制造符的數量一樣多。

您可以多次執行一個給定的預制語句,在每次執行前,把不同的變量傳遞給它,或把變量設置為不同的值。

要對一個預制語句解除分配,需使用DEALLOCATE PREPARE語句。嘗試在解除分配后執行一個預制語句會導致錯誤。

如果您終止了一個客戶端會話,同時沒有對以前已預制的語句解除分配,則服務器會自動解除分配。

以下SQL語句可以被用在預制語句中:CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE和多數的SHOW語句。目前不支持其它語句。

以下例子顯示了預備一個語句的兩種方法。該語句用于在給定了兩個邊的長度時,計算三角形的斜邊。

第一個例子顯示如何通過使用文字字符串來創建一個預制語句,以提供語句的文本:

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|          5 |
+------------+
mysql> DEALLOCATE PREPARE stmt1;

第二個例子是相似的,不同的是提供了語句的文本,作為一個用戶變量:

mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|         10 |
+------------+
mysql> DEALLOCATE PREPARE stmt2;

預制語句的SQL語法不能被用于帶嵌套的風格中。也就是說,被傳遞給PREPARE的語句本身不能是一個PREPARE, EXECUTEDEALLOCATE PREPARE語句。

預制語句的SQL語法與使用預制語句API調用不同。例如,您不能使用mysql_stmt_prepare() C API函數來預備一個PREPARE, EXECUTEDEALLOCATE PREPARE語句。

預制語句的SQL語法可以在已存儲的過程中使用,但是不能在已存儲的函數或觸發程序中使用。

當使用預制語句時,可以在LIMIT子句中使用占位符。請參見13.2.7節,“SELECT語法”


這是MySQL參考手冊的翻譯版本,關于MySQL參考手冊,請訪問dev.mysql.com。 原始參考手冊為英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。

广西11选五走势图彩经网