資料庫優化策略
① 誰知道資料庫優化設計方案有哪些
本文首先討論了基於第三範式的資料庫表的基本設計,著重論述了建立主鍵和索引的策略和方案,然後從資料庫表的擴展設計和庫表對象的放置等角度概述了資料庫管理系統的優化方案。
關鍵詞: 優化(Optimizing) 第三範式(3NF) 冗餘數據(Rendant Data) 索引(Index) 數據分割(Data Partitioning) 對象放置(Object Placement)
1 引言
資料庫優化的目標無非是避免磁碟I/O瓶頸、減少CPU利用率和減少資源競爭。為了便於讀者閱讀和理解,筆者參閱了Sybase、Informix和Oracle等大型資料庫系統參考資料,基於多年的工程實踐經驗,從基本表設計、擴展設計和資料庫表對象放置等角度進行討論,著重討論了如何避免磁碟I/O瓶頸和減少資源競爭,相信讀者會一目瞭然。
2 基於第三範式的基本表設計
在基於表驅動的信息管理系統(MIS)中,基本表的設計規范是第三範式(3NF)。第三範式的基本特徵是非主鍵屬性只依賴於主鍵屬性。基於第三範式的資料庫表設計具有很多優點:一是消除了冗餘數據,節省了磁碟存儲空間;二是有良好的數據完整性限制,即基於主外鍵的參照完整限制和基於主鍵的實體完整性限制,這使得數據容易維護,也容易移植和更新;三是數據的可逆性好,在做連接(Join)查詢或者合並表時不遺漏、也不重復;四是因消除了冗餘數據(冗餘列),在查詢(Select)時每個數據頁存的數據行就多,這樣就有效地減少了邏輯I/O,每個Cash存的頁面就多,也減少物理I/O;五是對大多數事務(Transaction)而言,運行性能好;六是物理設計(Physical Design)的機動性較大,能滿足日益增長的用戶需求。
在基本表設計中,表的主鍵、外鍵、索引設計佔有非常重要的地位,但系統設計人員往往只注重於滿足用戶要求,而沒有從系統優化的高度來認識和重視它們。實際上,它們與系統的運行性能密切相關。現在從系統資料庫優化角度討論這些基本概念及其重要意義:
(1)主鍵(Primary Key):主鍵被用於復雜的SQL語句時,頻繁地在數據訪問中被用到。一個表只有一個主鍵。主鍵應該有固定值(不能為Null或預設值,要有相對穩定性),不含代碼信息,易訪問。把常用(眾所周知)的列作為主鍵才有意義。短主鍵最佳(小於25bytes),主鍵的長短影響索引的大小,索引的大小影響索引頁的大小,從而影響磁碟I/O。主鍵分為自然主鍵和人為主鍵。自然主鍵由實體的屬性構成,自然主鍵可以是復合性的,在形成復合主鍵時,主鍵列不能太多,復合主鍵使得Join*作復雜化、也增加了外鍵表的大小。人為主鍵是,在沒有合適的自然屬性鍵、或自然屬性復雜或靈敏度高時,人為形成的。人為主鍵一般是整型值(滿足最小化要求),沒有實際意義,也略微增加了表的大小;但減少了把它作為外鍵的表的大小。
(2)外鍵(Foreign Key):外鍵的作用是建立關系型資料庫中表之間的關系(參照完整性),主鍵只能從獨立的實體遷移到非獨立的實體,成為後者的一個屬性,被稱為外鍵。
(3)索引(Index):利用索引優化系統性能是顯而易見的,對所有常用於查詢中的Where子句的列和所有用於排序的列創建索引,可以避免整表掃描或訪問,在不改變表的物理結構的情況下,直接訪問特定的數據列,這樣減少數據存取時間;利用索引可以優化或排除耗時的分類*作;把數據分散到不同的頁面上,就分散了插入的數據;主鍵自動建立了唯一索引,因此唯一索引也能確保數據的唯一性(即實體完整性);索引碼越小,定位就越直接;新建的索引效能最好,因此定期更新索引非常必要。索引也有代價:有空間開銷,建立它也要花費時間,在進行Insert、Delete和Update*作時,也有維護代價。索引有兩種:聚族索引和非聚族索引。一個表只能有一個聚族索引,可有多個非聚族索引。使用聚族索引查詢數據要比使用非聚族索引快。在建索引前,應利用資料庫系統函數估算索引的大小。
① 聚族索引(Clustered Index):聚族索引的數據頁按物理有序儲存,佔用空間小。選擇策略是,被用於Where子句的列:包括范圍查詢、模糊查詢或高度重復的列(連續磁碟掃描);被用於連接Join*作的列;被用於Order by和Group by子句的列。聚族索引不利於插入*作,另外沒有必要用主鍵建聚族索引。
② 非聚族索引(Nonclustered Index):與聚族索引相比,佔用空間大,而且效率低。選擇策略是,被用於Where子句的列:包括范圍查詢、模糊查詢(在沒有聚族索引時)、主鍵或外鍵列、點(指針類)或小范圍(返回的結果域小於整表數據的20%)查詢;被用於連接Join*作的列、主鍵列(范圍查詢);被用於Order by和Group by子句的列;需要被覆蓋的列。對只讀表建多個非聚族索引有利。索引也有其弊端,一是創建索引要耗費時間,二是索引要佔有大量磁碟空間,三是增加了維護代價(在修改帶索引的數據列時索引會減緩修改速度)。那麼,在哪種情況下不建索引呢?對於小表(數據小於5頁)、小到中表(不直接訪問單行數據或結果集不用排序)、單值域(返回值密集)、索引列值太長(大於20bitys)、容易變化的列、高度重復的列、Null值列,對沒有被用於Where子語句和Join查詢的列都不能建索引。另外,對主要用於數據錄入的,盡可能少建索引。當然,也要防止建立無效索引,當Where語句中多於5個條件時,維護索引的開銷大於索引的效益,這時,建立臨時表存儲有關數據更有效。
批量導入數據時的注意事項:在實際應用中,大批量的計算(如電信話單計費)用C語言程序做,這種基於主外鍵關系數據計算而得的批量數據(文本文件),可利用系統的自身功能函數(如Sybase的BCP命令)快速批量導入,在導入資料庫表時,可先刪除相應庫表的索引,這有利於加快導入速度,減少導入時間。在導入後再重建索引以便優化查詢。
(4)鎖:鎖是並行處理的重要機制,能保持數據並發的一致性,即按事務進行處理;系統利用鎖,保證數據完整性。因此,我們避免不了死鎖,但在設計時可以充分考慮如何避免長事務,減少排它鎖時間,減少在事務中與用戶的交互,杜絕讓用戶控制事務的長短;要避免批量數據同時執行,尤其是耗時並用到相同的數據表。鎖的徵用:一個表同時只能有一個排它鎖,一個用戶用時,其它用戶在等待。若用戶數增加,則Server的性能下降,出現「假死」現象。如何避免死鎖呢?從頁級鎖到行級鎖,減少了鎖徵用;給小表增加無效記錄,從頁級鎖到行級鎖沒有影響,若在同一頁內競爭有影響,可選擇合適的聚族索引把數據分配到不同的頁面;創建冗餘表;保持事務簡短;同一批處理應該沒有網路交互。
(5)查詢優化規則:在訪問資料庫表的數據(Access Data)時,要盡可能避免排序(Sort)、連接(Join)和相關子查詢*作。經驗告訴我們,在優化查詢時,必須做到:
① 盡可能少的行;
② 避免排序或為盡可能少的行排序,若要做大量數據排序,最好將相關數據放在臨時表中*作;用簡單的鍵(列)排序,如整型或短字元串排序;
③ 避免表內的相關子查詢;
④ 避免在Where子句中使用復雜的表達式或非起始的子字元串、用長字元串連接;
⑤ 在Where子句中多使用「與」(And)連接,少使用「或」(Or)連接;
⑥ 利用臨時資料庫。在查詢多表、有多個連接、查詢復雜、數據要過濾時,可以建臨時表(索引)以減少I/O。但缺點是增加了空間開銷。
除非每個列都有索引支持,否則在有連接的查詢時分別找出兩個動態索引,放在工作表中重新排序。
3 基本表擴展設計
基於第三範式設計的庫表雖然有其優越性(見本文第一部分),然而在實際應用中有時不利於系統運行性能的優化:如需要部分數據時而要掃描整表,許多過程同時競爭同一數據,反復用相同行計算相同的結果,過程從多表獲取數據時引發大量的連接*作,當數據來源於多表時的連接*作;這都消耗了磁碟I/O和CPU時間。
尤其在遇到下列情形時,我們要對基本表進行擴展設計:許多過程要頻繁訪問一個表、子集數據訪問、重復計算和冗餘數據,有時用戶要求一些過程優先或低的響應時間。
如何避免這些不利因素呢?根據訪問的頻繁程度對相關表進行分割處理、存儲冗餘數據、存儲衍生列、合並相關表處理,這些都是克服這些不利因素和優化系統運行的有效途徑。
3.1 分割表或儲存冗餘數據
分割表分為水平分割表和垂直分割表兩種。分割表增加了維護數據完整性的代價。
水平分割表:一種是當多個過程頻繁訪問數據表的不同行時,水平分割表,並消除新表中的冗餘數據列;若個別過程要訪問整個數據,則要用連接*作,這也無妨分割表;典型案例是電信話單按月分割存放。另一種是當主要過程要重復訪問部分行時,最好將被重復訪問的這些行單獨形成子集表(冗餘儲存),這在不考慮磁碟空間開銷時顯得十分重要;但在分割表以後,增加了維護難度,要用觸發器立即更新、或存儲過程或應用代碼批量更新,這也會增加額外的磁碟I/O開銷。
垂直分割表(不破壞第三範式),一種是當多個過程頻繁訪問表的不同列時,可將表垂直分成幾個表,減少磁碟I/O(每行的數據列少,每頁存的數據行就多,相應佔用的頁就少),更新時不必考慮鎖,沒有冗餘數據。缺點是要在插入或刪除數據時要考慮數據的完整性,用存儲過程維護。另一種是當主要過程反復訪問部分列時,最好將這部分被頻繁訪問的列數據單獨存為一個子集表(冗餘儲存),這在不考慮磁碟空間開銷時顯得十分重要;但這增加了重疊列的維護難度,要用觸發器立即更新、或存儲過程或應用代碼批量更新,這也會增加額外的磁碟I/O開銷。垂直分割表可以達到最大化利用Cache的目的。
總之,為主要過程分割表的方法適用於:各個過程需要表的不聯結的子集,各個過程需要表的子集,訪問頻率高的主要過程不需要整表。在主要的、頻繁訪問的主表需要表的子集而其它主要頻繁訪問的過程需要整表時則產生冗餘子集表。
注意,在分割表以後,要考慮重新建立索引。
3.2 存儲衍生數據
對一些要做大量重復性計算的過程而言,若重復計算過程得到的結果相同(源列數據穩定,因此計算結果也不變),或計算牽扯多行數據需額外的磁碟I/O開銷,或計算復雜需要大量的CPU時間,就考慮存儲計算結果(冗餘儲存)。現予以分類說明:
若在一行內重復計算,就在表內增加列存儲結果。但若參與計算的列被更新時,必須要用觸發器更新這個新列。
若對表按類進行重復計算,就增加新表(一般而言,存放類和結果兩列就可以了)存儲相關結果。但若參與計算的列被更新時,就必須要用觸發器立即更新、或存儲過程或應用代碼批量更新這個新表。
若對多行進行重復性計算(如排名次),就在表內增加列存儲結果。但若參與計算的列被更新時,必須要用觸發器或存儲過程更新這個新列。
總之,存儲冗餘數據有利於加快訪問速度;但違反了第三範式,這會增加維護數據完整性的代價,必須用觸發器立即更新、或存儲過程或應用代碼批量更新,以維護數據的完整性。
3.3 消除昂貴結合
對於頻繁同時訪問多表的一些主要過程,考慮在主表內存儲冗餘數據,即存儲冗餘列或衍生列(它不依賴於主鍵),但破壞了第三範式,也增加了維護難度。在源表的相關列發生變化時,必須要用觸發器或存儲過程更新這個冗餘列。當主要過程總同時訪問兩個表時可以合並表,這樣可以減少磁碟I/O*作,但破壞了第三範式,也增加了維護難度。對父子表和1:1關系表合並方法不同:合並父子表後,產生冗餘表;合並1:1關系表後,在表內產生冗餘數據。
4 資料庫對象的放置策略
資料庫對象的放置策略是均勻地把數據分布在系統的磁碟中,平衡I/O訪問,避免I/O瓶頸。
⑴ 訪問分散到不同的磁碟,即使用戶數據盡可能跨越多個設備,多個I/O運轉,避免I/O競爭,克服訪問瓶頸;分別放置隨機訪問和連續訪問數據。
⑵ 分離系統資料庫I/O和應用資料庫I/O。把系統審計表和臨時庫表放在不忙的磁碟上。
⑶ 把事務日誌放在單獨的磁碟上,減少磁碟I/O開銷,這還有利於在障礙後恢復,提高了系統的安全性。
⑷ 把頻繁訪問的「活性」表放在不同的磁碟上;把頻繁用的表、頻繁做Join*作的表分別放在單獨的磁碟上,甚至把把頻繁訪問的表的欄位放在不同的磁碟上,把訪問分散到不同的磁碟上,避免I/O爭奪;
⑸ 利用段分離頻繁訪問的表及其索引(非聚族的)、分離文本和圖像數據。段的目的是平衡I/O,避免瓶頸,增加吞吐量,實現並行掃描,提高並發度,最大化磁碟的吞吐量。利用邏輯段功能,分別放置「活性」表及其非聚族索引以平衡I/O。當然最好利用系統的默認段。另外,利用段可以使備份和恢復數據更加靈活,使系統授權更加靈活。
② 資料庫調優的方法有哪些
1.引言 資料庫調優可以使資料庫應用運行得更快,它需要綜合考慮各種復雜的因素。將數據均 勻分布在磁碟上可以提高I/O 利用率,提高數據的讀寫性能;適當程度的非規范化可以改善 系統查詢性能;建立索引和編寫高效的SQL 語句能有效避免低性能操作;通過鎖的調優解 決並發控制方面的性能問題。 資料庫調優技術可以在不同的資料庫系統中使用,它不必糾纏於復雜的公式和規則,然 而它需要對程序的應用、資料庫管理系統、查詢處理、並發控制、操作系統以及硬體有廣泛 而深刻的理解。 2.計算機硬體調優 2.1 資料庫對象的放置策略 利用資料庫分區技術,均勻地把數據分布在系統的磁碟中,平衡I/O 訪問,避免I/O 瓶頸: (1)訪問分散到不同的磁碟,即使用戶數據盡可能跨越多個設備,多個I/O 運轉,避免 I/O 競爭,克服訪問瓶頸;分別放置隨機訪問和連續訪問數據。 (2)分離系統資料庫I/O 和應用資料庫I/O,把系統審計表和臨時庫表放在不忙的磁碟 上。 (3)把事務日誌放在單獨的磁碟上,減少磁碟I/O 開銷,這還有利於在障礙後恢復,提 高了系統的安全性。 (4)把頻繁訪問的「活性」表放在不同的磁碟上;把頻繁用的表、頻繁做Join的表分別 放在單獨的磁碟上,甚至把頻繁訪問的表的欄位放在不同的磁碟上,把訪問分散到不同的磁 盤上,避免I/O 爭奪。 2.2 使用磁碟硬體優化資料庫 RAID (獨立磁碟冗餘陣列)是由多個磁碟驅動器(一個陣列)組成的磁碟系統。通過將磁碟陣列當作一個磁碟來對待,基於硬體的RAID允許用戶管理多個磁碟。使用基於硬體的 RAID與基於操作系統的RAID相比較,基於硬體的RAID能夠提供更佳的性能。如果使用基於操作系統的RAID,那麼它將占據其他系統需求的CPU周期;通過使用基於硬體的RAID, 用戶在不關閉系統的情況下能夠替換發生故障的驅動器。 SQL Server 一般使用RAID等級0、1 和5。 RAID 0 是傳統的磁碟鏡象,陣列中每一個磁碟都有一個或多個磁碟拷貝,它主要用來 提供最高級的可靠性,使RAID 0成倍增加了寫操作卻可以並行處理多個讀操作,從而提高 了讀操作的性能。 RAID 1 是磁碟鏡像或磁碟雙工,能夠為事務日誌保證冗餘性。 RAID 5帶奇偶的磁碟條帶化,即將數據信息和校驗信息分散到陣列的所有磁碟中,它可以消除一個校驗盤的瓶頸和單點失效問題,RAID 5 也會增加寫操作,也可以並行處理一個讀操作,還 可以成倍地提高讀操作的性能。 相比之下,RAID 5 增加的寫操作比RAID 0 增加的要少許多。在實際應用中,用戶的讀操作要求遠遠多於寫操作請求,而磁碟執行寫操作的速度很快,以至於用戶幾乎感覺不到增加的時間,所以增加的寫操作負擔不會帶來什麼問題。在性能較好的伺服器中一般都會選擇使用RAID 5 的磁碟陣列卡來實現,對於性能相對差一些的伺服器也可利用純軟體的方式來實現RAID 5。 3.關系系統與應用程序調優 3.1 應用程序優化 從資料庫設計者的角度來看,應用程序無非是實現對數據的增加、修改、刪除、查詢和體現數據的結構和關系。設計者在性能方面的考慮因素,總的出發點是:把資料庫當作奢侈 的資源看待,在確保功能的同時,盡可能少地動用資料庫資源。包括如下原則: (1)不訪問或少訪問資料庫; (2)簡化對資料庫的訪問; (3)使訪問最優; (4)對前期及後續的開發、部署、調整提出要求,以協助實現性能目標。 另外,不要直接執行完整的SQL 語法,盡量通過存儲過程來調用SQL Server。客戶與伺服器連接時,建立連接池,讓連接盡量得以重用,以避免時間與資源的損耗。非到不得已, 不要使用游標結構,確實使用時,注意各種游標的特性。
③ 怎麼進行mysql資料庫優化
主要從以下角度思考優化方向:1,Mysql配置優化主要對查詢緩存,mysql資料庫連接時長,開啟慢查詢日誌(開啟後還要分析sql)等方面進行優化2. Myslq語句優化3. Mysql索引優化主要是需要注意索引數量和索引失效情況,重復索引4. Mysql引擎優化innodb引擎注重於事務,能保證數據一致性myisam引擎可以進行全文檢索,但不是事務安全當初在黑馬程序員學過,還用實例進行優化學習。
④ 怎麼優化MySQL資料庫
1、選取最適用的欄位屬性,盡可能減少定義欄位長度,盡量把欄位設置NOT NULL,例如'省份,性別',最好設置為ENUM
2、使用連接(JOIN)來代替子查詢:
a.刪除沒有任何訂單客戶:DELETE FROM customerinfo WHERE customerid NOT in(SELECT customerid FROM orderinfo)
b.提取所有沒有訂單客戶:SELECT FROM customerinfo WHERE customerid NOT in(SELECT customerid FROM orderinfo)
c.提高b的速度優化:SELECT FROM customerinfo LEFT JOIN orderid customerinfo.customerid=orderinfo.customerid
WHERE orderinfo.customerid IS NULL
3、使用聯合(UNION)來代替手動創建的臨時表
a.創建臨時表:SELECT name FROM `nametest` UNION SELECT username FROM `nametest2`
4、事務處理:
a.保證數據完整性,例如添加和修改同時,兩者成立則都執行,一者失敗都失敗
mysql_query("BEGIN");
mysql_query("INSERT INTO customerinfo (name) VALUES ('$name1')";
mysql_query("SELECT * FROM `orderinfo` where customerid=".$id");
mysql_query("COMMIT");
5、鎖定表,優化事務處理:
a.我們用一個 SELECT 語句取出初始數據,通過一些計算,用 UPDATE 語句將新值更新到表中。
包含有 WRITE 關鍵字的 LOCK TABLE 語句可以保證在 UNLOCK TABLES 命令被執行之前,
不會有其它的訪問來對 inventory 進行插入、更新或者刪除的操作
mysql_query("LOCK TABLE customerinfo READ, orderinfo WRITE");
mysql_query("SELECT customerid FROM `customerinfo` where id=".$id);
mysql_query("UPDATE `orderinfo` SET ordertitle='$title' where customerid=".$id);
mysql_query("UNLOCK TABLES");
6、使用外鍵,優化鎖定表
a.把customerinfo里的customerid映射到orderinfo里的customerid,
任何一條沒有合法的customerid的記錄不會寫到orderinfo里
CREATE TABLE customerinfo
(
customerid INT NOT NULL,
PRIMARY KEY(customerid)
)TYPE = INNODB;
CREATE TABLE orderinfo
(
orderid INT NOT NULL,
customerid INT NOT NULL,
PRIMARY KEY(customerid,orderid),
FOREIGN KEY (customerid) REFERENCES customerinfo
(customerid) ON DELETE CASCADE
)TYPE = INNODB;
注意:'ON DELETE CASCADE',該參數保證當customerinfo表中的一條記錄刪除的話同時也會刪除order
表中的該用戶的所有記錄,注意使用外鍵要定義事務安全類型為INNODB;
7、建立索引:
a.格式:
(普通索引)->
創建:CREATE INDEX <索引名> ON tablename (索引欄位)
修改:ALTER TABLE tablename ADD INDEX [索引名] (索引欄位)
創表指定索引:CREATE TABLE tablename([...],INDEX[索引名](索引欄位))
(唯一索引)->
創建:CREATE UNIQUE <索引名> ON tablename (索引欄位)
修改:ALTER TABLE tablename ADD UNIQUE [索引名] (索引欄位)
創表指定索引:CREATE TABLE tablename([...],UNIQUE[索引名](索引欄位))
(主鍵)->
它是唯一索引,一般在創建表是建立,格式為:
CREATA TABLE tablename ([...],PRIMARY KEY[索引欄位])
8、優化查詢語句
a.最好在相同欄位進行比較操作,在建立好的索引欄位上盡量減少函數操作
例子1:
SELECT * FROM order WHERE YEAR(orderDate)<2008;(慢)
SELECT * FROM order WHERE orderDate<"2008-01-01";(快)
例子2:
SELECT * FROM order WHERE addtime/7<24;(慢)
SELECT * FROM order WHERE addtime<24*7;(快)
例子3:
SELECT * FROM order WHERE title like "%good%";
SELECT * FROM order WHERE title>="good" and name<"good";
⑤ 資料庫設計過程中,大批量的數據怎麼進行資料庫優化
實例講解MYSQL資料庫的查詢優化技術
作者:佚名 文章來源:未知 點擊數:2538 更新時間:2006-1-19
資料庫系統是管理信息系統的核心,基於資料庫的聯機事務處理(OLTP)以及聯機分析處理(OLAP)是銀行、企業、政府等部門最為重要的計算機應用之一。從大多數系統的應用實例來看,查詢操作在各種資料庫操作中所佔據的比重最大,而查詢操作所基於的SELECT語句在SQL語句中又是代價最大的語句。舉例來說,如果數據的量積累到一定的程度,比如一個銀行的賬戶資料庫表信息積累到上百萬甚至上千萬條記錄,全表掃描一次往往需要數十分鍾,甚至數小時。如果採用比全表掃描更好的查詢策略,往往可以使查詢時間降為幾分鍾,由此可見查詢優化技術的重要性。
筆者在應用項目的實施中發現,許多程序員在利用一些前端資料庫開發工具(如PowerBuilder、Delphi等)開發資料庫應用程序時,只注重用戶界面的華麗,並不重視查詢語句的效率問題,導致所開發出來的應用系統效率低下,資源浪費嚴重。因此,如何設計高效合理的查詢語句就顯得非常重要。本文以應用實例為基礎,結合資料庫理論,介紹查詢優化技術在現實系統中的運用。
分析問題
許多程序員認為查詢優化是DBMS(資料庫管理系統)的任務,與程序員所編寫的SQL語句關系不大,這是錯誤的。一個好的查詢計劃往往可以使程序性能提高數十倍。查詢計劃是用戶所提交的SQL語句的集合,查詢規劃是經過優化處理之後所產生的語句集合。DBMS處理查詢計劃的過程是這樣的:在做完查詢語句的詞法、語法檢查之後,將語句提交給DBMS的查詢優化器,優化器做完代數優化和存取路徑的優化之後,由預編譯模塊對語句進行處理並生成查詢規劃,然後在合適的時間提交給系統處理執行,最後將執行結果返回給用戶。在實際的資料庫產品(如Oracle、Sybase等)的高版本中都是採用基於代價的優化方法,這種優化能根據從系統字典表所得到的信息來估計不同的查詢規劃的代價,然後選擇一個較優的規劃。雖然現在的資料庫產品在查詢優化方面已經做得越來越好,但由用戶提交的SQL語句是系統優化的基礎,很難設想一個原本糟糕的查詢計劃經過系統的優化之後會變得高效,因此用戶所寫語句的優劣至關重要。系統所做查詢優化我們暫不討論,下面重點說明改善用戶查詢計劃的解決方案。
解決問題
下面以關系資料庫系統Informix為例,介紹改善用戶查詢計劃的方法。
1.合理使用索引
索引是資料庫中重要的數據結構,它的根本目的就是為了提高查詢效率。現在大多數的資料庫產品都採用IBM最先提出的ISAM索引結構。索引的使用要恰到好處,其使用原則如下:
●在經常進行連接,但是沒有指定為外鍵的列上建立索引,而不經常連接的欄位則由優化器自動生成索引。
●在頻繁進行排序或分組(即進行group by或order by操作)的列上建立索引。
●在條件表達式中經常用到的不同值較多的列上建立檢索,在不同值少的列上不要建立索引。比如在雇員表的逗性別地列上只有逗男地與逗女地兩個不同值,因此就無必要建立索引。如果建立索引不但不會提高查詢效率,反而會嚴重降低更新速度。
●如果待排序的列有多個,可以在這些列上建立復合索引(compound index)。
●使用系統工具。如Informix資料庫有一個tbcheck工具,可以在可疑的索引上進行檢查。在一些資料庫伺服器上,索引可能失效或者因為頻繁操作而使得讀取效率降低,如果一個使用索引的查詢不明不白地慢下來,可以試著用tbcheck工具檢查索引的完整性,必要時進行修復。另外,當資料庫表更新大量數據後,刪除並重建索引可以提高查詢速度。
2.避免或簡化排序
應當簡化或避免對大型表進行重復的排序。當能夠利用索引自動以適當的次序產生輸出時,優化器就避免了排序的步驟。以下是一些影響因素:
●索引中不包括一個或幾個待排序的列;
●group by或order by子句中列的次序與索引的次序不一樣;
●排序的列來自不同的表。
為了避免不必要的排序,就要正確地增建索引,合理地合並資料庫表(盡管有時可能影響表的規范化,但相對於效率的提高是值得的)。如果排序不可避免,那麼應當試圖簡化它,如縮小排序的列的范圍等。
3.消除對大型錶行數據的順序存取
在嵌套查詢中,對表的順序存取對查詢效率可能產生致命的影響。比如採用順序存取策略,一個嵌套3層的查詢,如果每層都查詢1000行,那麼這個查詢就要查詢10億行數據。避免這種情況的主要方法就是對連接的列進行索引。例如,兩個表:學生表(學號、姓名、年齡……)和選課表(學號、課程號、成績)。如果兩個表要做連接,就要在逗學號地這個連接欄位上建立索引。
還可以使用並集來避免順序存取。盡管在所有的檢查列上都有索引,但某些形式的where子句強迫優化器使用順序存取。下面的查詢將強迫對orders表執行順序操作:
SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
雖然在customer_num和order_num上建有索引,但是在上面的語句中優化器還是使用順序存取路徑掃描整個表。因為這個語句要檢索的是分離的行的集合,所以應該改為如下語句:
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT * FROM orders WHERE order_num=1008
這樣就能利用索引路徑處理查詢。
4.避免相關子查詢
一個列的標簽同時在主查詢和where子句中的查詢中出現,那麼很可能當主查詢中的列值改變之後,子查詢必須重新查詢一次。查詢嵌套層次越多,效率越低,因此應當盡量避免子查詢。如果子查詢不可避免,那麼要在子查詢中過濾掉盡可能多的行。
5.避免困難的正規表達式
MATCHES和LIKE關鍵字支持通配符匹配,技術上叫正規表達式。但這種匹配特別耗費時間。例如:SELECT * FROM customer WHERE zipcode LIKE 逗98_ _ _地
即使在zipcode欄位上建立了索引,在這種情況下也還是採用順序掃描的方式。如果把語句改為SELECT * FROM customer WHERE zipcode >逗98000地,在執行查詢時就會利用索引來查詢,顯然會大大提高速度。
另外,還要避免非開始的子串。例如語句:SELECT * FROM customer WHERE zipcode[2,3]>逗80地,在where子句中採用了非開始子串,因而這個語句也不會使用索引。
6.使用臨時表加速查詢
把表的一個子集進行排序並創建臨時表,有時能加速查詢。它有助於避免多重排序操作,而且在其他方面還能簡化優化器的工作。例如:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.postcode>逗98000地
ORDER BY cust.name
如果這個查詢要被執行多次而不止一次,可以把所有未付款的客戶找出來放在一個臨時文件中,並按客戶的名字進行排序:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY cust.name
INTO TEMP cust_with_balance
然後以下面的方式在臨時表中查詢:
SELECT * FROM cust_with_balance
WHERE postcode>逗98000地
臨時表中的行要比主表中的行少,而且物理順序就是所要求的順序,減少了磁碟I/O,所以查詢工作量可以得到大幅減少。
注意:臨時表創建後不會反映主表的修改。在主表中數據頻繁修改的情況下,注意不要丟失數據。
7.用排序來取代非順序存取
非順序磁碟存取是最慢的操作,表現在磁碟存取臂的來回移動。SQL語句隱藏了這一情況,使得我們在寫應用程序時很容易寫出要求存取大量非順序頁的查詢。
有些時候,用資料庫的排序能力來替代非順序的存取能改進查詢。
實例分析
下面我們舉一個製造公司的例子來說明如何進行查詢優化。製造公司資料庫中包括3個表,模式如下所示:
1.part表
零件號?????零件描述????????其他列
(part_num)?(part_desc)??????(other column)
102,032???Seageat 30G disk?????……
500,049???Novel 10M network card??……
……
2.vendor表
廠商號??????廠商名??????其他列
(vendor _num)?(vendor_name) (other column)
910,257?????Seageat Corp???……
523,045?????IBM Corp?????……
……
3.parven表
零件號?????廠商號?????零件數量
(part_num)?(vendor_num)?(part_amount)
102,032????910,257????3,450,000
234,423????321,001????4,000,000
……
下面的查詢將在這些表上定期運行,並產生關於所有零件數量的報表:
SELECT part_desc,vendor_name,part_amount
FROM part,vendor,parven
WHERE part.part_num=parven.part_num
AND parven.vendor_num = vendor.vendor_num
ORDER BY part.part_num
如果不建立索引,上述查詢代碼的開銷將十分巨大。為此,我們在零件號和廠商號上建立索引。索引的建立避免了在嵌套中反復掃描。關於表與索引的統計信息如下:
表?????行尺寸???行數量?????每頁行數量???數據頁數量
(table)?(row size)?(Row count)?(Rows/Pages)?(Data Pages)
part????150?????10,000????25???????400
Vendor???150?????1,000???? 25???????40
Parven???13????? 15,000????300?????? 50
索引?????鍵尺寸???每頁鍵數量???頁面數量
(Indexes)?(Key Size)?(Keys/Page)???(Leaf Pages)
part?????4??????500???????20
Vendor????4??????500???????2
Parven????8??????250???????60
看起來是個相對簡單的3表連接,但是其查詢開銷是很大的。通過查看系統表可以看到,在part_num上和vendor_num上有簇索引,因此索引是按照物理順序存放的。parven表沒有特定的存放次序。這些表的大小說明從緩沖頁中非順序存取的成功率很小。此語句的優化查詢規劃是:首先從part中順序讀取400頁,然後再對parven表非順序存取1萬次,每次2頁(一個索引頁、一個數據頁),總計2萬個磁碟頁,最後對vendor表非順序存取1.5萬次,合3萬個磁碟頁。可以看出在這個索引好的連接上花費的磁碟存取為5.04萬次。
實際上,我們可以通過使用臨時表分3個步驟來提高查詢效率:
1.從parven表中按vendor_num的次序讀數據:
SELECT part_num,vendor_num,price
FROM parven
ORDER BY vendor_num
INTO temp pv_by_vn
這個語句順序讀parven(50頁),寫一個臨時表(50頁),並排序。假定排序的開銷為200頁,總共是300頁。
2.把臨時表和vendor表連接,把結果輸出到一個臨時表,並按part_num排序:
SELECT pv_by_vn,* vendor.vendor_num
FROM pv_by_vn,vendor
WHERE pv_by_vn.vendor_num=vendor.vendor_num
ORDER BY pv_by_vn.part_num
INTO TMP pvvn_by_pn
DROP TABLE pv_by_vn
這個查詢讀取pv_by_vn(50頁),它通過索引存取vendor表1.5萬次,但由於按vendor_num次序排列,實際上只是通過索引順序地讀vendor表(40+2=42頁),輸出的表每頁約95行,共160頁。寫並存取這些頁引發5*160=800次的讀寫,索引共讀寫892頁。
3.把輸出和part連接得到最後的結果:
SELECT pvvn_by_pn.*,part.part_desc
FROM pvvn_by_pn,part
WHERE pvvn_by_pn.part_num=part.part_num
DROP TABLE pvvn_by_pn
這樣,查詢順序地讀pvvn_by_pn(160頁),通過索引讀part表1.5萬次,由於建有索引,所以實際上進行1772次磁碟讀寫,優化比例為30∶1。筆者在Informix Dynamic
Sever上做同樣的實驗,發現在時間耗費上的優化比例為5∶1(如果增加數據量,比例可能會更大)。
小結
20%的代碼用去了80%的時間,這是程序設計中的一個著名定律,在資料庫應用程序中也同樣如此。我們的優化要抓住關鍵問題,對於資料庫應用程序來說,重點在於SQL的執行效率。查詢優化的重點環節是使得資料庫伺服器少從磁碟中讀數據以及順序讀頁而不是非順序讀頁。
⑥ 資料庫性能優化
設計資料庫的優化措施。這要看你對預期的數據量的一個估計,不同的數據量有不同的策略。100萬數據的表和1億的數據表的策略肯定是不一樣的。同樣的設計,查詢語句不一樣,效果可能也不一樣。
比較常用的資料庫設計方面的處理措施是,
1、索引的建立,一張表,如果有一些經常查詢的欄位上,要建立索引。比如庫存表,你會經常按廠家查詢,那麼在廠家這個欄位上就要建立索引。如樓上所說,在某些時刻,要採取違反第3範式的一些資料庫設計手段。
2、分庫,分表技術。可以按業務層次,或者日期、廠家、地區等欄位,對表進行橫向或縱向的分割。把事務表和數據倉庫表分開等。
3、事實上,對於系統的優化,從資料庫本身的優化,資料庫表的設計,以及應用程序的設計上,關聯是很密切的。比如在資料庫,可以把臨時表,或者一些日誌類的表放在內存檔中。在程序設計上,採用緩存機制,分布式資料庫機制等等,都是提高系統響應能力的方法。
⑦ 大批量的數據應當怎樣進行資料庫的優化
3.消除對大型錶行數據的順序存取 在嵌套查詢中,對表的順序存取對查詢效率可能產生致命的影響。比如採用順序存取策略,一個嵌套3層的查詢,如果每層都查詢1000行,那麼這個查詢就要查詢10億行數據。避免這種情況的主要方法就是對連接的列進行索引。例如,兩個表:學生表(學號、姓名、年齡……)和選課表(學號、課程號、成績)。如果兩個表要做連接,就要在「學號」這個連接欄位上建立索引。 還可以使用並集來避免順序存取。盡管在所有的檢查列上都有索引,但某些形式的where子句強迫優化器使用順序存取。下面的查詢將強迫對orders表執行順序操作: SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008 雖然在customer_num和order_num上建有索引,但是在上面的語句中優化器還是使用順序存取路徑掃描整個表。因為這個語句要檢索的是分離的行的集合,所以應該改為如下語句: SELECT * FROM orders WHERE customer_num=104 AND order_num>1001 UNION SELECT * FROM orders WHERE order_num=1008 這樣就能利用索引路徑處理查詢。 4.避免相關子查詢 一個列的標簽同時在主查詢和where子句中的查詢中出現,那麼很可能當主查詢中的列值改變之後,子查詢必須重新查詢一次。查詢嵌套層次越多,效率越低,因此應當盡量避免子查詢。如果子查詢不可避免,那麼要在子查詢中過濾掉盡可能多的行。 5.避免困難的正規表達式 MATCHES和LIKE關鍵字支持通配符匹配,技術上叫正規表達式。但這種匹配特別耗費時間。例如:SELECT * FROM customer WHERE zipcode LIKE 「98_ _ _」 即使在zipcode欄位上建立了索引,在這種情況下也還是採用順序掃描的方式。如果把語句改為SELECT * FROM customer WHERE zipcode >「98000」,在執行查詢時就會利用索引來查詢,顯然會大大提高速度。 另外,還要避免非開始的子串。例如語句:SELECT * FROM customer WHERE zipcode[2,3]>「80」,在where子句中採用了非開始子串,因而這個語句也不會使用索引。 6.使用臨時表加速查詢 把表的一個子集進行排序並創建臨時表,有時能加速查詢。它有助於避免多重排序操作,而且在其他方面還能簡化優化器的工作。例如: SELECT cust.name,rcvbles.balance,……other columns FROM cust,rcvbles WHERE cust.customer_id = rcvlbes.customer_id AND rcvblls.balance>0 AND cust.postcode>「98000」 ORDER BY cust.name 如果這個查詢要被執行多次而不止一次,可以把所有未付款的客戶找出來放在一個臨時文件中,並按客戶的名字進行排序: SELECT cust.name,rcvbles.balance,……other columns FROM cust,rcvbles WHERE cust.customer_id = rcvlbes.customer_id AND rcvblls.balance>0 ORDER BY cust.name INTO TEMP cust_with_balance 然後以下面的方式在臨時表中查詢: SELECT * FROM cust_with_balance WHERE postcode>「98000」 臨時表中的行要比主表中的行少,而且物理順序就是所要求的順序,減少了磁碟I/O,所以查詢工作量可以得到大幅減少。 注意:臨時表創建後不會反映主表的修改。在主表中數據頻繁修改的情況下,注意不要丟失數據。 7.用排序來取代非順序存取 非順序磁碟存取是最慢的操作,表現在磁碟存取臂的來回移動。SQL語句隱藏了這一情況,使得我們在寫應用程序時很容易寫出要求存取大量非順序頁的查詢。 有些時候,用資料庫的排序能力來替代非順序的存取能改進查詢。 實例分析 下面我們舉一個製造公司的例子來說明如何進行查詢優化。製造公司資料庫中包括3個表,模式如下所示: 1.part表 零件號牐牐牐牐犃慵描述牐牐牐牐牐牐牐犉淥列(part_num)牐╬art_desc)牐牐牐牐牐牐╫ther column) 102,032牐牐燬eageat 30G disk牐牐牐牐…… 500,049牐牐燦ovel 10M network card牐………… 2.vendor表 廠商號牐牐牐牐牐牫商名牐牐牐牐牐犉淥列(vendor _num)牐╲endor_name) (other column) 910,257牐牐牐牐燬eageat Corp牐牐…………
⑧ 請問SQL語句優化的策略都有哪些
● 創建表的時候。應盡量建立主鍵,根據主鍵查詢數據;
● 大數據表刪除,用truncate table代替delete。
● 合理使用索引,在OLTP應用中一張表的索引不要太多。組合索引的列順序盡量與查詢條件列順序保持一致;對於數據操作頻繁的表,索引需要定期重建,以減少失效的索引和碎片。
● 查詢盡量用確定的列名,少用*號。
盡量少嵌套子查詢,這種查詢會消耗大量的CPU資源;對於有比較多
or運算的查詢,建議分成多個查詢,用union all聯結起來;多表查詢
的查詢語句中,選擇最有效率的表名順序(基於規則的優化器中有效)。Oracle解析器對表解析從右到左,所以記錄少的表放在右邊。
● 盡量多用commit語句提交事務,可以及時釋放資源、解
鎖、釋放日誌空間、減少管理花費;在頻繁的、性能要求比較高的
數據操作中,盡量避免遠程訪問,如資料庫鏈等,訪問頻繁的表可以常駐內存:alter table...cache;
⑨ 簡述資料庫性能優化的內容
優化策略一般包括伺服器操作系統參數調整、資料庫參數調整、網路性能調整、應用程序SQL語句分析及設計等幾個方面
⑩ mysql 有哪些常見的優化策略
mysql的優復化大的有兩方面:
1、配置制優化
配置的優化其實包含兩個方面的:操作系統內核的優化和mysql配置文件的優化
1)系統內核的優化對專用的mysql伺服器來說,無非是內存實用、連接數、超時處理、TCP處理等方面的優化,根據自己的硬體配置來進行優化,這里不多講;
2)mysql配置的優化,一般來說包含:IO處理的常用參數、最大連接數設置、緩存使用參數的設置、慢日誌的參數的設置、innodb相關參數的設置等,如果有主從關系在設置主從同步的相關參數即可,網上的相關配置文件很多,大同小異,常用的設置大多修改這些差不多就夠用了。