《MySQL技術(shù)內(nèi)幕:SQL編程?》書摘

MySQL技術(shù)內(nèi)幕:SQL編程

姜承堯

第1章 SQL編程

>> B是由MySQL創(chuàng)始人之一Monty分支的一個(gè)版本巩踏。在MySQL數(shù)據(jù)庫(kù)被Oracle公司收購(gòu)后构蹬,Monty擔(dān)心MySQL數(shù)據(jù)庫(kù)發(fā)展的未來(lái)粹排,從而分支出一個(gè)版本增炭。這個(gè)版本和其他分支有很大的不同睦刃,其默認(rèn)使用嶄新的Maria存儲(chǔ)引擎,是原MyISAM存儲(chǔ)引擎的升級(jí)版本

>> 在這里禾嫉,我把SQL編程分為三個(gè)階段,當(dāng)然不是每個(gè)人都必須同意筆者的觀點(diǎn)蚊丐。

第一階段是面向過(guò)程化的SQL編程階段熙参。

>> 在這一階段,經(jīng)常會(huì)有濫用各種工具(如游標(biāo)麦备、臨時(shí)表孽椰、動(dòng)態(tài)SQL語(yǔ)句等)的情況,而程序員自己通常意識(shí)不到他們正在引起破壞凛篙。

>> 第二階段是面向集合的SQL編程階段黍匾。

>> 從這一階段開(kāi)始,程序員開(kāi)始相信那些說(shuō)游標(biāo)呛梆、臨時(shí)表锡搜、動(dòng)態(tài)SQL有害而永遠(yuǎn)不應(yīng)該使用的“專家”楚殿。

>> 第三階段是融合的SQL編程階段

>> 在這一階段扼脐,SQL程序員不再迷戀所謂的專家幌缝,他們可能意識(shí)到即使是游標(biāo),也并不是在所有情況下都是無(wú)用和有害的融痛。

>> 對(duì)于表中數(shù)據(jù)的存儲(chǔ)壶笼,InnoDB存儲(chǔ)引擎采用了聚集(clustered)的方式,每張表都是按主鍵的順序進(jìn)行存儲(chǔ)的雁刷,如果沒(méi)有顯式地在表定義時(shí)指定主鍵覆劈,InnoDB存儲(chǔ)引擎會(huì)為每一行生成一個(gè)6字節(jié)的ROWID,并以此作為主鍵沛励。

第2章 數(shù)據(jù)類型

>> 如果在數(shù)據(jù)

>> UNSIGNED屬性就是將數(shù)字類型無(wú)符號(hào)化责语,與C、C++這些程序語(yǔ)言中的unsigned含義相同目派。

>> 看起來(lái)這是一個(gè)不錯(cuò)的屬性選項(xiàng)坤候,特別是對(duì)于主鍵是自增長(zhǎng)的類型,因?yàn)橐话銇?lái)說(shuō)企蹭,用戶都希望主鍵是非負(fù)數(shù)白筹。然而在實(shí)際使用中,UNSIGNED可能會(huì)帶來(lái)一些負(fù)面的影響谅摄,示例如下:

>> 和其他數(shù)據(jù)庫(kù)一樣徒河,MySQL的確存在一些Bug,其實(shí)并不是MySQL數(shù)據(jù)庫(kù)的Bug比較多送漠,去看一下Oracle RAC的Bug顽照,那可能就更多了,它可是Oracle的一款旗艦產(chǎn)品闽寡。

>> 筆者個(gè)人的看法是盡量不要使用UNSIGNED代兵,因?yàn)榭赡軙?huì)帶來(lái)一些意想不到的效果尼酿。另外,對(duì)于INT類型可能存放不了的數(shù)據(jù)植影,INT UNSIGNED同樣可能存放不了裳擎,與其如此,還不如在數(shù)據(jù)庫(kù)設(shè)計(jì)

>> 階段將INT類型提升為BIGINT類型何乎。

>> 可以看到int(10)句惯,這代表什么意思呢土辩?整型不就是4字節(jié)的嗎支救?這10又代表什么呢?其實(shí)如果沒(méi)有ZEROFILL這個(gè)屬性拷淘,括號(hào)內(nèi)的數(shù)字是毫無(wú)意義的

>> 就是ZEROFILL屬性的作用各墨,如果寬度小于設(shè)定的寬度(這里的寬度為4),則自動(dòng)填充0启涯。要注意的是贬堵,這只是最后顯示的結(jié)果,在MySQL中實(shí)際存儲(chǔ)的還是1结洼。

>> SQL_MODE可以設(shè)置的選項(xiàng)黎做。

STRICT_TRANS_TABLES:

>> ALLOW_INVALID_DATES:該選項(xiàng)并不完全對(duì)日期的合法性進(jìn)行檢查,只檢查月份是否在1~12之間松忍,日期是否在1~31之間

>> ANSI_QUOTES:?jiǎn)⒂肁NSI_QUOTES后蒸殿,不能用雙引號(hào)來(lái)引用字符串,因?yàn)樗鼘⒈唤忉尀樽R(shí)別符鸣峭,

>> 然而從MySQL 5.6.4版本開(kāi)始宏所,MySQL增加了對(duì)秒的小數(shù)部分(fractional second)的支持,具體語(yǔ)法為:

>> 其中摊溶,type_name的類型可以是TIME爬骤、DATETIME和TIMESTAMP。fsp表示支持秒的小數(shù)部分的精度莫换,最大為6霞玄,表示微秒(microseconds);默認(rèn)為0拉岁,表示沒(méi)有小數(shù)部分坷剧,同時(shí)也是為了兼容之前版本中的TIME、DATETIME和TIMESTAMP類型膛薛。對(duì)于時(shí)間函數(shù)听隐,如CURTIME()、SYSDATE()和UTC_TIMESTAMP()也增加了對(duì)fsp的支持哄啄,例如:

>> TIMESTAMP占用4字節(jié)雅任,顯示的范圍為“1970-01-0100:00:00”UTC到“2038-01-19 03:14:07”UTC风范。其實(shí)際存儲(chǔ)的內(nèi)容為“1970-01-0100:00:00”到當(dāng)前時(shí)間的毫秒數(shù)。

>> UTC協(xié)調(diào)世界時(shí)沪么,又稱世界統(tǒng)一時(shí)間硼婿、世界標(biāo)準(zhǔn)時(shí)間和國(guó)際協(xié)調(diào)時(shí)間。它從英文Coordinated Universal Time和法文Temps Universel Cordonné而來(lái)禽车。

>> CURRENT_TIMESTAMP是NOW的同義詞寇漫,也就是說(shuō)兩者是相同的。

SYSDATE函數(shù)返回的是執(zhí)行到當(dāng)前函數(shù)時(shí)的時(shí)間殉摔,而NOW返回的是執(zhí)行SQL語(yǔ)句時(shí)的時(shí)間州胳。

>> 一般來(lái)說(shuō)表中都會(huì)有一個(gè)對(duì)日期類型的索引,如果使用上述的語(yǔ)句逸月,優(yōu)化器絕對(duì)不會(huì)使用索引栓撞,也不可能通過(guò)索引來(lái)查詢數(shù)據(jù),因此上述查詢的執(zhí)行效率可能非常低碗硬。

>> 演示前瓤湘,需要確認(rèn)已經(jīng)安裝了MySQL官方的示例數(shù)據(jù)庫(kù)employees

>> 一旦啟用ZEROFILL屬性,MySQL數(shù)據(jù)庫(kù)為列自動(dòng)添加UNSIGNED屬性恩尾,

>> MySQL數(shù)據(jù)庫(kù)支持兩種浮點(diǎn)類型:?jiǎn)尉鹊腇LOAT類型及雙精度的DOUBLE PRECISION類型弛说。這兩種類型都是非精確的類型,經(jīng)過(guò)一些操作后并不能保證運(yùn)算的正確性翰意,例如M*G/G不一定等于M木人,雖然數(shù)據(jù)庫(kù)內(nèi)部算法已經(jīng)使其盡可能的正確,但是結(jié)果還會(huì)有偏差

>> 為了保證最大的可移植性猎物,需要使用近似數(shù)值數(shù)據(jù)值存儲(chǔ)的代碼虎囚,使用FLOAT或DOUBLE PRECISION,并不規(guī)定精度或位數(shù)

>> DECIMAL和NUMERIC類型在MySQL中被視為相同的類型蔫磨,用于保存必須為確切精度的值淘讥。

>> DECIMAL或NUMERIC的最大位數(shù)是65,但具體的DECIMAL或NUMERIC列的實(shí)際范圍受具體列的精度或標(biāo)度約束堤如。如果分配給此類列的值的小數(shù)點(diǎn)后位數(shù)超過(guò)指定的標(biāo)度允許的范圍蒲列,值將按該標(biāo)度進(jìn)行轉(zhuǎn)換。(具體操作與操作系統(tǒng)有關(guān)搀罢,一般結(jié)果均被截取到允許的位數(shù))蝗岖。

>> 位類型,即BIT數(shù)據(jù)類型可用來(lái)保存位字段的值榔至。BIT(M)類型表示允許存儲(chǔ)M位數(shù)值抵赢,M范圍為1到64,占用的空間為(M+7)/8字節(jié)。

>> 因?yàn)椴捎梦坏拇鎯?chǔ)方式铅鲤,所以不能直接查看

>> 數(shù)字輔助表是一個(gè)只包含從1到N的N個(gè)整數(shù)的簡(jiǎn)單表划提,N通常很大。因?yàn)閿?shù)字輔助表是一個(gè)非常強(qiáng)大的工具邢享,可能經(jīng)常需要在解決方案中用到它鹏往,筆者建議創(chuàng)建一個(gè)持久的數(shù)字輔助表,并根據(jù)需要填充一定數(shù)據(jù)量的值骇塘。

>> 實(shí)際上如何填充數(shù)字輔助表無(wú)關(guān)緊要伊履,因?yàn)橹恍枰\(yùn)行這個(gè)過(guò)程一次。不過(guò)還可以對(duì)填充語(yǔ)句進(jìn)行優(yōu)化款违。

>> utf8目前被視為utf8mb3唐瀑,即最大占用3個(gè)字節(jié)空間,而utf8mb4可以視做utf8mb3的擴(kuò)展奠货。

>> 對(duì)BMP(Basic Multilingual Plane)字符的存儲(chǔ)介褥,utf8mb3和utf8mb4

>> 兩者是完全一樣的,區(qū)別只是utf8mb4對(duì)擴(kuò)展字符的支持递惋。

>> 對(duì)于Unicode編碼的字符集,強(qiáng)烈建議將所有的CHAR字段設(shè)置為VARCHAR字段溢陪,因?yàn)閷?duì)于CHAR字段萍虽,數(shù)據(jù)庫(kù)會(huì)保存最大可能的字節(jié)數(shù)。例如形真,對(duì)于CHAR(30)杉编,數(shù)據(jù)庫(kù)可能存儲(chǔ)90字節(jié)的數(shù)據(jù)。

>> 要查看當(dāng)前使用的字符集咆霜,可以使用STATUS命令:

>> MySQL數(shù)據(jù)庫(kù)一個(gè)比較“強(qiáng)悍”的地方是邓馒,可以細(xì)化每個(gè)對(duì)象字符集的設(shè)置

>> 排序規(guī)則(Collation)是指對(duì)指定字符集下不同字符的比較規(guī)則。

>> 兩個(gè)不同的字符集不能有相同的排序規(guī)則蛾坯。

每個(gè)字符集有一個(gè)默認(rèn)的排序規(guī)則光酣。

有一些常用的命名規(guī)則。如_ci結(jié)尾表示大小寫不敏感(case insensitive)脉课,_cs表示大小寫敏感(case sensitive)救军,_bin表示二進(jìn)制的比較(binary)。

>> 另外倘零,排序規(guī)則不僅影響大小寫的比較問(wèn)題唱遭,也影響著索引

>> 可以看到,不能在a列上創(chuàng)建一個(gè)唯一索引呈驶,報(bào)錯(cuò)中提示有重復(fù)數(shù)據(jù)拷泽。索引是B+樹(shù),同樣需要對(duì)字符進(jìn)行比較,因此在建立唯一索引時(shí)由于排序規(guī)則對(duì)大小寫不敏感而導(dǎo)致了錯(cuò)誤司致。

>> CHAR(N)和VARCHAR(N)中的N都代表字符長(zhǎng)度订晌,而非字節(jié)長(zhǎng)度。

>> 對(duì)于CHAR類型的字符串蚌吸,MySQL數(shù)據(jù)庫(kù)會(huì)自動(dòng)對(duì)存儲(chǔ)列的右邊進(jìn)行填充(Right Padded)操作锈拨,直到字符串達(dá)到指定的長(zhǎng)度N。而在讀取該列時(shí)羹唠,MySQL數(shù)據(jù)庫(kù)會(huì)自動(dòng)將填充的字符刪除

>> LENGTH函數(shù)返回的是字節(jié)長(zhǎng)度奕枢,而不是字符長(zhǎng)度。

>> VARCHAR類型存儲(chǔ)變長(zhǎng)字段的字符類型佩微,與CHAR類型不同的是缝彬,其存儲(chǔ)時(shí)需要在前綴長(zhǎng)度列表加上實(shí)際存儲(chǔ)的字符,該字符占用1~2字節(jié)的空間哺眯。當(dāng)存儲(chǔ)的字符串長(zhǎng)度小于255字節(jié)時(shí)谷浅,其需要1字節(jié)的空間,當(dāng)大于255字節(jié)時(shí)奶卓,需要2字節(jié)的空間一疯。所以,對(duì)于單字節(jié)的latin1來(lái)說(shuō)夺姑,CHAR(10)和VARCHAR(10)最大占用的存儲(chǔ)空間是不同的墩邀, CHAR(10)占用10個(gè)字節(jié)這是毫無(wú)疑問(wèn)的,

>> 而VARCHAR(10)的最大占用空間數(shù)是11字節(jié)盏浙,因?yàn)槠湫枰?字節(jié)來(lái)存放字符長(zhǎng)度眉睹。

>> BINARY和VARBINARY與前面介紹的CHAR和VARCHAR類型有點(diǎn)類似,不同的是BINARY和VARBINARY存儲(chǔ)的是二進(jìn)制的字符串废膘,而非字符型字符串竹海。也就是說(shuō),BINARY和VARBINARY沒(méi)有字符集的概念丐黄,對(duì)其排序和比較都是按照二進(jìn)制值進(jìn)行對(duì)比斋配。

>> BINARY和VARBINARY對(duì)比CHAR和VARCHAR,第一個(gè)不同之處就是BINARY (N)和VARBINARY(N)中的N值代表的是字節(jié)數(shù)孵稽,而非

>> 字符長(zhǎng)度许起;第二個(gè)不同點(diǎn)是, CHAR和VARCHAR在進(jìn)行字符比較時(shí)菩鲜,比較的只是字符本身存儲(chǔ)的字符园细,忽略字符后的填充字符,而對(duì)于BINARY和VARBINARY來(lái)說(shuō)接校,由于是按照二進(jìn)制值來(lái)進(jìn)行比較的猛频,因此結(jié)果會(huì)非常不同

>> 第三個(gè)不同的是狮崩,對(duì)于BINARY字符串,其填充字符是0x00鹿寻,而CHAR的填充字符為0x20睦柴。可能是因?yàn)锽INARY的比較需要毡熏,0x00顯然是比較的最小字符

>> 而坦敌,BLOB和TEXT在以下幾個(gè)方面又不同于VARBINARY和VARCHAR:[插圖]在BLOB和TEXT類型的列上創(chuàng)建索引時(shí),必須制定索引前綴的長(zhǎng)度痢法。而VARCHAR和VARBINARY的前綴長(zhǎng)度是可選的狱窘。

>> [插圖]BLOB和TEXT類型的列不能有默認(rèn)值。[插圖]在排序時(shí)只使用列的前max_sort_length個(gè)字節(jié)财搁。

>> max_sort_length默認(rèn)值為1024蘸炸,該參數(shù)是動(dòng)態(tài)參數(shù),任何客戶端都可以在MySQL數(shù)據(jù)庫(kù)運(yùn)行時(shí)更改該參數(shù)的值

>> 在數(shù)據(jù)庫(kù)中尖奔,最小的存儲(chǔ)單元是頁(yè)(也可以稱為塊)搭儒。為了有效存儲(chǔ)列類型為BLOB或TEXT的大數(shù)據(jù)類型,一般將列的值存放在行溢出頁(yè)提茁,而數(shù)據(jù)頁(yè)存儲(chǔ)的行數(shù)據(jù)只包含BLOB或TEXT類型數(shù)據(jù)列前一部分?jǐn)?shù)據(jù)淹禾。

>> 在有些存儲(chǔ)引擎內(nèi)部,比如InnoDB存儲(chǔ)引擎甘凭,會(huì)將大VARCHAR類型字符串(如VARCHAR(65530))自動(dòng)轉(zhuǎn)化為TEXT或BLOB類型

>> ENUM和SET類型都是集合類型稀拐,不同的是ENUM類型最多可枚舉65536個(gè)元素,而SET類型最多枚舉64個(gè)元素丹弱。

第3章 查詢處理

>> 在大多數(shù)編程語(yǔ)言中,代碼按編碼順序被處理铲咨。但在SQL語(yǔ)言中躲胳,第一個(gè)被處理的子句總是FROM子句

>> 每個(gè)操作都會(huì)產(chǎn)生一張?zhí)摂M表,該虛擬表作為一個(gè)處理的輸入纤勒。

>> 這些虛擬表對(duì)用戶是透明的坯苹,只有最后一步生成的虛擬表才會(huì)返回給用戶。如果沒(méi)有在查詢中指定某一子句摇天,則將跳過(guò)相應(yīng)的步驟粹湃。

>> 對(duì)虛擬表VT1應(yīng)用ON篩選,只有那些符合的行才被插入虛擬表VT2中泉坐。

>> JOIN:如果指定了OUTER JOIN(如LEFT OUTER JOIN为鳄、RIGHT OUTER JOIN),那么保留表中未匹配的行作為外部行添加到虛擬表VT2中腕让,產(chǎn)生虛擬表VT3孤钦。

>> 如果FROM子句包含兩個(gè)以上表,則對(duì)上一個(gè)連接生成的結(jié)果表VT3和下一個(gè)表重復(fù)執(zhí)行步驟1)~步驟3),直到處理完所有的表為止偏形。

>> 第一步需要做的是對(duì)FROM子句前后的兩張表進(jìn)行笛卡兒積操作静袖,也稱做交叉連接(Cross Join),生成虛擬表VT1俊扭。如果FROM子句前的表中包含a行數(shù)據(jù)队橙,F(xiàn)ROM子句后的表中包含b行數(shù)據(jù),那么虛擬表VT1中將包含a*b行數(shù)據(jù)

>> SELECT查詢一共有3個(gè)過(guò)濾過(guò)程萨惑,分別是ON捐康、WHERE、HAVING咒钟。ON是最先執(zhí)行的過(guò)濾過(guò)程吹由。

>> 對(duì)于大多數(shù)的編程語(yǔ)言而言,邏輯表達(dá)式的值只有兩種:TRUE和FALSE朱嘴。但是在關(guān)系數(shù)據(jù)庫(kù)中起邏輯表達(dá)式作用的并非只有兩種倾鲫,還有一種稱為三值邏輯的表達(dá)式。這是因?yàn)樵跀?shù)據(jù)庫(kù)中對(duì)NULL值的比較與大多數(shù)編程語(yǔ)言不同

>> 對(duì)于在ON過(guò)濾條件下的NULL值比較萍嬉,此時(shí)的比較結(jié)果為UNKNOWN乌昔,卻被視為FALSE來(lái)進(jìn)行處理,即兩個(gè)NULL并不相同壤追。但是在下面兩種情況下認(rèn)為兩個(gè)NULL值的比較是相等的:

GROUP BY子句把所有NULL值分到同一組磕道。

ORDER BY子句中把所有NULL值排列在一起

>> 因此在產(chǎn)生虛擬表VT2時(shí),會(huì)增加一個(gè)額外的列來(lái)表示ON過(guò)濾條件的返回值行冰,返回值有TRUE溺蕉、FALSE、UNKNOWN悼做,如表3-5所示疯特。

>> 取出比較值為TRUE的記錄,產(chǎn)生虛擬表VT2肛走,結(jié)果如表3-6所示漓雅。

>> 添加外部行的工作就是在VT2表的基礎(chǔ)上添加保留表中被過(guò)濾條件過(guò)濾掉的數(shù)據(jù),非保留表中的數(shù)據(jù)被賦予NULL值朽色,最后生成虛擬表VT3

>> 在當(dāng)前應(yīng)用WHERE過(guò)濾器時(shí)邻吞,有兩種過(guò)濾是不被允許的:

由于數(shù)據(jù)還沒(méi)有分組,因此現(xiàn)在還不能在WHERE過(guò)濾器中使用where_condition=MIN(col)這類對(duì)統(tǒng)計(jì)的過(guò)濾葫男。

由于沒(méi)有進(jìn)行列的選取操作抱冷,因此在SELECT中使用列的別名也是不被允許的,如SELECT city as c FROM t WHERE c='ShangHai'是不允許出現(xiàn)的腾誉。

>> 如果在查詢中指定了DISTINCT子句徘层,則會(huì)創(chuàng)建一張內(nèi)存臨時(shí)表(如果內(nèi)存中存放不下就放到磁盤上)峻呕。這張內(nèi)存臨時(shí)表的表結(jié)構(gòu)和上一步產(chǎn)生的虛擬表一樣,不同的是對(duì)進(jìn)行DISTINCT操作的列增加了一個(gè)唯一索引趣效,以此來(lái)去除重復(fù)數(shù)據(jù)瘦癌。

>> 對(duì)于使用了GROUP BY的查詢,再使用DISTINCT是多余的跷敬,因?yàn)橐呀?jīng)進(jìn)行分組讯私,不會(huì)移除任何行。

>> 關(guān)系數(shù)據(jù)庫(kù)是在數(shù)學(xué)的基礎(chǔ)上發(fā)展起來(lái)的西傀,關(guān)系對(duì)應(yīng)于數(shù)學(xué)中集合的概念斤寇。數(shù)據(jù)庫(kù)中常見(jiàn)的查詢操作其實(shí)對(duì)應(yīng)的是集合的某些運(yùn)算:選擇、投影拥褂、連接娘锁、并、交饺鹃、差莫秆、除。最終的結(jié)果雖然是以一張二維表的方式呈現(xiàn)在用戶面前悔详,但是從數(shù)據(jù)庫(kù)內(nèi)部來(lái)看是一系列的集合操作镊屎。因此,對(duì)于表中的記錄茄螃,用戶需要以集合的思想來(lái)理解缝驳。對(duì)于customers和orders表,更準(zhǔn)確的描述應(yīng)如圖3-2所示归苍。

>> 由此可見(jiàn)用狱,即使采用的是InnoDB存儲(chǔ)引擎表,對(duì)于沒(méi)有使用ORDER BY子句的選擇查詢拼弃,其結(jié)果永遠(yuǎn)不會(huì)是按照主鍵順序進(jìn)行排列的齿拂。因?yàn)?br>

>> 沒(méi)有ORDER BY子句的查詢只代表從集合中查詢數(shù)據(jù),而集合是沒(méi)有順序概念的肴敛。

>> 因此要牢記,不要為表中的行假定任何特定的順序吗购。就是說(shuō)医男,在實(shí)際使用環(huán)境中,如果確實(shí)需要有序輸出行記錄捻勉,則必須使用ORDER BY子句

>> 在ORDER BY子句中镀梭,NULL值被認(rèn)為是相同的值,會(huì)將其排序在一起踱启。在MySQL數(shù)據(jù)庫(kù)中报账,NULL值在升序過(guò)程中總是首先被選出研底,即NULL值在ORDER BY子句中被視為最小值。

>> 如果只是選取前5條記錄透罢,則非常輕松和容易榜晦;但是對(duì)100萬(wàn)條記錄,選取從第80萬(wàn)行記錄開(kāi)始的5條記錄羽圃,則還需要掃描記錄到這個(gè)位置

>> 上一節(jié)介紹了邏輯查詢處理乾胶,并且描述了執(zhí)行查詢應(yīng)該得到什么樣的結(jié)果。但是數(shù)據(jù)庫(kù)也許并不會(huì)完全按照邏輯查詢處理的方式來(lái)進(jìn)行查詢朽寞。圖1-1顯示了在MySQL數(shù)據(jù)庫(kù)層有Parser和Optimizer兩個(gè)組件识窿。Parser的工作就是分析SQL語(yǔ)句,而Optimizer的工作就是對(duì)這個(gè)SQL語(yǔ)句進(jìn)行優(yōu)化脑融,選擇一條最優(yōu)的路徑來(lái)選取數(shù)據(jù)喻频,但是必須保證物理查詢處理的最終結(jié)果和邏輯查詢處理是相等的。

第4章 子查詢

>> 子查詢可以按兩種方式進(jìn)行分類肘迎。若按照期望值的數(shù)量甥温,可以將子查詢分為標(biāo)量子查詢和多值子查詢;若按查詢對(duì)外部查詢的依賴可分為獨(dú)立子查詢(self-contained subquery)和相關(guān)子查詢(correlated subquery)

>> MySQL優(yōu)化器對(duì)于IN語(yǔ)句的優(yōu)化是“LAZY”的膜宋。對(duì)于IN子句窿侈,如果不是顯式的列表定義,如IN ('a','b','c')秋茫,那么IN子句都會(huì)被轉(zhuǎn)換為EXISTS的相關(guān)子查詢

>> 如果子查詢和外部查詢分別返回M和N行史简,那么該子查詢被掃描為O(N+M*N)而不是O(M+N)。

>> 用戶通過(guò)EXPLAIN EXTENDED命令可以更為明確地得到優(yōu)化器的執(zhí)行方式

>> 有意思的是肛著,翻閱官方的MySQL手冊(cè)會(huì)發(fā)現(xiàn)圆兵,在子查詢章節(jié)中有相關(guān)子查詢的介紹,卻沒(méi)有獨(dú)立子查詢的介紹枢贿。這是因?yàn)樵诖蠖鄶?shù)情況下殉农,MySQL數(shù)據(jù)庫(kù)都將獨(dú)立子查詢轉(zhuǎn)換為相關(guān)子查詢。

>> 注意到慢的原因是獨(dú)立子查詢被轉(zhuǎn)換成相關(guān)子查詢局荚,而這個(gè)相關(guān)子查詢需要進(jìn)行多次的分組操作超凳。可以采取另一個(gè)方法耀态,再嵌套一層子查詢轮傍,避免多次的分組操作,

>> 相關(guān)子查詢(Dependent Subquery或Correlated Subquery)是指引用了外部查詢列的子查詢首装,即子查詢會(huì)對(duì)外部查詢的每行進(jìn)行一次計(jì)算

>> 创夜。但是在優(yōu)化器內(nèi)部,這是一個(gè)動(dòng)態(tài)的過(guò)程仙逻,隨情況的變化會(huì)有所不同驰吓,通過(guò)不止一種優(yōu)化方式來(lái)處理相關(guān)子查詢涧尿。

>> 這里再次提醒開(kāi)發(fā)人員,對(duì)子查詢的編寫需要非常小心檬贰,盡可能地使用EXPLAIN來(lái)確認(rèn)子查詢的執(zhí)行計(jì)劃姑廉,并確認(rèn)是否可以對(duì)其進(jìn)行進(jìn)一步優(yōu)化。在測(cè)試機(jī)上執(zhí)行一句SQL需要1秒的時(shí)間看似很短偎蘸,但這通常是數(shù)據(jù)量較小的緣故庄蹋;如果在大數(shù)據(jù)量的生產(chǎn)環(huán)境中,這可能會(huì)帶來(lái)災(zāi)難性的后果迷雪。

>> EXIST

>> S是一個(gè)非常強(qiáng)大的謂詞限书,它允許數(shù)據(jù)庫(kù)高效地檢查指定查詢是否產(chǎn)生某些行。通常EXISTS的輸入是一個(gè)子查詢章咧,并關(guān)聯(lián)到外部查詢倦西,但這不是必須的

>> 。根據(jù)子查詢是否返回行赁严,該謂詞返回TRUE或FALSE扰柠。與其他謂詞和邏輯表達(dá)式不同的是,無(wú)論輸入子查詢是否返回行疼约,EXISTS都不會(huì)返回UNKNOWN卤档。如果子查詢的過(guò)濾器為某行返回UNKNOWN,則表示該行不返回程剥,因此劝枣,這個(gè)UNKNOWN被認(rèn)為是FALSE。

>> 盡管通常不建議在SQL語(yǔ)句中使用*织鲸,因?yàn)榭赡軙?huì)引起一些問(wèn)題的產(chǎn)生舔腾,但是在EXIST子查詢中*可以放心地使用。EXISTS只關(guān)心行是否存在搂擦,而不會(huì)去取各列的值稳诚。

>> EXISTS與IN的一個(gè)小區(qū)別體現(xiàn)在對(duì)三值邏輯的判斷上。EXISTS總是返回TRUE或FALSE瀑踢,而對(duì)于IN扳还,除了TRUE、FALSE值外橱夭,還有可能對(duì)NULL值返回UNKNOWN普办。但是在過(guò)濾器中,UNKNOWN的處理方式與FALSE相同徘钥,因此使用IN與使用EXISTS一樣, SQL優(yōu)化器會(huì)選擇相同的執(zhí)行計(jì)劃肢娘。

>> 但是輸入列表中包含NULL值時(shí)呈础,NOT EXISTS和NOT IN之間的差異就表現(xiàn)得非常明顯了舆驶。

>> 對(duì)于包含NULL值的NOT IN來(lái)說(shuō),其總是返回FALSE和UNKNOWN

>> 而钞,而對(duì)于NOT EXISTS沙廉,其總是返回TRUE和FALSE。這就是NOT EXISTS和NOT IN的最大區(qū)別臼节。

>> 派生表又被稱為表子查詢撬陵,與其他表一樣出現(xiàn)在FROM的子句中,但是是從子查詢派生出的虛擬表中產(chǎn)生的

>> 目前派生表在使用上有以下使用規(guī)則:

列的名稱必須是唯一的网缝。

在某些情況下不支持LIMIT巨税。

>> 派生表是完全的虛擬表,并沒(méi)有也不可能被物理地具體化粉臊,因此優(yōu)化器不清楚派生表的信息草添,這對(duì)于涉及查看派生表的EXPLAIN執(zhí)行計(jì)劃來(lái)說(shuō),速度可能非常慢扼仲,

>> 由于目前Oracle和MySQL都將SEMI JOIN轉(zhuǎn)換為了EXISTS語(yǔ)句远寸,因此在執(zhí)行效率上顯得非常低。從理論上來(lái)說(shuō)屠凶,SEMI JOIN應(yīng)該只需要關(guān)心外部表中與子查詢匹配的部分即可

>> 驰后。這就是MariaDB要對(duì)SEMI JOIN進(jìn)行的優(yōu)化,在MariaDB中子查詢變得實(shí)際可用得多矗愧,效率也得到了極大的提升

>> Table Pullout的作用就是根據(jù)唯一索引將子查詢重寫為JOIN語(yǔ)句

>> 預(yù)熱是指所要讀取的表中的數(shù)據(jù)都已經(jīng)在InnoDB存儲(chǔ)引擎的緩沖池中灶芝,這時(shí)不涉及磁盤的讀取。而無(wú)預(yù)熱指的是數(shù)據(jù)庫(kù)剛啟動(dòng)贱枣,緩沖池中沒(méi)有數(shù)據(jù)监署,需要讀取磁盤上的數(shù)據(jù)到緩沖池。

>> Duplicate Weedout優(yōu)化是指外部查詢條件的列是唯一的纽哥, MariaDB優(yōu)化器會(huì)先將子查詢查出的結(jié)果進(jìn)行去重钠乏,這個(gè)步驟被稱為Duplicate Weedout或者Duplicate Elimination。

>> 如果子查詢是獨(dú)立子查詢春塌,則優(yōu)化器可以選擇將獨(dú)立子查詢產(chǎn)生的結(jié)果填充到單獨(dú)一張物化臨時(shí)表(materialized temporary table)中

第5章 聯(lián)接與集合操作

>> 聯(lián)接查詢是一種常見(jiàn)的數(shù)據(jù)庫(kù)操作晓避,即在兩張表(或更多表)中進(jìn)行行匹配的操作。一般稱之為水平操作只壳,這是因?yàn)閷?duì)幾張表進(jìn)行聯(lián)接操作所產(chǎn)生的結(jié)果集可以包含這幾張表中所有的列俏拱。對(duì)應(yīng)于聯(lián)接的水平操作淤年,一般將集合操作視為垂直操作健民。

MySQL數(shù)據(jù)庫(kù)支持如下的聯(lián)接查詢:

CROSS JOIN(交叉聯(lián)接)

INNER JOIN(內(nèi)聯(lián)接)

OUTER JOIN(外聯(lián)接)

其他

>> 在進(jìn)行聯(lián)接操作時(shí),請(qǐng)牢記第3章描述的邏輯查詢處理階段氢卡,尤其是關(guān)于聯(lián)接所涉及的階段。

>> 每個(gè)聯(lián)接都只發(fā)生在兩個(gè)表之間搞隐,即使FROM子句中包含多個(gè)表也是如此

>> 驹愚。每次聯(lián)接操作也只進(jìn)行邏輯操作的前三個(gè)步驟,每次產(chǎn)生一個(gè)虛擬表劣纲,這個(gè)虛擬表再依次與FROM子句的下一個(gè)表進(jìn)行聯(lián)接

>> 需要注意的是逢捺,不同聯(lián)接類型執(zhí)行的步驟不同。對(duì)于CROSS JOIN癞季,只應(yīng)用第一個(gè)階段的笛卡兒積劫瞳。INNER JOIN應(yīng)用第一和第二個(gè)步驟,OUTER JOIN應(yīng)用所有的前三個(gè)步驟绷柒。

>> 對(duì)于表5-1左側(cè)的SQL聯(lián)接查詢語(yǔ)句志于,其由ANSI SQL 89標(biāo)準(zhǔn)引入,與新語(yǔ)法的區(qū)別是FROM子句中的表名之間用逗號(hào)分隔辉巡,沒(méi)有JOIN關(guān)鍵字恨憎,也沒(méi)有ON子句,其語(yǔ)法格式如下:

>> ANSI SQL 89只支持CROSS JOIN和INNTER JOIN郊楣,不支持OUTER JOIN憔恳。新語(yǔ)法是由ANSI SQL 92引入的,與舊語(yǔ)法的區(qū)別是引入了JOIN關(guān)鍵字和ON過(guò)濾子句净蚤,并去掉了表之間的逗號(hào)钥组,其語(yǔ)法格式如下:

>> CROSS JOIN對(duì)兩個(gè)表執(zhí)行笛卡兒積,返回兩個(gè)表中所有列的組合今瀑。若左表有m行數(shù)據(jù)程梦,右表有n行數(shù)據(jù),則CROSS JOIN將返回m*n行的表橘荠。

>> 對(duì)于交叉聯(lián)接屿附,筆者更喜歡使用ANSI SQL 89語(yǔ)法。這樣代碼會(huì)更短哥童,語(yǔ)法更加易讀挺份。不必?fù)?dān)心兩者的性能,因?yàn)檎缜懊嫠f(shuō)的贮懈,優(yōu)化器將為兩者生成相同的執(zhí)行計(jì)劃匀泊。

>> CROSS JOIN的一個(gè)用處是快速生成重復(fù)測(cè)試數(shù)

>> 據(jù),因?yàn)橥ㄟ^(guò)它可以很快地構(gòu)造m*n*o行的數(shù)據(jù)朵你。

>> 雖然對(duì)兩個(gè)N行表進(jìn)行笛卡兒積會(huì)產(chǎn)生N2行的數(shù)據(jù)各聘。但是如果是對(duì)一行表與N行表進(jìn)行CROSS JOIN,笛卡爾兒積返回的還是N行數(shù)據(jù)

>> 如果使用的是ANSI 92語(yǔ)法抡医,則選擇在哪個(gè)子句中指定過(guò)濾條件躲因,用戶具有更多的靈活性。因?yàn)榍懊嬲f(shuō)了,從邏輯上講毛仪,在哪里指定過(guò)濾條件都是一樣的搁嗓,通常不會(huì)有性能上的差異。唯一的準(zhǔn)則就是可讀性強(qiáng)箱靴。通過(guò)一種讓DBA、開(kāi)發(fā)人員感覺(jué)更自然的方式進(jìn)行代碼編寫荷愕。例如衡怀,在表之間匹配記錄的過(guò)濾器放在ON子句中,而只從一個(gè)表中過(guò)濾數(shù)據(jù)的條件放在WHERE子句中

>> 對(duì)于CROSS JOIN安疗,筆者喜歡使用ANSI 89語(yǔ)法抛杨,而對(duì)于INNER JOIN正好相反,更傾向于使用ANSI 92語(yǔ)法荐类。如果忘記指定聯(lián)接條件怖现,則使用ANSI 89語(yǔ)法可能有些危險(xiǎn),因?yàn)榭赡軙?huì)得到很大的笛卡兒積返回集

>> 特別需要注意的是玉罐,在MySQL數(shù)據(jù)庫(kù)中屈嗤,如果INNER JOIN后不跟ON子句,也是可以通過(guò)語(yǔ)法解析器的吊输,這時(shí)INNER JOIN等于CROSS JOIN饶号,即產(chǎn)生笛卡兒積

>> 如果ON子句中的列具有相同的名稱,可以使用USING子句來(lái)進(jìn)行簡(jiǎn)化季蚂,得到的結(jié)果和上述兩語(yǔ)法的語(yǔ)句結(jié)果是一樣的:

>> 目前MySQL數(shù)據(jù)庫(kù)不支持FULL OUTER JOIN茫船。

>> OUTER JOIN只在ANSI SQL 92中得到支持,在其他一些數(shù)據(jù)庫(kù)中可以使用(+)=扭屁、*=來(lái)表示LEFT JOIN算谈,用=(+)、=*來(lái)擴(kuò)展ANSI SQL 89語(yǔ)法使其支持OUTER JOIN料滥。

>> 但是對(duì)MySQL數(shù)據(jù)庫(kù)來(lái)說(shuō)然眼,只有一種OUTER JOIN的聯(lián)接語(yǔ)法。

>> 需要注意的是幔欧,INNER JOIN中的過(guò)濾條件都可以寫在ON子句中罪治,而OUTER JOIN的過(guò)濾條件不可以這樣處理,因?yàn)榭赡軙?huì)得到不正確的結(jié)果

>> 與INNER JOIN不同的是礁蔗,對(duì)于OUTER JOIN觉义,必須制定ON子句,否則MySQL數(shù)據(jù)庫(kù)會(huì)拋出異常浴井,

>> 前面介紹的都是EQUAL JOIN(等值聯(lián)接)晒骇,即聯(lián)接條件是基于“等于”運(yùn)算符的聯(lián)接操作。NONEQUI JOIN的聯(lián)接條件包含“等于”運(yùn)算符之外的運(yùn)算符。

>> 對(duì)于INNER JOIN的多表聯(lián)接查詢洪囤,可以隨意安排表的順序徒坡,而不會(huì)影響查詢的結(jié)果。這是因?yàn)閮?yōu)化器會(huì)自動(dòng)根據(jù)成本評(píng)估出訪問(wèn)表的順序瘤缩。在該查詢的執(zhí)行計(jì)劃中喇完,可能會(huì)發(fā)現(xiàn)優(yōu)化器訪問(wèn)表的順序不同于在查詢中指定的順序。

>> 如果認(rèn)為不按優(yōu)化器所選擇的順序聯(lián)接表會(huì)更加高效剥啤,可以通過(guò)前面介紹的STRAIGHT_JOIN來(lái)強(qiáng)制聯(lián)接處理的順序

>> 聯(lián)接算法是MySQL數(shù)據(jù)庫(kù)用于處理聯(lián)接的物理策略锦溪。目前MySQL數(shù)據(jù)庫(kù)僅支持Nested-Loops Join算法。而MySQL的分支版本MariaDB除了支持Nested-Loops Join算法外府怯,還支持Classic Hash Join算法刻诊。

>> Simple Nested-Loops Join從第一張表中每次讀取一條記錄,然后將記錄與嵌套表中的記錄進(jìn)行比較

>> 對(duì)于聯(lián)接的列含有索引的情況牺丙,外部表的每條記錄不再需要掃描整張內(nèi)部表则涯,只需要掃描內(nèi)部表上的索引即可得到聯(lián)接的判斷結(jié)果。

>> 根據(jù)前面描述的Simple Nested-Loops Join算法冲簿,優(yōu)化器在一般情況下總是選擇將聯(lián)接列含有索引的表作為內(nèi)部表粟判。如果兩張表R和S在聯(lián)接的列上都有索引,并且索引的高度相同民假,那么優(yōu)化器會(huì)選擇將記錄數(shù)最少的表作為外部表浮入,這是因?yàn)閮?nèi)部表的掃描次數(shù)總是索引的高度,與記錄的數(shù)量無(wú)關(guān)羊异。

>> Block Nested-Loops Join算法就是針對(duì)沒(méi)有索引的聯(lián)接情況設(shè)計(jì)的事秀,其使用Join Buffer(聯(lián)接緩沖)來(lái)減少內(nèi)部循環(huán)讀取表的次數(shù)。

>> Block Nested-Loops Join算法先把對(duì)Outer Loop表(外部表)每次讀取的10行記錄(準(zhǔn)確地說(shuō)是10行需要進(jìn)行聯(lián)接的列)放入Join Buffer中野舶,然后在Inner Loop表(內(nèi)部表)中直接匹配這10行數(shù)據(jù)易迹。因此,對(duì)Inner Loop表的掃描減少了1/10

>> 每次聯(lián)接使用一個(gè)Join Buffer平道,因此多表的聯(lián)接可以使用多個(gè)Join Buffer睹欲。

Join Buffer在聯(lián)接發(fā)生之前進(jìn)行分配,在SQL語(yǔ)句執(zhí)行完后進(jìn)行釋放一屋。

Join Buffer只存儲(chǔ)需要進(jìn)行查詢操作的相關(guān)列數(shù)據(jù)窘疮,而不是整行的記錄。

>> Block Nested-Loops Join算法不支持OUTER JOIN

>> 可以看到這次執(zhí)行計(jì)劃的Extra列中并沒(méi)有Using join buffer的提示冀墨,這也就意味著此時(shí)優(yōu)化器沒(méi)有使用Block Nested-Loops Join算法闸衫。從MySQL 5.6及MariaDB 5.3開(kāi)始,Join Buffer的使用得到了進(jìn)一步擴(kuò)展诽嘉,在OUTER JOIN中使用Join Buffer受到支持

>> ?5.6(MariaDB 5.3)開(kāi)始支持Batched Key Access Join算法(簡(jiǎn)稱BKA)蔚出,該算法的思想為結(jié)合索引和group這兩種方法(Simple Nested-

>> Loops Join和Block Nested-Loops Join只能使用一種)來(lái)提高search-for-match的操作弟翘,以此加快聯(lián)接的執(zhí)行效率

>> 因?yàn)锽atched Key Access Join算法的本質(zhì)是通過(guò)Multi-Range Read接口將非主鍵索引對(duì)于記錄的訪問(wèn),轉(zhuǎn)化為根據(jù)ROWID排序的較為有序的記錄獲取骄酗,所以要想通過(guò)Batched Key Access Join算法來(lái)提高性能稀余,不但需要確保聯(lián)接的列參與match的操作,還要有對(duì)非主鍵列的search操作趋翻。

>> Batched Key Access Join算法從本質(zhì)上來(lái)說(shuō)還是Simple Nested-Loops Join算法睛琳,其發(fā)生的條件為內(nèi)部表上有索引,并且該索引為非主鍵的踏烙,并且聯(lián)接需要訪問(wèn)內(nèi)部表主鍵上的索引掸掏。

>> Classic Hash Join算法同樣使用Join Buffer,先將外部表中數(shù)據(jù)放入Join Buffer中宙帝,然后根據(jù)鍵值產(chǎn)生一張散列表,這是第一個(gè)階段募闲,稱為build階段步脓。隨后讀取內(nèi)部表中的一條記錄,對(duì)其應(yīng)用散列函數(shù)浩螺,將其和散列表中的數(shù)據(jù)進(jìn)行比較靴患,這是第二個(gè)階段,稱為probe階段要出。

>> Hash Join只能應(yīng)用于等值的聯(lián)接操作中鸳君,因?yàn)橐淹ㄟ^(guò)散列函數(shù)生成新的聯(lián)接值,不能將Hash Join用于非等值的聯(lián)接操作中患蹂。

>> 倘若Join Buffer能夠完全存放下外部表的數(shù)據(jù)或颊,那么Classic Hash Join算法只需要掃描一次內(nèi)部表。反之传于,Classic Hash Join需要掃描多次內(nèi)部表

>> 正如前面所說(shuō)囱挑,當(dāng)Join Buffer不能存放下所有外部表中的數(shù)據(jù)時(shí),Classic Hash Join需要掃描內(nèi)部表多次沼溜。對(duì)于這種情況平挑,其他數(shù)據(jù)庫(kù)中使用的是Grace Hash Join算法,對(duì)內(nèi)部表和外部表都只需掃描一次系草,有興趣的讀者可以查找相關(guān)資料通熄。MariaDB有計(jì)劃支持Grace Hash Join算法,相信不久的將來(lái)也能在MySQL數(shù)據(jù)庫(kù)中看到Grace Hash Join算法找都。

>> MySQL數(shù)據(jù)庫(kù)支持兩種集合操作:UNION ALL和UNION DISTINCT

>> 集合操作的兩個(gè)輸入必須擁有相同的列數(shù)唇辨,若數(shù)據(jù)類型不同,MySQL數(shù)據(jù)庫(kù)會(huì)自動(dòng)將進(jìn)行隱式轉(zhuǎn)化檐嚣。同時(shí)助泽,結(jié)果列的名稱由第一個(gè)輸入決定啰扛。

>> UNION DISTINCT組合兩個(gè)輸入,并應(yīng)用DISTINCT過(guò)濾重復(fù)項(xiàng)嗡贺。一般省略DISTINCT關(guān)鍵字隐解,直接用UNION

>> 由于向臨時(shí)表添加了唯一索引,插入的速度顯然會(huì)因此而受到影響诫睬。如果確認(rèn)進(jìn)行UNION操作的兩個(gè)集合中沒(méi)有重復(fù)的選項(xiàng)煞茫,最有效的辦法應(yīng)該是使用UNION ALL。

UNION ALL組合兩個(gè)輸入中所有項(xiàng)的結(jié)果集摄凡,并包含重復(fù)的選項(xiàng)

>> MySQL數(shù)據(jù)庫(kù)并不原生支持EXCEPT的語(yǔ)法续徽,不過(guò)我們?nèi)匀豢梢酝ㄟ^(guò)一些手段來(lái)得到EXCEPT的結(jié)果。EXCEPT集合操作允許用戶找出位于第一個(gè)輸入中但不位于第二個(gè)輸入中的行數(shù)據(jù)亲澡。同UNION一樣钦扭,EXCEPT可分為EXCEPT DISTINCT和EXCEPT ALL。

第6章 聚合和旋轉(zhuǎn)操作

>> MySQL數(shù)據(jù)庫(kù)支持聚合(aggregate)操作床绪,按照分組對(duì)同一組內(nèi)的數(shù)據(jù)聚合進(jìn)行統(tǒng)計(jì)操作客情。

>> GROUP_CONCAT將分組后的非NULL數(shù)據(jù)

>> 通過(guò)連接符進(jìn)行拼接,對(duì)NULL數(shù)據(jù)返回NULL值癞己。

>> MySQL數(shù)據(jù)庫(kù)僅支持流聚合膀斋,而其他的數(shù)據(jù)庫(kù)可能會(huì)支持散列聚合。流聚合依賴于獲得的存儲(chǔ)在GROUP BY列中的數(shù)據(jù)痹雅。如果一個(gè)SQL查詢中包含的GROUP BY語(yǔ)句多于一行仰担,流聚合會(huì)先根據(jù)GROUP BY對(duì)行進(jìn)行排序。

>> ing是一項(xiàng)可以把行旋轉(zhuǎn)為列的技術(shù)绩社。在執(zhí)行Pivoting的過(guò)程中可能會(huì)使用到聚合摔蓝。Pivoting技術(shù)應(yīng)用得非常廣泛

>> 因此,在頻繁更改架構(gòu)的情況下铃将,可以在一個(gè)表中存儲(chǔ)所有的數(shù)據(jù)项鬼,每行存儲(chǔ)一個(gè)屬性的值,多用VARCHAR來(lái)存儲(chǔ)劲阎,因?yàn)槠淇扇菁{各種類型的數(shù)據(jù)

>> 在對(duì)通過(guò)開(kāi)放架構(gòu)設(shè)計(jì)的表進(jìn)行添加绘盟、修改或刪除表和列時(shí),只需要通過(guò)INSERT悯仙、UPDATE龄毡、DELETE操作來(lái)完成邏輯架構(gòu)的更改即可。當(dāng)然使用這種方法可能導(dǎo)致關(guān)系數(shù)據(jù)庫(kù)的其他特性無(wú)法使用锡垄,如完整性約束沦零、SQL優(yōu)化等,同時(shí)查詢數(shù)據(jù)變得不如使用之前的SQL語(yǔ)句來(lái)得直接和直觀货岭。所以路操,對(duì)于利用開(kāi)放架構(gòu)設(shè)計(jì)的表疾渴,一般使用Pivoting技術(shù)來(lái)查詢數(shù)據(jù)。

>> 這種旋轉(zhuǎn)方式是非常高效的屯仗,因?yàn)樗粚?duì)表進(jìn)行一次掃描搞坝。另外,這是一種靜態(tài)的Pivoting魁袜,用戶必須事先知道一共有多少個(gè)屬性桩撮,然而對(duì)于一般的開(kāi)放架構(gòu)表,用戶都會(huì)定義一個(gè)最大的屬性個(gè)數(shù)峰弹,這樣可以比較容易地進(jìn)行Pivoting店量。

第8章 事務(wù)編程

>> 對(duì)于Oracle數(shù)據(jù)庫(kù)來(lái)說(shuō),其默認(rèn)的事務(wù)隔離級(jí)別為READ COMMITTED鞠呈,不滿足I的要求融师,即隔離性的要求

>> 需要注意的是,持久性只能從事務(wù)本身的角度來(lái)保證結(jié)果的永久性蚁吝,如事務(wù)提交后诬滩,所有的變化都是永久的,即使當(dāng)數(shù)據(jù)庫(kù)由于崩潰而需要恢復(fù)時(shí)灭将,也能保證恢復(fù)后提交的數(shù)據(jù)都不會(huì)丟失。但如果不是數(shù)據(jù)庫(kù)本身發(fā)生故障后控,而是一些外部的原因庙曙,如RAID卡損壞、自然災(zāi)害等導(dǎo)致數(shù)據(jù)庫(kù)發(fā)生問(wèn)題浩淘,那么所有提交的數(shù)據(jù)可能會(huì)丟失捌朴。因此持久性保證的是事務(wù)系統(tǒng)的高可靠性(high reliability),而不是高可用性(high availability)张抄。對(duì)于高可用性的實(shí)現(xiàn)砂蔽,事務(wù)本身并不能保證,需要一些系統(tǒng)共同配合來(lái)完成署惯。

>> 帶有保存點(diǎn)的扁平事務(wù)左驾,除了支持扁平事務(wù)支持的操作外,允許在事務(wù)執(zhí)行過(guò)程中回滾到同一事務(wù)中較早的一個(gè)狀態(tài)极谊,這是因?yàn)榭赡苣承┦聞?wù)在執(zhí)行過(guò)程中出現(xiàn)的錯(cuò)誤并不會(huì)對(duì)所有的操作都無(wú)效诡右,放棄整個(gè)事務(wù)不合乎要求,開(kāi)銷也太大轻猖。保存點(diǎn)(savepoint)用來(lái)通知系統(tǒng)應(yīng)該記住事務(wù)當(dāng)前的狀態(tài)帆吻,以便以后發(fā)生錯(cuò)誤時(shí),事務(wù)能回到該狀態(tài)咙边。

>> 鏈?zhǔn)聞?wù)可視為保存點(diǎn)模式的一個(gè)變種猜煮。帶有保存點(diǎn)的扁平事務(wù)次员,當(dāng)發(fā)生系統(tǒng)崩潰時(shí),所有的保存點(diǎn)都將消失王带,因?yàn)槠浔4纥c(diǎn)是易失的(volatile)淑蔚,而非持久的(persistent)。這意味著當(dāng)恢復(fù)保存點(diǎn)時(shí)辫秧,事務(wù)需要從開(kāi)始處重新執(zhí)行束倍,而不能從最近的一個(gè)保存點(diǎn)繼續(xù)執(zhí)行。

>> 鏈?zhǔn)聞?wù)的思想是:在提交一個(gè)事務(wù)時(shí)盟戏,釋放不需要的數(shù)據(jù)對(duì)象绪妹,將必要的處理上下文隱式地傳給下一個(gè)要開(kāi)始的事務(wù)。注意柿究,提交事務(wù)操作和開(kāi)始下一個(gè)事務(wù)操作將合并為一個(gè)原子操作邮旷。這意味著下一個(gè)事務(wù)將看到上一個(gè)事務(wù)的結(jié)果,就好像在一個(gè)事務(wù)中進(jìn)行的蝇摸。

>> 鏈?zhǔn)聞?wù)與帶有保存點(diǎn)的扁平事務(wù)不同的是婶肩,帶有保存點(diǎn)的扁平事務(wù)能回滾到任意正確的保存點(diǎn)。而鏈?zhǔn)聞?wù)中的回滾僅限于當(dāng)前事務(wù)貌夕,即只能恢復(fù)到最近一個(gè)保存點(diǎn)律歼。對(duì)于鎖的處理,兩者也不相同啡专。鏈?zhǔn)聞?wù)在COMMIT后即釋放了當(dāng)前事務(wù)所持有的鎖险毁,而帶有保存點(diǎn)的扁平事務(wù)不影響迄今為止所持有的鎖。

>> MySQL命令行的默認(rèn)設(shè)置下们童,事務(wù)都是自動(dòng)提交(auto commit)的畔况,即執(zhí)行SQL語(yǔ)句后就會(huì)馬上執(zhí)行COMMIT操作。因此要顯式地開(kāi)啟一個(gè)事務(wù)須使用命令BEGIN和START TRANSACTION慧库,或者執(zhí)行命令SET AUTOCOMMIT=0跷跪,以禁用當(dāng)前會(huì)話的自動(dòng)提交。

>> 注意 Microsoft SQL Server的數(shù)據(jù)庫(kù)管理員或開(kāi)發(fā)人員往往忽視對(duì)于DDL語(yǔ)句的隱式提交操作齐板,因?yàn)樵贛icrosoft SQL Server數(shù)據(jù)庫(kù)中吵瞻,即使是DDL也是可以回滾的,這和InnoDB存儲(chǔ)引擎甘磨、Oracle這些數(shù)據(jù)庫(kù)完全不同听皿。

>> 令人驚訝的是,大部分?jǐn)?shù)據(jù)庫(kù)系統(tǒng)都沒(méi)有提供真正的隔離性宽档,最初或許是因?yàn)橄到y(tǒng)實(shí)現(xiàn)者并沒(méi)有真正理解這些問(wèn)題尉姨,如今這些問(wèn)題已經(jīng)弄清楚了,但是數(shù)據(jù)庫(kù)實(shí)現(xiàn)者在正確性和性能之間做了妥協(xié)吗冤。

>> 雖然ISO和ANSI SQL標(biāo)準(zhǔn)制定了四種事務(wù)隔離級(jí)別的標(biāo)準(zhǔn)又厉,但是很少有數(shù)據(jù)庫(kù)廠商遵循這些標(biāo)準(zhǔn)九府。比如Oracle數(shù)據(jù)庫(kù)就不支持READ UNCOMMITTED和REPEATABLE READ的事務(wù)隔離級(jí)別。

>> InnoDB存儲(chǔ)引擎默認(rèn)的支持隔離級(jí)別是REPEATABLE READ覆致,但是與標(biāo)準(zhǔn)SQL不同的是侄旬,InnoDB存儲(chǔ)引擎在REPEATABLE READ事務(wù)隔離級(jí)別下,使用Next-Key Lock的鎖算法煌妈,因此避免了幻讀的產(chǎn)生儡羔。這與其他數(shù)據(jù)庫(kù)系統(tǒng)(如Microsoft SQL Server數(shù)據(jù)庫(kù))是不同的。所以說(shuō)璧诵,InnoDB存儲(chǔ)引擎在默認(rèn)的REPEATABLE READ事務(wù)隔離級(jí)別下已經(jīng)能完全保證事務(wù)的隔離性要求汰蜘,即達(dá)到SQL標(biāo)準(zhǔn)的SERIALIZABLE隔離級(jí)別。

>> 在SERIALIZABLE的事務(wù)隔離級(jí)別之宿,InnoDB存儲(chǔ)引擎會(huì)對(duì)每個(gè)SELECT語(yǔ)句后自動(dòng)加上LOCK IN SHARE MODE族操,即給每個(gè)讀取操作加一個(gè)共享鎖。在這個(gè)事務(wù)隔離級(jí)別下比被,讀占用鎖了色难,因此對(duì)于一致性的非鎖定讀不再予以支持。由于InnoDB存儲(chǔ)引擎在REPEATABLE READ隔離級(jí)別下就可以達(dá)到3 °的隔離等缀,因此一般不在本地事務(wù)中使用SERIALIZABLE隔離級(jí)別枷莉,SERIALIZABLE事務(wù)隔

>> 離級(jí)別主要用于InnoDB存儲(chǔ)引擎的分布式事務(wù)。

>> XA事務(wù)允許不同數(shù)據(jù)庫(kù)之間的分布式事務(wù)尺迂,如一臺(tái)服務(wù)器是MySQL數(shù)據(jù)庫(kù)的依沮,另一臺(tái)是Oracle數(shù)據(jù)庫(kù)的,可能還有一臺(tái)服務(wù)器是SQL Server數(shù)據(jù)庫(kù)的枪狂,只要參與到全局事務(wù)中的每個(gè)節(jié)點(diǎn)都支持XA事務(wù)即可

>> 分布式事務(wù)使用兩段式提交(two-phase commit)的方式。

>> 在單個(gè)節(jié)點(diǎn)上運(yùn)行分布式事務(wù)沒(méi)有太大的實(shí)際意義宋渔,但是要在MySQL數(shù)據(jù)庫(kù)的命令下演示多個(gè)節(jié)點(diǎn)參與的分布式事務(wù)也是行不通的州疾。通常來(lái)說(shuō),都是通過(guò)編程語(yǔ)言來(lái)完成分布式事務(wù)的操作的皇拣。當(dāng)前Java的JTA(Java Transaction API)可以很好地支持MySQL的分布式事務(wù)严蓖,需要使用分布式事務(wù)應(yīng)該認(rèn)真參考其API。

>> 顯然氧急,第三種方法要快得多颗胡!這是因?yàn)槊恳淮翁峤欢家獙懸淮沃刈鋈罩荆源鎯?chǔ)過(guò)程load1和load2實(shí)際寫了10000次重做日志文件吩坝,而對(duì)于存儲(chǔ)過(guò)程load3來(lái)說(shuō)毒姨,實(shí)際只寫了1次重做日志。

>> 大多數(shù)程序員會(huì)使用第一種或者第二種方法钉寝,有人可能不知道InnoDB存儲(chǔ)引擎自動(dòng)提交的情況弧呐,另外有些人可能持有以下兩種觀點(diǎn):首先闸迷,在曾經(jīng)使用過(guò)的數(shù)據(jù)庫(kù)中,對(duì)于事務(wù)的要求總是盡快地進(jìn)行釋放俘枫,不能有長(zhǎng)時(shí)間的事務(wù)腥沽;其次,可能擔(dān)心存在Oracle數(shù)據(jù)庫(kù)中由于沒(méi)有足夠UNDO空間產(chǎn)生的Snapshot Too Old的經(jīng)典問(wèn)題鸠蚪。MySQL InnoDB存儲(chǔ)引擎都沒(méi)有上述兩個(gè)問(wèn)題今阳,因此程序員不論從何種角度出發(fā),都不應(yīng)該在一個(gè)循環(huán)中反復(fù)地進(jìn)行提交操作茅信,不論是顯式的提交還是隱式的提交盾舌。

>> 喜歡使用自動(dòng)回滾的人大多是以前使用Microsoft SQL Server數(shù)據(jù)庫(kù)的開(kāi)發(fā)人員。在Microsoft SQL Server數(shù)據(jù)庫(kù)中汹押,可以使用SET XABORT ON來(lái)自動(dòng)回滾一個(gè)事務(wù)矿筝,因?yàn)镸icrosoft SQL Server數(shù)據(jù)庫(kù)不僅會(huì)自動(dòng)回滾當(dāng)前的事務(wù),還會(huì)拋出異常棚贾,開(kāi)發(fā)人員可以捕獲到這個(gè)異常窖维。

>> 對(duì)于長(zhǎng)事務(wù)的問(wèn)題,有時(shí)可以通過(guò)將其轉(zhuǎn)化為小批量(mini batch)的事務(wù)來(lái)進(jìn)行處理妙痹。當(dāng)事務(wù)發(fā)生錯(cuò)誤時(shí)铸史,只需要回滾一部分?jǐn)?shù)據(jù),然后接著上次的已完成的事務(wù)繼續(xù)進(jìn)行怯伊。

第9章 索引

>> 順序讀攘战巍(sequntial read)是指順序地讀取磁盤上的頁(yè)。隨機(jī)讀裙⑶邸(random read)是指訪問(wèn)的頁(yè)不是連續(xù)的崭篡,需要磁盤的磁頭不斷移動(dòng)。這里需要注意的是吧秕,這里的“順序”指的是邏輯上的順序琉闪,在物理上不可能保證所有的數(shù)據(jù)都是順序的。

>> 在B+樹(shù)索引中砸彬,B+樹(shù)索引只能找到某條記錄所在的頁(yè)颠毙,需再根據(jù)二分查找法來(lái)進(jìn)一步找到記錄所在頁(yè)的具體位置。

>> 在介紹B+樹(shù)前砂碉,先要了解一下二叉查找樹(shù)蛀蜜。B+樹(shù)是通過(guò)二叉查找樹(shù),再由平衡二叉樹(shù)增蹭、B樹(shù)演化而來(lái)滴某。

>> 若想最大性能地構(gòu)造一個(gè)二叉查找樹(shù),需要這棵二叉查找樹(shù)是平衡的,因此引入了新的定義—平衡二叉樹(shù)壮池,又稱為AVL樹(shù)偏瓤。

>> 平衡二叉樹(shù)的定義如下:首先符合二叉查找樹(shù)的定義,其次必須滿足任何節(jié)點(diǎn)的兩棵子樹(shù)的高度最大差為1

>> 平衡二叉樹(shù)在查找方面的性能是比較高的椰憋,但不是最高的厅克,只是接近最高性能。要達(dá)到最好的性能需要建立一棵最優(yōu)二叉樹(shù)橙依,但是最優(yōu)二叉樹(shù)的建立和維護(hù)需要大量的操作证舟,因此一般只需建立一棵平衡二叉樹(shù)即可。

平衡二叉樹(shù)的查詢速度的確很快窗骑,但是維護(hù)一棵平衡二叉樹(shù)的代價(jià)非常大女责,通常需要1次或多次左旋或右旋來(lái)得到經(jīng)過(guò)插入或更新操作后二叉樹(shù)的平衡性

>> 相信在任何一本數(shù)據(jù)結(jié)構(gòu)書中都能找到B+樹(shù)的定義,其定義十分復(fù)雜创译,這里列出B+樹(shù)的定義只會(huì)讓讀者感到更加困惑

>> B+樹(shù)是為磁盤或其他直接存取輔助設(shè)備設(shè)計(jì)的一種平衡查找樹(shù)抵知,在B+樹(shù)中,所有記錄節(jié)點(diǎn)都是按鍵值的大小順序存放在同一層的葉子節(jié)點(diǎn)软族,各葉子節(jié)點(diǎn)通過(guò)指針進(jìn)行鏈接

>> B+樹(shù)的插入要求必須保證插入后葉子節(jié)點(diǎn)中的記錄依然順序排列刷喜,同時(shí)需要考慮插入到B+樹(shù)的3種情況,每種情況都可能導(dǎo)致不同的插入算法立砸,如表9-1所示掖疮。

>> 不管怎么變化,B+樹(shù)總會(huì)保持平衡颗祝,但是為了保持平衡需要在插入新的鍵值后做大量的拆分頁(yè)(split)操作浊闪,而B+樹(shù)主要用于磁盤,因此頁(yè)的拆分意味著磁盤的操作螺戳,應(yīng)該在可能的情況下減少頁(yè)的拆分搁宾。為此,B+樹(shù)提供了旋轉(zhuǎn)(rotation)的功能倔幼。

>> B+樹(shù)索引的本質(zhì)就是B+樹(shù)在數(shù)據(jù)庫(kù)中的實(shí)現(xiàn)盖腿,而B+樹(shù)索引在數(shù)據(jù)庫(kù)中的一個(gè)特點(diǎn)就是高扇出性。例如在InnoDB存儲(chǔ)引擎中凤藏,每個(gè)頁(yè)的大小為16KB。

>> 因此在數(shù)據(jù)庫(kù)中堕伪,B+樹(shù)的高度一般都在2~4層揖庄,這意味著查找某一鍵值最多只需要2到4次IO操作,這還不錯(cuò)欠雌。因?yàn)楝F(xiàn)在一般的磁盤每秒至少可以做100次IO操作蹄梢,2~4次的IO操作意味著查詢時(shí)間只需0.02~0.04秒。

>> 在MySQL數(shù)據(jù)庫(kù)中,索引是在存儲(chǔ)引擎層實(shí)現(xiàn)的禁炒,這意味著每個(gè)引擎的B+樹(shù)索引的實(shí)現(xiàn)方式可能是不同的而咆,取決于存儲(chǔ)引擎實(shí)現(xiàn)的本身。

B+樹(shù)索引可以分為聚集索引與輔助索引(非聚集索引)幕袱,但是這兩者本身都與之前討論的B+樹(shù)的數(shù)據(jù)結(jié)構(gòu)一樣暴备,區(qū)別僅在于所存放數(shù)據(jù)的內(nèi)容。

>> 聚集索引是根據(jù)主鍵創(chuàng)建的一棵B+樹(shù)们豌,聚集索引的葉子節(jié)點(diǎn)存放了表中的所有記錄涯捻。輔助索引是根據(jù)索引鍵創(chuàng)建的一棵B+樹(shù),與聚集索引不同的是望迎,其葉子節(jié)點(diǎn)僅存放索引鍵值障癌,以及該索引鍵值指向的主鍵。

>> 按性別進(jìn)行查詢時(shí)辩尊,可取值的范圍一般只有“M”和“F”涛浙,因此上述SQL語(yǔ)句得到的結(jié)果可能是該表50%的數(shù)據(jù)(我們假設(shè)男女比例1:1),這時(shí)添加B+樹(shù)索引是完全沒(méi)有必要的摄欲。相反轿亮,如果某個(gè)字段的取值范圍很廣,幾乎沒(méi)有重復(fù)蒿涎,即是高選擇性的哀托,那么此時(shí)使用B+樹(shù)索引是最適合的

>> 怎樣查看索引是否是高選擇性的呢?可以通過(guò)SHOW INDEX語(yǔ)句中的Cardinality列來(lái)觀察劳秋。Cardinality值非常關(guān)鍵仓手,表示索引中唯一只記錄數(shù)量的預(yù)估值。這里需要注意的是玻淑, Cardinality是一個(gè)預(yù)估值嗽冒,而不是一個(gè)準(zhǔn)確值,用戶也不可能得到一個(gè)準(zhǔn)確的值补履。在實(shí)際應(yīng)用中添坊,Cardinality/n_rows_in_table應(yīng)盡可能接近1,如果非常小箫锤,那么需要考慮是否還要建這個(gè)索引贬蛙。

>> 在OLAP中添加索引依據(jù)的是宏觀的信息,而不是微觀信息谚攒,這是因?yàn)樽罱K要得到的結(jié)果是提供給決策者的阳准。例如不需要在OLAP中對(duì)姓名字段進(jìn)行索引,因?yàn)楹苌贂?huì)對(duì)單個(gè)用戶進(jìn)行查詢馏臭。但是對(duì)于OLAP中的復(fù)雜查詢野蝇,需要涉及多張表之間的聯(lián)接操作,這時(shí)索引的添加是有意義的

>> 之前的MySQL版本不支持ICP,當(dāng)進(jìn)行索引查詢時(shí)绕沈,首先根據(jù)索引來(lái)查找記錄锐想,然后再根據(jù)WHERE條件來(lái)過(guò)濾記錄。在支持ICP后乍狐,MySQL數(shù)據(jù)庫(kù)會(huì)在取出索引的同時(shí)赠摇,判斷是否可以進(jìn)行WHERE條件的過(guò)濾,即將WHERE的部分過(guò)濾操作放在了存儲(chǔ)引擎層澜躺。在某些查詢中蝉稳,ICP會(huì)大大減少上層SQL層對(duì)于記錄的索取(fetch)掘鄙,從而提高數(shù)據(jù)庫(kù)的整體性能耘戚。

>> ICP優(yōu)化支持range、ref操漠、eq_ref和ref_or_null類型的查詢收津,當(dāng)前支持MyISAM和InnoDB存儲(chǔ)引擎。當(dāng)優(yōu)化器選擇ICP優(yōu)化時(shí)浊伙,可在執(zhí)行計(jì)劃的Extra列看到Using index condition提示撞秋。

>> 內(nèi)存數(shù)據(jù)庫(kù)中,一般使用T樹(shù)(T-Tree)作為其索引的數(shù)據(jù)結(jié)構(gòu)

>> T樹(shù)的好處是節(jié)點(diǎn)不存放數(shù)據(jù)嚣鄙,只存放指針吻贿,這樣能減少對(duì)內(nèi)存的使用,這對(duì)內(nèi)存數(shù)據(jù)庫(kù)來(lái)說(shuō)顯得尤為重要哑子。同時(shí)T樹(shù)也是一棵平衡二叉樹(shù)舅列,以此保證查找的性能。T樹(shù)中的T指的是T樹(shù)中節(jié)點(diǎn)的形狀卧蜓。

>> 當(dāng)前MySQL數(shù)據(jù)庫(kù)中帐要,Memory存儲(chǔ)引擎支持哈希索引。InnoDB存儲(chǔ)引擎支持自適應(yīng)哈希索引弥奸,用戶僅能開(kāi)啟該特性榨惠,不能對(duì)其進(jìn)行人工干預(yù)

第10章 分區(qū)

>> 分區(qū)功能并不是在存儲(chǔ)引擎層完成的,因此不只有InnoDB存儲(chǔ)引擎支持分區(qū)盛霎,常見(jiàn)的存儲(chǔ)引擎MyISAM赠橙、NDB等都支持分區(qū)

>> 分區(qū)的過(guò)程是將一個(gè)表或索引分解為多個(gè)更小、更可管理的部分愤炸。就訪問(wèn)數(shù)據(jù)庫(kù)的應(yīng)用而言期揪,從邏輯上講,只有一個(gè)表或一個(gè)索引摇幻,但是在物理上這個(gè)表或索引可能由數(shù)十個(gè)物理分區(qū)組成横侦。每個(gè)分區(qū)都是獨(dú)立的對(duì)象,可以獨(dú)自處理绰姻,也可以作為一個(gè)更大對(duì)象的一部分進(jìn)行處理枉侧。

>> MySQL數(shù)據(jù)庫(kù)支持的分區(qū)類型為水平分區(qū),并不支持垂直分區(qū)狂芋。此外榨馁,MySQL數(shù)據(jù)庫(kù)的分區(qū)是局部分區(qū)索引,一個(gè)分區(qū)中既存放數(shù)據(jù)又存放索引帜矾。全局分區(qū)是指翼虫,數(shù)據(jù)存放各個(gè)分區(qū)中,但是所有數(shù)據(jù)的索引放在一個(gè)對(duì)象中屡萤。

>> 目前珍剑,MySQL數(shù)據(jù)庫(kù)暫時(shí)不支持全局分區(qū)。

>> 不論創(chuàng)建何種類型的分區(qū)死陆,如果表中存在主鍵

>> 或唯一索引時(shí)毙籽,分區(qū)列必須是唯一索引的一個(gè)組成部分缸剪,

>> 唯一索引可以是NULL值,并且只要求分區(qū)列是唯一索引的一個(gè)組成部分,不需要整個(gè)唯一索引列都是分區(qū)列

>> 查看表在磁盤上的物理文件徘溢,啟用分區(qū)之后,表不再由一個(gè)ibd文件組成届宠,而是由建立分區(qū)時(shí)的各個(gè)分區(qū)ibd文件組成蛤袒,比如下面的t#P#p0.ibd、t#P#p1.ibd塌衰。

>> 通過(guò)EXPLAIN PARTITION命令我們可以發(fā)現(xiàn)诉稍,在上述語(yǔ)句中,SQL優(yōu)化器只需要搜索p2008這個(gè)分區(qū)猾蒂,而不會(huì)搜索所有的分區(qū)—稱為Partition Pruning(分區(qū)修剪)均唉,故查詢的速度得到了大幅度提升。

>> 產(chǎn)生這個(gè)問(wèn)題的主要原因是肚菠,對(duì)RANGE分區(qū)的查詢舔箭,優(yōu)化器只能對(duì)YEAR()、TO_DAYS()蚊逢、TO_SECONDS()和UNIX_TIMESTAMP()這類函數(shù)進(jìn)行優(yōu)化選擇

>> 在執(zhí)行INSERT操作插入多個(gè)行數(shù)據(jù)的過(guò)程中如果遇到分區(qū)未定義的值层扶, MyISAM和InnoDB存儲(chǔ)引擎的處理會(huì)完全不同。MyISAM引擎會(huì)將之前的行數(shù)據(jù)都插入烙荷,但之后的數(shù)據(jù)不會(huì)被插入镜会。而InnoDB存儲(chǔ)引擎將其視為一個(gè)事務(wù),沒(méi)有任何數(shù)據(jù)被插入

>> MySQL數(shù)據(jù)庫(kù)允許對(duì)NULL值進(jìn)行分區(qū)终抽,但是處理方法可能與其他數(shù)據(jù)庫(kù)完全不同戳表。MySQL數(shù)據(jù)庫(kù)的分區(qū)總是把NULL值視為小于任何的一個(gè)非NULL值桶至,這和MySQL數(shù)據(jù)庫(kù)中處理NULL值的ORDER BY操作是一樣的。

>> 因此對(duì)于不同的分區(qū)類型匾旭,MySQL數(shù)據(jù)庫(kù)對(duì)NULL值的處理也各不相同镣屹。

>> 如果一百萬(wàn)行和一千萬(wàn)行的數(shù)據(jù)本身構(gòu)成的B+樹(shù)的層次是一樣的,可能都是兩層价涝,那么上述主鍵分區(qū)的索引并不會(huì)帶來(lái)性能的提高女蜈。假設(shè)一千萬(wàn)行數(shù)據(jù)的B+樹(shù)的高度是3,一百萬(wàn)行數(shù)據(jù)的B+樹(shù)的高度是2色瘩,這樣上述主鍵分區(qū)的索引可以避免一次IO伪窖,從而提高查詢的效率。

>> MySQL 5.6開(kāi)始支持ALTER TABLE ... EXCHANGE PARTITION語(yǔ)法居兆。該語(yǔ)句允許分區(qū)或子分區(qū)中的數(shù)據(jù)與另一個(gè)非分區(qū)的表中數(shù)據(jù)進(jìn)行交換覆山。如果非分區(qū)表的數(shù)據(jù)為空,那么相當(dāng)于將分區(qū)中的數(shù)據(jù)移動(dòng)到非分區(qū)表中泥栖。若分區(qū)表的數(shù)據(jù)為空汹买,則相當(dāng)于將外部表中的數(shù)據(jù)導(dǎo)入分區(qū)中。

>> 交換的表須與分區(qū)表有相同的表結(jié)構(gòu)聊倔,但是表不能含有分區(qū)晦毙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市耙蔑,隨后出現(xiàn)的幾起案子见妒,更是在濱河造成了極大的恐慌,老刑警劉巖甸陌,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件须揣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钱豁,警方通過(guò)查閱死者的電腦和手機(jī)耻卡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牲尺,“玉大人卵酪,你說(shuō)我怎么就攤上這事“迹” “怎么了溃卡?”我有些...
    開(kāi)封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蜒简。 經(jīng)常有香客問(wèn)我瘸羡,道長(zhǎng),這世上最難降的妖魔是什么搓茬? 我笑而不...
    開(kāi)封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任犹赖,我火速辦了婚禮队他,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘峻村。我一直安慰自己漱挎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布雀哨。 她就那樣靜靜地躺著,像睡著了一般私爷。 火紅的嫁衣襯著肌膚如雪雾棺。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天衬浑,我揣著相機(jī)與錄音捌浩,去河邊找鬼。 笑死工秩,一個(gè)胖子當(dāng)著我的面吹牛尸饺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播助币,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浪听,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了眉菱?” 一聲冷哼從身側(cè)響起迹栓,我...
    開(kāi)封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俭缓,沒(méi)想到半個(gè)月后克伊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡华坦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年愿吹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惜姐。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犁跪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出歹袁,到底是詐尸還是另有隱情耘拇,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布宇攻,位于F島的核電站惫叛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏逞刷。R本人自食惡果不足惜嘉涌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一妻熊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧仑最,春花似錦扔役、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至预皇,卻和暖如春侈玄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吟温。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工序仙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鲁豪。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓潘悼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親爬橡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子治唤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容