?
本文檔使用 PHP中文網(wǎng)手冊(cè) 發(fā)布
目錄
在本附錄中,介紹了使用諸如子查詢或視圖等MySQL特性時(shí)存在的限制。
這里介紹的某些限制適用于所有的存儲(chǔ)子程序,即存儲(chǔ)程序和存儲(chǔ)函數(shù)。某些限制僅適用于存儲(chǔ)函數(shù)而不是存儲(chǔ)程序。
對(duì)存儲(chǔ)函數(shù)的的所有限制也適用于觸發(fā)程序。
注釋:如果SQL語句,如SELECT ... INTO語句包含具有相同名稱的對(duì)列的引用以及聲明的局部變量,MySQL會(huì)將引用解釋為變量的名稱。這是一種非標(biāo)準(zhǔn)的行為,優(yōu)先順序通常是列名、然后是SQL變量和參數(shù)。請(qǐng)參見20.2.9.3節(jié),“SELECT ... INTO語句”。
存儲(chǔ)子程序不能包含任意SQL語句。在存儲(chǔ)子程序中,禁止使用下述語句:
·???????? CHECK TABLES
·???????? LOCK TABLES, UNLOCK TABLES
·???????? LOAD DATA, LOAD TABLE
·???????? SQL預(yù)處理語句(PREPARE、EXECUTE、DEALLOCATE PREPARE)。隱含意義:不能在存儲(chǔ)子程序中使用動(dòng)態(tài)SQL語句(其中,能夠以字符串形式構(gòu)造動(dòng)態(tài)語句,然后執(zhí)行它們)。從MySQL 5.0.13開始,對(duì)于存儲(chǔ)程序放寬了該限制,但該限制仍適用于存儲(chǔ)函數(shù)和觸發(fā)程序。
·???????? OPTIMIZE TABLE
對(duì)于存儲(chǔ)函數(shù)(而不是存儲(chǔ)程序),禁止下述額外語句:
·???????? 執(zhí)行顯式或隱式提交或回滾操作的語句。
·???????? 返回結(jié)果集的語句。包括沒有INFO子句的SELECT語句,以及SHOW語句。能夠用SELECT … INTO,或使用光標(biāo)和FETCH語句處理結(jié)果集的函數(shù)。
·???????? FLUSH語句。注意,盡管能夠在存儲(chǔ)程序中使用FLUSH,但不能從存儲(chǔ)函數(shù)或觸發(fā)程序調(diào)用這類存儲(chǔ)程序。
注意,盡管某些限制在正常情況下適用于存儲(chǔ)函數(shù)和觸發(fā)程序,不適用于存儲(chǔ)程序,如果它們是從存儲(chǔ)函數(shù)或觸發(fā)程序中調(diào)用的,這些限制也適用于存儲(chǔ)程序。
使用存儲(chǔ)子程序會(huì)導(dǎo)致復(fù)制問題。關(guān)于這方面的進(jìn)一步討論,請(qǐng)參見20.4節(jié),“存儲(chǔ)子程序和觸發(fā)程序的二進(jìn)制日志功能”。
INFORMATION_SCHEMA尚不包含PARAMETERS表,因此,對(duì)于需要在運(yùn)行時(shí)獲取子程序參數(shù)信息的應(yīng)用程序來說,必須采用相應(yīng)的規(guī)避錯(cuò)誤,如解析SHOW CREATE語句的輸出。
沒有存儲(chǔ)子程序調(diào)試工具。
存儲(chǔ)子程序使用了具體化的光標(biāo),而不是固有光標(biāo)(在服務(wù)器端生成結(jié)果集并對(duì)結(jié)果集進(jìn)行高速緩沖處理,然后在客戶端獲取結(jié)果集時(shí)按行返回)。
不能提前處理CALL語句。無論是對(duì)服務(wù)器端預(yù)處理語句還是SQL預(yù)處理語句,均成立。
為了防止服務(wù)器線程間的交互問題,當(dāng)客戶端發(fā)出語句時(shí),服務(wù)器將使用可用的、用于語句執(zhí)行的子程序和觸發(fā)程序快照。也就是說,服務(wù)器將計(jì)算出可在語句執(zhí)行期間使用的存儲(chǔ)程序、函數(shù)和觸發(fā)程序的列表,加載它們,然后進(jìn)入語句執(zhí)行。這意味著,在語句執(zhí)行的同時(shí),它不會(huì)看到其他線程對(duì)子程序所作的變更。
從MySQL 5.0.2開始,通過mysql_stmt_attr_set() C API函數(shù)實(shí)現(xiàn)了服務(wù)器端光標(biāo)。服務(wù)器端光標(biāo)允許在服務(wù)器端生成結(jié)果集,但不會(huì)將其傳輸?shù)娇蛻舳耍强蛻舳苏?qǐng)求這些行。例如,如果客戶端執(zhí)行了查詢,但僅對(duì)第1行感興趣,那么不會(huì)傳輸剩余的行。
光標(biāo)是只讀的,不能使用光標(biāo)來更新行。
未實(shí)施UPDATE WHERE CURRENT OF和DELETE WHERE CURRENT OF,這是因?yàn)椴恢С挚筛碌墓鈽?biāo)。
光標(biāo)是不可保持的(提交后不再保持打開)。
光標(biāo)是不敏感的。
光標(biāo)是不可滾動(dòng)的。
光標(biāo)是未命名的。語句處理程序起著光標(biāo)ID的作用。
對(duì)于每條預(yù)處理語句,僅能打開1個(gè)光標(biāo)。如果需要多個(gè)光標(biāo),必須處理多條語句。
如果在預(yù)處理模式下不支持語句,不能在生成結(jié)果集的語句上使用光標(biāo)。包括CHECK TABLES、HANDLER READ和SHOW BINLOG EVENTS語句。
隨后將更正的一致缺陷:如果將NULL值與使用ALL、ANY或SOME的子查詢進(jìn)行比較,而且子查詢返回空結(jié)果,比較操作將對(duì)NULL的非標(biāo)準(zhǔn)結(jié)果進(jìn)行評(píng)估,而不是TRUE或FALSE。
子查詢的外部語句可以是SELECT、INSERT、UPDATE、DELETE、SET或DO中的任何一個(gè)。
僅部分支持行比較操作:
·???????? 對(duì)于expr IN (subquery),expr可以是n-tuple(通過行構(gòu)造程序語法指定),而且子查詢能返回n-tuples個(gè)行。
·???????? 對(duì)于expr op {ALL|ANY|SOME} (subquery),expr必須是標(biāo)度值,子查詢必須是列子查詢,不能返回多列行。
換句話講,對(duì)于返回n-tuples行的子查詢,支持:
(val_1, ..., val_n) IN (subquery)
但不支持:
(val_1, ..., val_n) op {ALL|ANY|SOME} (subquery)
支持針對(duì)IN的行比較,但不支持針對(duì)其他的行比較,原因在于,IN實(shí)施是通過將其重新編寫為“=”比較和AND操作的序列完成的。該方法不能用于ALL、ANY或SOME。
未良好優(yōu)化行構(gòu)造程序。下面的兩個(gè)表達(dá)式是等效的,但只有第2個(gè)表達(dá)式能被優(yōu)化:
(col1, col2, ...) = (val1, val2, ...)
col1 = val1 AND col2 = val2 AND ...
對(duì)于IN的子查詢優(yōu)化不如對(duì)“=”的優(yōu)化那樣有效。
對(duì)于不良IN性能的一種典型情況是,當(dāng)子查詢返回少量行,但外部查詢返回將與子查詢結(jié)果相比較的大量行。
FROM子句中的子查詢不能與子查詢有關(guān)系。在評(píng)估外部查詢之前,將對(duì)它們進(jìn)行具體化處理(執(zhí)行以生成結(jié)果集),因此,不能按照外部查詢的行對(duì)它們進(jìn)行評(píng)估。
一般而言,不能更改表,并從子查詢內(nèi)的相同表進(jìn)行選擇。例如,該限制適用于具有下述形式的語句:
DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);
例外:如果為FROM子句中更改的表使用子查詢,前述禁令將不再適用。例如:
UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);
禁令在此不適用,這是因?yàn)?span>FROM中的子查詢已被具體化為臨時(shí)表,因此“t”中的相關(guān)行已在滿足“t”條件的情況下、在更新時(shí)被選中。
與子查詢相比,針對(duì)聯(lián)合的優(yōu)化程序更成熟,因此,在很多情況下,如果將其改寫為join(聯(lián)合),使用子查詢的語句能夠更有效地執(zhí)行。
但下述情形例外:IN子查詢可被改寫為SELECT DISTINCT聯(lián)合。例如:
SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE condition);
可將該語句改寫為:
SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND condition;
但在該情況下,聯(lián)合需要額外的DISTINCT操作,而且與子查詢相比,效率并不高。
可能的未來優(yōu)化:MySQL不改寫針對(duì)子查詢?cè)u(píng)估的聯(lián)合順序。在某些情況下,如果MySQL將其改寫為聯(lián)合,能夠更有效地執(zhí)行子查詢。這樣,優(yōu)化程序就能在更多的執(zhí)行方案間進(jìn)行選擇。例如,它能決定是否首先讀取某一表或其他。
例如:
SELECT a FROM outer_table AS ot
WHERE a IN (SELECT a FROM inner_table AS it WHERE ot.b = it.b);
對(duì)于該查詢,MySQL總會(huì)首先掃描outer_table,如然后針對(duì)每一行在inner_table上執(zhí)行子查詢。如果outer_table有很多行而inner_table只有少量行,查詢的執(zhí)行速度或許要慢于本應(yīng)有的速度。
前述查詢可改寫為:
SELECT a FROM outer_table AS ot, inner_table AS it
WHERE ot.a = it.a AND ot.b = it.b;
在該情況下,我們能掃描小的表(inner_table)并查詢outer_table中的行,如果在“ot.a,ot.b”上有索引,速度會(huì)更快。
可能的未來優(yōu)化:對(duì)外部查詢的每一行評(píng)估關(guān)聯(lián)的子查詢。更好的方法是,如果外部行的值與之前的行相比沒有變化,不對(duì)子查詢進(jìn)行再次評(píng)估,而是使用以前的結(jié)果。
可能的未來優(yōu)化:通過將結(jié)果具體化到臨時(shí)表,而且該表不使用索引,對(duì)FROM子句中的子查詢進(jìn)行評(píng)估。在查詢中與其他表進(jìn)行比較時(shí),盡管可能是有用的,但不允許使用索引。
可能的未來優(yōu)化:如果FROM子句中的子查詢類似于可施加MERGE算法的視圖,改寫查詢并采用MERGE算法,以便能夠使用索引。下述語句包含這類子查詢:
SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;
該語句可被改寫為聯(lián)合,如下所示:
SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;
這類改寫具有兩個(gè)優(yōu)點(diǎn):
1.??? 避免使用那些不能使用索引的臨時(shí)表。在改寫的查詢中,優(yōu)化程序可在t1上使用索引。
2.??? 優(yōu)化程序在選擇不同的執(zhí)行計(jì)劃方面具有更大的自由。例如,將查詢改寫為聯(lián)合,那么就允許優(yōu)化程序首先使用t1或t2。
可能的未來優(yōu)化:對(duì)于沒有關(guān)聯(lián)子查詢的IN、= ANY、<> ANY、= ALL、以及<> ALL,為結(jié)果使用“內(nèi)存中”哈希處理,或?qū)^大的結(jié)果使用具有索引的臨時(shí)表。例如:
SELECT a FROM big_table AS bt
WHERE non_key_field IN (SELECT non_key_field FROM table WHERE condition)
在該情況下,可創(chuàng)建臨時(shí)表:
CREATE TABLE t (key (non_key_field))
(SELECT non_key_field FROM table WHERE condition)
然后,對(duì)big_table中的每一行,根據(jù)bt.non_key_field,在“t”中進(jìn)行鍵查找。
視圖處理功能概念未優(yōu)化:
·???????? 不能在視圖上創(chuàng)建索引。
·???????? 對(duì)于使用MERGE算法處理的視圖,可以使用索引。但是,對(duì)于使用臨時(shí)表算法處理的視圖,不能在其基表上利用索引提供的優(yōu)點(diǎn)(盡管能夠在臨時(shí)表的生成過程中使用索引)。
在視圖的FROM子句中不能使用子查詢。未來該限制將被放寬。
存在一個(gè)一般原則,不能更改某一表并在子查詢的相同表內(nèi)進(jìn)行選擇。請(qǐng)參見I.3節(jié),“對(duì)子查詢的限制”。
如果從表選擇了視圖并接著從視圖進(jìn)行了選擇,同樣的原理也適用,如果在子查詢中從表選擇了視圖并使用MERGE算法評(píng)估了視圖,也同樣。例如:
CREATE VIEW v1 AS
SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE t1.a = t2.a);
?
UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;
如果視圖是使用臨時(shí)表評(píng)估的,可從視圖子查詢中的表進(jìn)行選擇,并仍能更改外部查詢中的表。在該情況下,視圖將被具體化,因此,你實(shí)際上不能從子查詢的表中進(jìn)行選擇并“同時(shí)”更改它(這是你打算強(qiáng)制MySQL使用臨時(shí)表算法的另一原因,其方法是在視圖定義中指定ALGORITHM = TEMPTABLE關(guān)鍵字)。
可以使用DROP TABLE或ALTER TABLE來舍棄或更改視圖定義中使用的表(它會(huì)是視圖失效),而且舍棄或更改操作不會(huì)導(dǎo)致告警。但在以后使用視圖時(shí)會(huì)出錯(cuò)。
視圖定義是通過特定語句“凍結(jié)”的:
·???????? 如果PREPARE預(yù)處理的語句引用了視圖,以后每次執(zhí)行語句時(shí)看到的視圖內(nèi)容與預(yù)處理視圖時(shí)的內(nèi)容相同。即使在語句預(yù)處理完成之后、在執(zhí)行語句之前更改了視圖定義,情況也同樣。例如:
·??????????????? CREATE VIEW v AS SELECT 1;
·??????????????? PREPARE s FROM 'SELECT * FROM v';
·??????????????? ALTER VIEW v AS SELECT 2;
·??????????????? EXECUTE s;
EXECUTE語句返回的結(jié)果是1,而不是2。
·???????? 如果存儲(chǔ)子程序中的語句引用了視圖,語句所見到的視圖內(nèi)容與首次執(zhí)行語句時(shí)的相同。這意味著,如果語句是以循環(huán)方式執(zhí)行的,進(jìn)一步的語句迭代見到的視圖內(nèi)容是相同的,即使在循環(huán)過程中更改了視圖定義也同樣。例如:
·??????????????? CREATE VIEW v AS SELECT 1;
·??????????????? delimiter //
·??????????????? CREATE PROCEDURE p ()
·??????????????? BEGIN
·??????????????? ??DECLARE i INT DEFAULT 0;
·??????????????? ??WHILE i < 5 DO
·??????????????? ????SELECT * FROM v;
·??????????????? ????SET i = i + 1;
·??????????????? ????ALTER VIEW v AS SELECT 2;
·??????????????? ??END WHILE;
·??????????????? END;
·??????????????? //
·??????????????? delimiter ;
·??????????????? CALL p();
如果調(diào)用了程序p(),每次通過循環(huán)時(shí)SELECT返回1,即使在循環(huán)內(nèi)更改了視圖定義也同樣。
關(guān)于視圖的可更新性,對(duì)于視圖,其總體目標(biāo)是,如果任何視圖從理論上講是可更新的,在實(shí)際上也應(yīng)是可更新的。這包括在其定義中有UNION的視圖。目前,并非所有理論上可更新的視圖均能被更新。最初的視圖實(shí)施有意采用該方式,為的是盡快地在MySQL中獲得有用的可更新視圖。很多理論上可更新的視圖現(xiàn)已能更新,但限制依然存在:
·???????? 其子查詢位于WHERE子句之外任何位置的可更新視圖。對(duì)于某些其子查詢位于SELECT列表中的視圖,也是可更新的。
·???????? 不能使用UPDATE來更新定義為Join的視圖的1個(gè)以上的基表。
·???????? 不能使用DELETE來更新定義為Join的視圖。
XA事務(wù)支持限于InnoDB存儲(chǔ)引擎。
MySQL XA實(shí)施是針對(duì)外部XA的,其中,MySQL服務(wù)器作為資源管理器,而客戶端程序作為事務(wù)管理器。未實(shí)施“內(nèi)部XA”。這樣,就允許MySQL服務(wù)器內(nèi)的單獨(dú)存儲(chǔ)引擎作為RM(資源管理器),而服務(wù)器本身作為TM(事務(wù)管理器)。處理包含1個(gè)以上存儲(chǔ)引擎的XA事務(wù)時(shí),需要內(nèi)部XA。內(nèi)部XA的實(shí)施是不完整的,這是因?yàn)椋蟠鎯?chǔ)引擎在表處理程序?qū)用嫔现С謨呻A段提交,目前僅對(duì)InnoDB實(shí)現(xiàn)了該特性。
對(duì)于XA START,不支持JOIN和RESUME子句。
對(duì)于XA END,不支持SUSPEND [FOR MIGRATE]子句。
在全局事務(wù)內(nèi),對(duì)于每個(gè)XA事務(wù),xid值的bqual部分應(yīng)是不同的,該要求是對(duì)當(dāng)前MySQL XA實(shí)施的限制。它不是XA規(guī)范的組成部分。
如果XA事務(wù)達(dá)到PREPARED狀態(tài)而且MySQL服務(wù)器宕機(jī),當(dāng)服務(wù)器重啟后,能夠繼續(xù)處理事務(wù)。就像原本應(yīng)當(dāng)?shù)哪菢?。但是,如果客戶端連接中止而服務(wù)器繼續(xù)運(yùn)行,服務(wù)器將回滾任何未完成的XA事務(wù),即使該事務(wù)已達(dá)到PREPARED狀態(tài)也同樣。它應(yīng)能提交或回滾PREPARED XA事務(wù),但在不更改二進(jìn)制日志機(jī)制的情況下不能這樣。
這是MySQL參考手冊(cè)的翻譯版本,關(guān)于MySQL參考手冊(cè),請(qǐng)?jiān)L問dev.mysql.com。原始參考手冊(cè)為英文版,與英文版參考手冊(cè)相比,本翻譯版可能不是最新的。