第1章資料模型設計
第1條:確保所有表都有主鍵
【1】當表缺少主鍵時,會出現各種問題,所有表都必須有一列(或多列)設定為主鍵。
【2】主鍵應當具備的特徵
唯一性,值非空,不可變,儘可能簡單
【3】不要使用複合主鍵,效率太低
定義主鍵時,大多數資料庫會同時強制建立唯一索引
適用主鍵做連線查詢很常見,但是在具有多個列的主鍵上這樣做很複雜,效率也很低
【4】如果不希望非鍵列出現重複資料,在列上定義唯一索引以保證其完整性。
第2條:避免儲存冗餘資料
【1】規範化是按照不同的主題將資訊分類,以避免冗餘資料的存在
【2】冗餘是指使用者在不同地方輸入相同資料的情況
【3】規範化最重要的目標就是最小化資料重複
【4】通過消除冗餘資料,避免插入、更新和刪除時出現異常
第3條:消除重複資料組
【1】資料庫規範化的目標是消除重複的資料組,並儘可能減少表結構的修改
【2】通過刪除重複的資料組,可以使用唯一的索引來防止以外的重複資料,並大大簡化查詢語句
【3】刪除重複的資料組使設計更加靈活,因為新增新的資料組只需要加一條記錄,而不用修改表設計增加更多的列
第4條:每列只儲存一個屬性
【1】正確的表設計師為每個分配單獨的列,當列包含多個屬性時,搜尋和分組即使有可能做,也會是極其困難的
【2】對於某些應用程式,有過濾列中的某部分資料的需求,這可能會決定列的粒度級別
【3】當需要重新把屬性組合成報表或列印清單時,適用連線
第5條:理解為什麼儲存計算列通常有害無益
【1】如果這個表用於大型線上資料錄入系統,建立計算列可能會對伺服器造成巨大的負載,從而影響伺服器的響應時間
【2】許多資料庫系統允許你在建立表時定義計算類,但應該主義效能影響,特別是在適用非確定性表示式或函式的時候
【3】你還可以像定義普通列一樣定義計算列,然後適用觸發器來維護,但是編寫觸發器的程式碼可能會很複雜
【4】計算列會對資料庫系統產生額外的開銷,只有當利大於弊時候才考慮適用它
【5】大多數情況下,你希望在計算列上建立一個索引,以小號更多的儲存空間和攪蠻的更新作為交換,獲得一些便利性
【6】當不能使用索引時,使用檢視來做計算通常可以作為在表裡建立計算列的計算方法
第6條:定義外來鍵以確保引用完整性
【1】正確地設計資料庫時,在許多表中都會包含應用相關父表主鍵的外來鍵
【2】外來鍵明顯有助於保證相關表之間的資料完整性,確保子表的記錄能在父表找到對應的記錄
【3】如果表中存在違反約束的資料,向表中新增FOREIGN KEY約束將失敗
【4】在某些資料庫系統中,定義FOREIGN KEY約束將會最懂建立索引,這樣可以提高連線查詢的效能。在其他一些資料庫系統中,建立索引來覆蓋FOREIGN KEY約束必須小心。即使沒有索引,一些資料庫系統優化器也會特別對待這些列,以提供更好的查詢效率
第7條:確保表間關係的合理性
【1】再三斟酌,為了簡化關係模型而合併包含相似欄位的表是否真的有意義
【2】只要對應列資料型別匹配【或可以隱式地強制轉換】,就可以在兩個表之間建立連線,但只有當列當屬於同一個業務領域時,關係才是有效的。所以,最理想的連線是兩端都具有相同的資料型別和業務領域
【3】在建模之前,檢查你處理的資料是否是結構化資料。如果是半結構化的,則要做特殊的處理
【4】明確資料模型的目標通常有助於判斷給定的設計是否由於簡化關係模型和適用此資料模型應用程式的設計導致了複雜性或異常的增加
第8條:當第三正規化不夠時,採用更多正規化
【1】判斷一個設計遵循第三正規化但可能違反更高正規化的警告標誌是,看一個表是否與其他多個表關聯,特別是當表參與了多個多對多的關係時。
【2】另一個判斷方法是,如果表包含複合鍵就有可能違反較高的正規化。
【3】前三個正規化關注關係中屬性之間的功能依賴,功能依賴是指屬性依賴於關係中的鍵。
【4】對於四個正規化,我們關注的是多值依賴,是兩個彼此獨立的屬性同時依賴關係中同一個鍵的情況
【5】大多數資料模型已經滿足了較高的正規化。因此,只需要注意某些明顯違反高階正規化的情況
【6】第四正規化只有在某些特殊的情況下才會違反
【7】第五正規化要求候選鍵可推匯出所有連線依賴,意味著你應該能夠基於各個屬性來約束候選鍵的有效值。這種情況只發生在複合鍵上
【8】第六正規化是將表的關係減少到只存在一個非關鍵屬性,這樣會導致表的數量膨脹,但是可以避免出現空值的列
【9】無損分解是檢測表是否違反較高正規化的一個有效工具
第9條:非規範化資料倉儲
【1】規範化的表通常比非規範化的表更小且佔用的空間更少
【2】資料被拆分成多個小表,小到足以存在快取中,效能通常也更好
【3】想清楚要複製的資料及原因
【4】計劃如何保持資料同步
【5】適用非規範化欄位重構查詢
第2章可程式設計性與索引設計
第10條:建立索引時空值的影響
【1】null是關聯式資料庫中的特殊值,表示列位置或資料確實。
【2】null永遠不能等於或不等於另一個值,甚至是另一個null也不行
【3】要檢測是否存在null值,必須適用IS NULL條件
【4】建立索引時考慮列是否包含空值
【5】如果要搜尋空值,但列中的大多數值都可能為NULL,那麼最好不要對列進行索引。這也可能表明表需要重新設計
【6】如果希望更快地對列進行搜尋,但列中大多數值為NULL,具有資料庫支援的話,可以建立排除空值的索引
【7】每種資料庫處理索引中空值的方法都不同。在為可能包含空值的列上建立索引時,確保瞭解資料庫系統的選項
第11條:建立索引時謹慎考慮以最小化索引和資料掃描
【1】儘管加大硬體的投資可以提高效能,但是優化查詢通常可以以更低成本的方式獲得更好的效果
【2】導致效能問題常見的原因是缺少索引或者設定了錯誤的索引,這會導致資料庫引擎必須處理更多的資料來查詢符合條件的記錄。這些問題通常被稱為索引掃描和表掃描
【3】當資料庫引擎需要通過掃描索引或者資料塊來能找到相應的記錄時,就需要索引掃描或表掃描
【4】分析資料,建立正確的索引以提高效能
【5】確保建立的索引都被使用
第12條:索引不只是過濾
【1】資料庫索引在資料庫中擁有獨特的資料結構
【2】由於索引會複製已索引表的資料,所以每個索引都有屬於自己的磁碟空間,所以索引時純冗餘的,但這種冗餘是可以接受的
【3】因為索引不需要在每次查詢中索引表中的每一個行,可以快速定位資料提高資料檢索操作的速度
【4】WHERE子句中的列是否包含在索引中會查詢的效能產生影響,一個寫的很差的WHERE字句是緩慢查詢的罪魁禍首
【5】SELECT子句中的列是否被索引也會影響查詢的效率
【6】連線查詢的列是否被索引可能會影響查詢的效率
第13條:不要過度使用觸發
【1】建立表時,因為使用約束提供的DRI以及內建功能建立的計算列,效能通常會更好,所以我們建議將約束或建立計算列的內建功能作為預設解決方案
【2】觸發器通常不可移植:一個資料庫系統的觸發器,在不做修改的情況下,很難在另一個資料庫系統中執行
【3】僅在絕對必要時才使用觸發器。如果可能,確保觸發器是冪等的
第14條:使用過濾索引包含或排除資料子集
【1】過濾索引進隊少部分行有用,可節省空間
【2】過濾索引可用於對行自己執行為以約束
【3】過濾索引可避免排序操作
【4】考慮是否需要分割槽表來提供類似過濾索引的功能,從而避免維護一個索引的成本
第15條:使用宣告式約束替代編碼校驗
【1】考慮使用約束來槍支資料完整性
【2】查詢優化器可以使用約束定義來構建高效能查詢執行計劃
第16條:瞭解資料庫使用的SQL方言並編寫相應的
【1】即使一條語句可能複合SQL標準,也可能無法在你的DBMS中使用
【2】由於不同的DBMS以不同方式執行,相同的SQL語句在效能上的表現也會不同
第17條:瞭解何時在索引中使用計算結果
【1】不要過度使用索引
【2】分析資料庫預期的使用情況,以確保過濾索引僅在真正有意義的地方使用
第3章 當你不能改變設計時
第18條:使用檢視來簡化不能更改的
【1】檢視是一種讓使用者建立自然或至關的結構化資料的方式
【2】使用檢視來限制對資料的訪問,限制使用者儘可以看到【有時候可以修改】他們所需要的資料
【3】使用檢視來隱藏和重用複雜的查詢
【4】檢視可從各種表中彙總用於生成報告的資料
【5】使用檢視實現和強制命名及編碼標準,特別是在需要更新舊資料庫的結構時
第19條:使用ETL將非關係資料轉換為有用的資訊
【1】ETL工具讓你能更容易並非關係資料匯入到資料庫中
【2】ETL工具可幫助你重新格式化並重新排列匯入的資料,以便將其轉換為有用的資訊
【3】大多數資料庫系統中提供了某些勒死的ETL工具,也有一些商業工具可用
第20條:建立彙總表並維護
【1】儲存彙總資料可以幫助最小化聚合流程
【2】使用表儲存彙總資料後,可以索引包含聚合資料的欄位,以便更有效地查詢彙總資料
【3】彙總對於幾乎靜態的表效果最好。如果原表變化太頻繁,則彙總的開銷可能太大
【4】觸發器可用於執行彙總,但重建彙總表的儲存過程通常更好
第21條:使用UNION語句將非規範化資料列轉行
【1】UNION查詢中的每個SELECT語句必須具有相同數量的列
【2】儘管SELECT語句的列名並不重要,但每列的資料型別必須相容
【3】要控制資料出現的順序,可以再最後一個SELECT語句之後使用ORDER BY子句
【4】如果你不希望消除重複行或能夠承受移除重複行帶來的效能損失,請使用UNION ALL替代UNION
第4章過濾與查詢資料
第22條:瞭解關係代數及其如何在SQL實理
【1】關係模型定義了你可以再集合上執行的8個操作
【2】所有主流的SQL實現都支援選擇、投影、連線、笛卡爾積和並集
【3】一些SQL的實現使用INTERSECT和EXCEPT或MINUS關鍵字支援交集和差集
【4】實現SQL的主流資料庫系統都不支援除操作,但可以通過SQL的其他操作得到相同的結果
第23條:查詢不匹配或缺失的記
【1】雖然易於理解,但使用NOT IN運算子通常不是最有效的辦法
【2】使用NOT EXISTS操作符通常比使用NOT IN運算子更快
【3】使用無效連線通常是非常有效的,但這取決於DBMS如何處理空值
【4】使用DBMS查詢分析器來確定哪種方式最適合你的具體情況
第24條:瞭解何時使用CASE解決問題
【1】當你需要解決IF...THEN...ELSE這類問題時,CASE是一個強大的工具
【2】你可以使用簡單的CASE來執行相等判斷和基於搜尋的CASE以使用複雜的條件
【3】可以使用表示式的地方都可以使用CASE,包括作為SELECT子句的列定義或作為WHERE或HAVING子句條件的一部分
第25條:瞭解解決多條件查詢的技術
【1】需要通過關聯表或多個表判斷多個條件才能解決問題,通常都比較複雜
【2】當父表查詢需要在其一個或多個子表的相應記錄滿足多個條件時才能翻會記錄,必須在表子查詢中使用INNER JOIN或OUTER JOIN並結合空值判斷,或者或者在表子查詢中使用IN和AND或NOT IN和OR才能得到正確的結果
第26條:如需完美匹配,先對資料進行除操作
【1】除是8個公認的關係集操作之一,但SQL標準和主流資料庫系統都不支援DIVIDE關鍵字
【2】你可以使用除來查詢一組資料中匹配另一組資料所有記錄的記錄
【3】你可以通過測試除數集中的每一行、NOT EXISTS和GROUP BY或HAVING來執行除操作
第27條:如何按時間範圍正確地過濾日期和時間的列
【1】不要依賴隱式日期轉換;使用顯式轉換函式來處理日期字元
【2】不要將函式應用於日期和時間列,否則查詢將不能使用索引
【3】攝入誤差可能導致日期和時間值不正確;使用>=和<替代BETWEEN
第28條:書寫可引數化搜尋的查詢以確保引擎使用索引
【1】避免使用不可引數化搜尋的操作符
【2】不要再WHERE子句中的一個或多個欄位上使用函式
【3】不要對WHERE子句的欄位進行算數運算
【4】使用LIKE操作符時,只能在字串末尾使用萬用字元【不是‘%something’或‘some%thing’】
第29條:正確地定義“左”連線的“右”側
【1】在SQL中使用OUTER JOIN執行差集操作
【2】當你對外部WHERE子句中的左連線加入右側資料使用過濾時,你將無法獲得所需的結果,反之亦然
【3】要正確地過濾資料自己,必須在資料庫系統執行外連線之前使用過濾
第5章聚合
第30條:理解GROUPBY的工作原理
【1】聚合在執行WHERE子句之後完成
【2】GROUP BY子句聚合過濾後的資料集
【3】HAVING子句過濾聚合後的資料集
【4】ORDER BY子句對變換後的資料集進行排序
【5】在SELECT子句中沒有使用聚合函式或計算的任何列必須同時出現在GROUP BY子句中
【6】使用ROLLUP、CUBE和GROUPING SETS可以在單個查詢中提供更多可能的組合、以代替建立多個聚合查詢,然後再將其合併
第31條:簡化GROUP BY子句
【1】某些DMBS要求將非聚合的列也新增到GROUP BY,即使當前的SQL標準不再需要這麼做
【2】GROUP BY中的列過多可能會對查詢的效能產生負面影響、也會使閱讀、理解和重寫變得困難
【3】對於同時需要聚合和詳細資訊的查詢,首先在子查詢中執行所有聚合,然後將結果再連線到其他表以查詢詳細資訊
第32條:利用GROUP BY或HAVING解決複雜的問題
【1】在分組之前使用WHERE子句過濾記錄,分組後使用HAVING過濾記錄
【2】HAVING子句可以過濾聚合表示式
【3】即使你在SELECT子句中已給聚合表示式明明,如果要在HAVING子句中使用表示式,必須重寫該表示式。不能重用SELECT中的名稱。
【4】可以將簡單文字的聚合值與複雜子查詢聚合返回的值進行比較
第33條:避免使用GROUP BY來查詢最大值或最小值
【1】主表連線到自身需要使用LEFT JOIN
【2】將GROUP BY子句中的每一列都變成ON 子句的一部分,並使用相等=進行比較
【3】MAX()或MIN()子句中的列將成為ON子句的一部分,並且使用<或>
【4】應該為ON子句中的列新增索引,以過的更好的效能,特別是針對較大的資料集時
第34條:使用OUTER JOIN時避免獲取錯誤的COUNT()
【1】使用COUNT(*)來統計所有記錄的總數,也包括空值的記錄
【2】使用COUNT()僅統計列值不為NULL的記錄的總數
【3】有時一個子查詢甚至一個相關的子查詢,也會比使用GROUP BY有效率
第35條:測試HAVING COUNT(x) <某數時包含零值記錄
【1】使用INNER JOIN不能找出零計數
【2】過濾左連線的右側,將獲得相當於內連線的結果。將過濾器移入子查詢或在ON條件中過濾右側
【3】當想大於1的總計數時,尋找零計數可以幫助你識別資料中的問題
第36條:使用DISTINCT獲取不重複的計數
【1】使用COUNT()函式適當的方式來簡化計算
【2】可以考慮使用函式作為COUNT()函式的引數,以便不需要使用WHERE子句就能執行組合計算
第37條:知道如何使用視窗函式
【1】視窗函式感知周圍的行,這使得建立執行或移動聚合比傳統的聚合函式和語句級分組更容易
【2】視窗函式是更需要對不同的或獨立的資料應用聚合的理想選擇
【3】視窗函式可以與現有的聚合函式一起使用,並通過包含OVER子句來啟用
【4】PARTITION BY謂詞可用於制定必須將該分組應用於聚合表示式
【5】ORDER BY謂詞通常很重要,因為它影響後續行將如何計算其聚合表示式
第38條:建立行號與排名
【1】必須始終對ROW_NUMBER()、RANK()和其他排序函式進行視窗化,因此必須與相應的OVER子句一起出現
【2】考慮如何使用排序函式處理關聯。如果你需要連續排名,應該使用DENSE_RANK()
【3】ORDER BY謂詞對於這類函式是強制性的,因為它會影響結果如何排序
第39條:建立可移動聚合函
【1】無論如何需要將視窗框架的邊界更改為非預設設定,即使可選,也必須指定ORDER BY謂詞
【2】如果需要為視窗框架定義任意大小,則必須使用ROWS,這樣可以輸入需要包含在視窗框架中的前後幾行
【3】RANGE只能接受UNBOUNDED PRECEDING、CURRENT ROW或UNBOUNDED FOLLOWING作為有效選項
【4】你可以選擇RANGE邏輯分組行貨ROWS物理偏移行。如果ORDER BY謂詞不返回重複值,則兩者結果是等效的
第6章 子查詢
第40條:瞭解在何處使用子查詢
【1】你可以在任何使用表、檢視或能夠返回表的函式或過程的位置使用表子查詢
【2】你可以在任何使用表子查詢和需要為IN或NOT IN條件提供一個列表的位置,使用返回單列的表子查詢
【3】你可以在任何使用列名的位置使用標量子查詢,如在一個SELECT語句中,或在一個SELECT語句的表示式,或作為比較條件的一部分
第41條:瞭解關聯和非關聯子查詢的差異
【1】關聯子查詢在WHERE或HAVING子句中使用一個應用,該應用依賴於潛入子查詢的查詢返回值
【2】非關聯子查詢不依賴於外部查詢,並且可以獨立執行
【3】通常,你可以使用非關聯子查詢,為FROM子句提供已過濾的資料集,或作為IN條件的單列資料集,或作為在WHERE或HAVING子句中為比較條件返回的標量值
【4】你可以使用關聯子查詢,為SELECT子句返回標量值,在WHERE或HAVING子句中為比較條件提供單個值進行測試,或者在EXISTS子句中提供用於存在性檢驗的資料集合
【5】關聯子查詢不一定比其他方法慢,但它可能是返回正確結果的唯一方法
第42條:儘可能使用公共表表示式而不是子查詢
【1】利用公用表表示式【CTE】,你可以簡化多次使用相同子查詢的複雜查詢
【2】CTE可以免除使用可能無意中更改的功能,而這樣的修改會導致使用該函式的查詢無法正常工作
【3】在同一SQL中,CTE允許你直接定義要嵌入到另一個查詢中的子查詢,這樣做也更容易理解
【4】雖然你可以使用遞迴CTE生成一些資料值,這些值在計數表中找到,但儲存的基數表效率更高,因為你可以對其新增索引
【5】你可以使用遞迴CTE遍歷層次關係,並以有意義的方式進行展示
第43條:使用連線而非子查詢建立更高效的查詢
【1】不要認為按順序解決問題是首選方法。SQL語句最適合按集合,而不是按行執行
【2】瞭解DBMS優化器多種處理方式的特性,從而決定首選的解決方案
【3】確保為任何連結都建立了適當的索引
第7章 獲取與分析後設資料
第44條:瞭解如何使用系統的查詢分析器
【1】執行計劃中顯示地資訊可能會隨時間而變化
【2】DB2要求先建立系統表。它將執行計劃儲存在這些系統表中,而不是顯示它們。它會產生預估的計劃
第45條:學習獲取資料庫的後設資料
【1】儘可能使用SQL標準的INFORMATION_SCHEMA檢視
【2】INFORMATION_SCHEMA在DBMS之間並不完全一樣
第46條:理解執行計劃的工作原理
【1】每當你閱讀執行計劃時,將其轉換為實際步驟,分析是否存在未使用的索引,並確定其未被使用的原因
【2】分析各個步驟,並判斷它們是否有效。請注意,效率受資料分部的影響。因此沒有所謂的“壞”操作,而是分析所使用的的操作是否適合正在使用的查詢
【3】不要因為一個查詢就加上索引來改善執行計劃,你必須從資料庫出發全盤考慮以確保索引儘可能的通用
【4】注意大與小情況,其中資料分佈不均的資料對同一個查詢會需要不同的優化。當執行計劃被快取和重用時,這個問題就特別嚴重
第8章 笛卡兒積
第47條:生成兩張表所有行的組合並標示一張表中間接關聯另一張表的列
【1】使用笛卡爾積產生兩個表之間的各種組合
【2】使用INNER JOIN確定實際發生的組合
【3】使用LEFT JOIN將笛卡爾積的結果與實際發生的組合列表進行比較
【4】你還可以使用SELECT子句中CASE語句中的IN子查詢來產生於使用笛卡爾積及LEFT JOIN相同的結果,但效能取決於資料流、索引和特定DBMS
第48條:理解如何以等分量排名
【1】將等分資料分成排名區間是評估資訊有趣有用的方式
【2】使用RANK()視窗函式輕鬆建立排名值
【3】將1除以分割槽數以產生每個分割槽的乘數
第49條:知道如何對錶中的行配對
【1】找出從N個專案中取出K個專案的排列組合很有用
【2】有獨特列時找出排列組合很容易
【3】要增加每個組合選擇的專案數量時,只需將目標表的另一個副本新增到查詢中即可
【4】操作大量資料時要小心,因為最終可能產生成百上千億行
第50條:理解如何列出類別與前三偏好
【1】除運算可找出完全匹配
【2】如果接受部分匹配,則需要套用其他技巧
【3】表中有排名的資料可以幫助你決定最佳的匹配
第9章計數表
第51條:根據計數表內定義的引數生成空行
【1】生成空白行可能是有用的,特別是對於報表
【2】你可以使用遞迴CTE或技術表來幫助你生成空行。在某些情況下,直接使用表可能會更快
【3】為了方便為空行數提供引數值,建立一個接收引數的函式,以便你可以從SELECT語句中呼叫它
第52條:使用計數表和視窗函式生成序列
【1】計數表可以與視窗函式一起使用,以提供更多的序列或其他需要以視窗描述的方式
【2】非等式連線與計數表在需要憑空產生記錄時很有用
第53條:根據計數表內定義的範圍生成行
【1】使用計數表產生資料庫中沒有的值
【2】當計數表包含一個範圍的值時,你可以比較此範圍與現有資料以產生相對值
【3】你可以使用序列計數表根據另一個計數表的值生成行
第54條:根據計數表定義的值範圍轉換某個表中的值
【1】確保你的轉換計數表符合你的資料設計
【2】確保非等式中使用的不等式適用於正在使用的計數表
第55條:使用日期表簡化日期計算
【1】對於日期與日期運算密集的應用程式,日期表可大幅簡化邏輯
【2】日期表可加入工作日、假日或財年等特定應用領域
【3】由於日期表基本上是個維度表,因此即使是線上交易處理資料庫也可以大量建立索引。如果可能,將表明確地儲存在記憶體中能夠避免磁碟存取並改善優化器的判斷
第56條:建立在某個範圍內所有日期的日程表
【1】確保你的日期表有適當的索引
【2】確保WHERE子句從適當的表中測試值
第57條:使用計數錶行轉列
【1】需要行轉列資料時,你的資料庫系統可能有專屬的語法
【2】若只想要使用標準SQL,你可以使用CASE表示式對資料進行行列轉換,以提供聚合函式中每行需要的值
第10章 層次資料建模
第58條:從鄰接列表模型開始
【1】鄰接列表只是在表中新增一個自引用表的主鍵的一個外來鍵。不需要後設資料
【2】始終使用鄰接列表模型構建一致的層次模型
第59條:對不常更新的資料使用巢狀集以提升查詢效能
【1】你必須使用儲存過程來維護巢狀集模型,以封裝構建集合後的邏輯,併為每個節點分配正確的左和右數字。
【2】巢狀集模型不適用於頻繁更新的情況,因為對層次結構的更改需要對其他幾個節點進行重新編號,可能是整個表,這可能會導致死鎖。
【3】獲取計數不需要查詢其他記錄,因為它可以從lft和rgt後設資料列計算,使得巢狀集模型對於維護統計資訊非常有效。
【4】巢狀集模型只能使用單個根節點的單個層次結構。如果你需要多個層次結構,多個根節點,請考慮其他模型。
第60條:使用儲存路徑簡化設定與搜尋
【1】儲存路徑的好處是容易理解與處理,因為它基於我們都熟悉的檔案系統路徑。
【2】設計的限制很難發現,因為沒有簡單的方法預知層次結構是否太深或太寬而超過索引的限制。因此你必須對層次結構加上限制以避免產生問題。
【3】儲存路徑的搜尋僅在一個方向上有效,因為在開始或謂詞中有萬用字元時不能建立可搜尋的查詢。設計時要考慮這一點。
第61條:使用祖先遍歷閉包做複雜搜尋
【1】當你需要頻繁更新和易於搜尋時,使用祖先遍歷閉包模型,但代價是維護祖先表的額外複雜性。
【2】雖然比較規範化,但是不能將祖先表中的後設資料保持為最新,可能導致查詢結果不正確。這可以通過在Employees表上使用觸發器來自動修改祖先表來緩解,但需要付出一定的成本。