第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資料表,儲存引擎可以建立數據和索引檔案。因此,對於每個MyISAM資料表tbl_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 summary=@A 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=tonu@example.com';

注意,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=tonu@example.com';

注意,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=tonu@example.com'
    -> AND ISSUER '/C=FI/ST=Some-State/L=Helsinki/
       O=MySQL Finland AB/CN=Tonu Samuel/Email=tonu@example.com'
    -> 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()觀看您當前的鑒定user@host登錄項。

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 @@session.max_join_size=@@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 root@localhost                                           |
+---------------------------------------------------------------------+
| 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。 原始參考手冊為英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。