数据库表设计、 数据库分层、myslq水平拆分、oracle表分区
生活随笔
收集整理的這篇文章主要介紹了
数据库表设计、 数据库分层、myslq水平拆分、oracle表分区
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
數(shù)據(jù)庫表設計
數(shù)據(jù)庫表結構設計方法及原則(li)數(shù)據(jù)庫設計的三大范式:為了建立冗余較小、結構合理的數(shù)據(jù)庫,設計數(shù)據(jù)庫時必須遵循一定的規(guī)則。在關系型數(shù)據(jù)庫中這種規(guī)則就稱為范式。范式是符合某一種設計要求的總結。要想設計一個結構合理的關系型數(shù)據(jù)庫,必須滿足一定的范式。在實際開發(fā)中最為常見的設計范式有三個:第一范式是最基本的范式。如果數(shù)據(jù)庫表中的所有字段值都是不可分解的原子值,就說明該數(shù)據(jù)庫表滿足了第一范式;第二范式在第一范式的基礎之上更進一層。第二范式需要確保數(shù)據(jù)庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯(lián)合主鍵而言)。也就是說在一個數(shù)據(jù)庫表中,一個表中只能保存一種數(shù)據(jù),不可以把多種數(shù)據(jù)保存在同一張數(shù)據(jù)庫表中;第三范式需要確保數(shù)據(jù)表中的每一列數(shù)據(jù)都和主鍵直接相關,而不能間接相關。總結一下,就是:第一范式(確保每列保持原子性);第二范式(確保表中的每列都和主鍵相關);第三范式(確保每列都和主鍵列直接相關,而不是間接相關)。在目前的企業(yè)信息系統(tǒng)中,數(shù)據(jù)庫還是最佳的數(shù)據(jù)存儲方式,雖然已經(jīng)有很多的書籍在指導我們進行數(shù)據(jù)庫設計,但應該那種方式是設計數(shù)據(jù)庫的表結構的最好方法、設計時應遵從什么樣的原則、四個范式如何能夠用一種方式達到順暢的應用等是我一直在思考和總結的問題,下文是我針對這幾個問題根據(jù)自己的設計經(jīng)歷準備總結的一篇文章的提綱,歡迎大家一塊進行探討,集思廣益。其中提到了領域建模的概念,但未作詳細解釋,希望以后能夠有時間我們針對這個命題進行深入探討。1.不應該針對整個系統(tǒng)進行數(shù)據(jù)庫設計,而應該根據(jù)系統(tǒng)架構中的組件劃分,針對每個組件所處理的業(yè)務進行組件單元的數(shù)據(jù)庫設計;不同組件間所對應的數(shù)據(jù)庫表之間的關聯(lián)應盡可能減少,如果不同組件間的表需要外鍵關聯(lián)也盡量不要創(chuàng)建外鍵關聯(lián),而只是記錄關聯(lián)表的一個主鍵,確保組件對應的表之間的獨立性,為系統(tǒng)或表結構的重構提供可能性。//注意他這里說的是"不要創(chuàng)建外鍵關聯(lián)",創(chuàng)建外鍵關聯(lián)的語句是: //foreign key(member_id) references member (id); //我們幾乎沒有用到這條語句,因為我們就是這樣做的,用到外鍵時,只是記錄關聯(lián)表的主鍵,而非在數(shù)據(jù)庫級別上創(chuàng)建外鍵。 //也不知道是歪打正著,還是前輩DBA過于強大,已經(jīng)考慮好了。2.采用領域模型驅(qū)動的方式和自頂向下的思路進行數(shù)據(jù)庫設計,首先分析系統(tǒng)業(yè)務,根據(jù)職責定義對象。對象要符合封裝的特性,確保與職責相關的數(shù)據(jù)項被定義在一個對象之內(nèi),這些數(shù)據(jù)項能夠完整描述該職責,不會出現(xiàn)職責描述缺失。并且一個對象有且只有一項職責,如果一個對象要負責兩個或兩個以上的職責,應進行分拆。// 領域模型驅(qū)動的方式,目前用的還不是很熟,考慮的不夠多。因為經(jīng)常的數(shù)據(jù)庫中的表只是拿來做存儲用而已, //特別是小需求,要加什么字段,找到相關表加上去就行了,不太考慮領域模型。這個在中文站老業(yè)務表里很常見3.根據(jù)建立的領域模型進行數(shù)據(jù)庫表的映射,此時應參考數(shù)據(jù)庫設計第二范式:一個表中的所有非關鍵字屬性都依賴于整個關鍵字。關鍵字可以是一個屬性,也可以是多個屬性的集合,不論那種方式,都應確保關鍵字能夠保證唯一性。在確定關鍵字時,應保證關鍵字不會參與業(yè)務且不會出現(xiàn)更新異常,這時,最優(yōu)解決方案為采用一個自增數(shù)值型屬性或一個隨機字符串作為表的關鍵字。4.由于第一點所述的領域模型驅(qū)動的方式設計數(shù)據(jù)庫表結構,領域模型中的每一個對象只有一項職責,所以對象中的數(shù)據(jù)項不存在傳遞依賴,所以,這種思路的數(shù)據(jù)庫表結構設計從一開始即滿足第三范式:一個表應滿足第二范式,且屬性間不存在傳遞依賴。//數(shù)據(jù)庫三范式記不得的同學去查資料溫習一下。 //個人認為第三范式的目的是盡量減少數(shù)據(jù)冗余,保證相同的數(shù)據(jù)只存在一份。 //第三范式其實我們遵守的并不是很嚴格,特別是老的數(shù)據(jù)庫表中會有冗余字段。這個要看情況決定吧。5.同樣,由于對象職責的單一性以及對象之間的關系反映的是業(yè)務邏輯之間的關系,所以在領域模型中的對象存在主對象和從對象之分,從對象是從1-N或N-N的角度進一步完善主對象的業(yè)務邏輯,所以從對象及對象關系映射為的表及表關聯(lián)關系不存在刪除和插入異常。//最后一句看不懂,可能是"所以表及表關聯(lián)關系不應該出現(xiàn)刪除和插入異常。"?6.在映射后得出的數(shù)據(jù)庫表結構中,應再根據(jù)第四范式進行進一步修改,確保不存在多值依賴。這時,應根據(jù)反向工程的思路反饋給領域模型。如果表結構中存在多值依賴,則證明領域模型中的對象具有至少兩個以上的職責,應根據(jù)第一條進行設計修正。第四范式:一個表如果滿足BCNF,不應存在多值依賴。 復制代碼 //第四范式我們遵守的并不多吧。 //例如: //VAS_WP_CONFIG.config_name字段的值包括:adv(廣告主題)/glare(炫彩滾動主題)/theme_simple(普通主題)/theme_cartoon(動畫主題)/ theme_none(不顯示背景主題) //cate_background(類目背景)/video(公司視頻)/board_cartoon(動畫招牌)/board_simple(普通招牌)等。 //如果遵守第四范式,則需要新增一張VAS_WP_CONFIG_NAME表,存儲配置名稱枚舉值,而VAS_WP_CONFIG.config_name字段改為VAS_WP_CONFIG.config_name_id。 //這樣做更利于擴展,不會因為每個人的理解不一致而向VAS_WP_CONFIG.config_name字段里設置亂七八糟的值,但是這樣需要維護更多的小表,造成數(shù)據(jù)值表的數(shù)量膨脹,DBA可能會覺得管理上有更多的困難。 //我們采用潛規(guī)則約定、java枚舉類等其它方式來進行保證。但有時候效果并不是很好,經(jīng)常發(fā)現(xiàn)舊數(shù)據(jù)庫表中枚舉字段的值五花八門,不全是約定的。 復制代碼7.在經(jīng)過分析后確認所有的表都滿足二、三、四范式的情況下,表和表之間的關聯(lián)盡量采用弱關聯(lián)以便于對表字段和表結構的調(diào)整和重構。并且,我認為數(shù)據(jù)庫中的表是用來持久化一個對象實例在特定時間及特定條件下的狀態(tài)的,只是一個存儲介質(zhì),所以,表和表之間也不應用強關聯(lián)來表述業(yè)務(數(shù)據(jù)間的一致性),這一職責應由系統(tǒng)的邏輯層來保證,這種方式也確保了系統(tǒng)對于不正確數(shù)據(jù)(臟數(shù)據(jù))的兼容性。當然,從整個系統(tǒng)的角度來說我們還是要盡最大努力確保系統(tǒng)不會產(chǎn)生臟數(shù)據(jù),單從另一個角度來說,臟數(shù)據(jù)的產(chǎn)生在一定程度上也是不可避免的,我們也要保證系統(tǒng)對這種情況的容錯性。這是一個折中的方案。8.應針對所有表的主鍵和外鍵建立索引,有針對性的(針對一些大數(shù)據(jù)量和常用檢索方式)建立組合屬性的索引,提高檢索效率。雖然建立索引會消耗部分系統(tǒng)資源,但比較起在檢索時搜索整張表中的數(shù)據(jù)尤其時表中的數(shù)據(jù)量較大時所帶來的性能影響,以及無索引時的排序操作所帶來的性能影響,這種方式仍然是值得提倡的。//索引目前都是DBA根據(jù)具體的SQL來創(chuàng)建的,不過開發(fā)寫SQL時,也應該適當考慮一下字段的索引。9.盡量少采用存儲過程,目前已經(jīng)有很多技術可以替代存儲過程的功能如"對象/關系映射"等,將數(shù)據(jù)一致性的保證放在數(shù)據(jù)庫中,無論對于版本控制、開發(fā)和部署、以及數(shù)據(jù)庫的遷移都會帶來很大的影響。但不可否認,存儲過程具有性能上的優(yōu)勢,所以,當系統(tǒng)可使用的硬件不會得到提升而性能又是非常重要的質(zhì)量屬性時,可經(jīng)過平衡考慮選用存儲過程。//目前都是杜絕使用存儲過程的,我覺得用起來比較方便,對于我們來說,主要原因是會給DBA帶來管理方面的麻煩, //因為時間一長,存儲過程的邏輯和使用場景,往往沒人能了解,容易產(chǎn)生更多問題10.當處理表間的關聯(lián)約束所付出的代價(常常是使用性上的代價)超過了保證不會出現(xiàn)修改、刪除、更改異常所付出的代價,并且數(shù)據(jù)冗余也不是主要的問題時,表設計可以不符合四個范式。四個范式確保了不會出現(xiàn)異常,但也可能由此導致過于純潔的設計,使得表結構難于使用,所以在設計時需要進行綜合判斷,但首先確保符合四個范式,然后再進行精化修正是剛剛進入數(shù)據(jù)庫設計領域時可以采用的最好辦法。11.設計出的表要具有較好的使用性,主要體現(xiàn)在查詢時是否需要關聯(lián)多張表且還需使用復雜的SQL技巧。我感覺遵守的范式越多,就越使SQL復雜,具體情況具體分析。設計出的表要盡可能減少數(shù)據(jù)冗余,確保數(shù)據(jù)的準確性,有效的控制冗余有助于提高數(shù)據(jù)庫的性能因此,考慮了以上條件之后,表設計約定規(guī)則如下:復制代碼 //規(guī)則1:表必須要有主鍵。 //規(guī)則2:一個字段只表示一個含義。 //規(guī)則3:總是包含兩個日期字段:gmt_create(創(chuàng)建日期),gmt_modified(修改日期),且這兩個字段不應該包含有額外的業(yè)務邏輯。 //規(guī)則4:MySQL中,gmt_create、gmt_modified使用DATETIME類型。 //規(guī)則5:禁止使用復雜數(shù)據(jù)類型(數(shù)組,自定義類型等)。 //規(guī)則6: MySQL中,附屬表拆分后,附屬表id與主表id保持一致。不允許在附屬表新增主鍵字段。 //規(guī)則7: MySQL中,存在過期概念的表,在其設計之初就必須有過期機制,且有明確的過期時間。過期數(shù)據(jù)必須遷移至歷史表中。 //規(guī)則8: MySQL中,不再使用的表,必須通知DBA予以更名歸檔。 //規(guī)則9: MySQL中,線上表中若有不再使用的字段,為保證數(shù)據(jù)完整,禁止刪除。 //規(guī)則10: MySQL中,禁止使用OCI驅(qū)動,全部使用THI驅(qū)動。 復制代碼 關于MySQL的部分學習筆記總結:一、事務跟存儲引擎1.四種事務隔離級別:read uncommited, read commited(大多數(shù)db默認的),repeatable read(mysql默認), seriazable。2.mysql是默認的auto commited, 也就是說每次查詢默認都是自動提交的(show variables like 'autocommited')。mysql可以通過set transaction isolatioin level命令來設置隔離級別,例如:set session transaction isolation level read commited。3.mysql中像innodb采用mvcc(多版本并發(fā)控制)來處理并發(fā)。mvcc只工作在read commited,repeatable read這兩種事務隔離級別上。read uncommited隔離級別不兼容mvcc是因為在該級別得下的查詢,不讀取符合當前事務版本的數(shù)據(jù)行,而是最新版本的數(shù)據(jù)行。seriazable隔離級別不兼容MVCC,因為該級別下的讀操作會對每個返回行進行加鎖。4.選擇存儲引擎,并發(fā)選用myisam,事務選擇innodb,myisam比innodb更容易出錯,出錯了恢復的時間也比較長。只有myisam支持全文檢索。5.把表從一種存儲引擎轉(zhuǎn)到另一種引擎:// 1. alter table mytable engine=falcon; 操作費時,可能會占用服務器的所有i/o處理能力。 // 2. create table innodb_table like myisam_table; // alter table innodb_table engine=innodb; // insert into innodb_table select * from myisam_table; 二、數(shù)據(jù)類型1.盡可能的要把field定義為Not NULL, mysql比較難優(yōu)化使用了可空列的查詢,它會使索引,索引統(tǒng)計更加復雜。可空列需要更多的存儲空間,還需要mysql內(nèi)部進行特殊處理,當可空列被索引時,每條記錄都需要一個格外的字節(jié)。 即使要在表中存儲"沒有值"的字段,考慮使用0,特殊字段或者空字符串來代替。2.datetime與timestamp能保存同樣的數(shù)據(jù):精確度為秒,但是timestamp使用的空間只有datetime的一半,還能保存時區(qū),擁有特殊的自動更新能力。但是timestamp保存的時間范圍要比datetime要小得多。mysql能存儲的最細的時間粒度為秒3.mysql支持很多種別名,如bool,integer,nummeric.4.float與double類型支持使用標準的浮點運算進行近似計算。 Decimal類型保存精確的小數(shù),在>=mysql5.0,mysql服務器自身進行了decimal的運算,因為CPU不支持直接對它進行運算,所以慢一點。5.mysql會把text與blob類型的列當成有實體的對象來進行保存。他們有各自的數(shù)據(jù)類型家族(tinytext,smalltext,text,mediumtext,longtext; blob類似); mysql對blob與text列排序方式和其他類型有所不同,它不會按照字符串的完整長度來排序。而只是按照max_sort_length規(guī)定的若干個字節(jié)來進行排序。6.采用enum來代替字符串類型。mysql在內(nèi)部把每個枚舉值都保存為整數(shù)。enum在內(nèi)部是按照數(shù)字進行排序的,而不是按照字符串。enum最不好的就是字符串列表是固定的,添加和刪除必須使用alter table。7.ip地址,一般會采用varchar(15)列來保存。事實上,IP地址是個無符號的32位整數(shù),而不是字符串。mysql提供了inet_aton()和inet_nota()函數(shù)在證書與ip地址之間進行轉(zhuǎn)換。三、索引1.聚集索引不僅僅是一種單獨的索引類型,而且是一種存儲數(shù)據(jù)的方式。Innodb引擎的聚集索引實際上在同樣的結構中保存了B-Tree索引和數(shù)據(jù)行。當表有聚集索引時,它的數(shù)據(jù)行實際上保存在索引的葉子上。注意是存儲引擎來實現(xiàn)索引。2.myisam與innodb數(shù)據(jù)布局:myisam索引樹(無論是主鍵索引還是非主鍵索引)葉子節(jié)點都是指向的數(shù)據(jù)行,而innodb中聚集索引,主鍵索引樹葉子節(jié)點就帶得有數(shù)據(jù)的內(nèi)容,而非主鍵索引樹中葉子節(jié)點指向主鍵值,而不是數(shù)據(jù)的位置。3.mysql有兩種產(chǎn)生排序結果的方式:使用文件排序,或者掃描有序的索引。目前只有myisam支持全文索引。4.myisam表有表級鎖;myisam表不支持事務,實際上,myisam并不保證單條命令完成;myisam只緩存了mysql進程內(nèi)部的索引,并保存在鍵緩存區(qū)內(nèi)。OS緩存了表的數(shù)據(jù);行被緊密的保存在一起,磁盤上的數(shù)據(jù)有很小的磁盤占用和快速的全表掃描。5.innodb支持事務和四種事務隔離級別;在mysql5.0中,只有innodb支持外鍵;支持行級鎖與mvcc;所有的innodb表都是按照主鍵聚集的;所有索引(出開主鍵)都是按主鍵引用行;索引沒有使用前綴壓縮,因此索引可能比myisam大很多;數(shù)據(jù)轉(zhuǎn)載緩慢;阻塞auto_increment,也就是用表級鎖來產(chǎn)生每個auto_increment。四、MYSQL性能分析1.mysql提供了一個benchmark(int 循環(huán)次數(shù),char* 表達式); 可以分析表達式執(zhí)行所花時間。 例如:// select BENCHMARK(10000,SHA1('aaaaaaaaaaaaaaaa'))2.mysql有兩種查詢?nèi)罩?#xff1a;普通日志和慢速日志。五、MYSQL高級特性1.在mysql中,只有myisam存儲引擎支持全文索引。myisam全文索引是一種特殊的具有兩層結構的B樹。2.存儲引擎事務在存儲引擎內(nèi)部被賦予acid屬性,分布式(XA)是一種高層次事務,它可以歷喲內(nèi)部個兩段提交的方式將acid屬性擴展到存儲引擎外部,甚至數(shù)據(jù)庫外部。階段1:通知所有提交者準備提交 階段2:通知所有參與者進行真正提交。3.mysql 的字符集和校對規(guī)則有 4 個級別的默認設置:服務器級、數(shù)據(jù)庫級、表級和字段級。Mysql4.1 開始支持 SQL 的子查詢。復制代碼 /******************************************/ /* 數(shù)據(jù)庫全名 = degopen@10.218.249.92:3318【mysql】 */ /* 表名稱 = task_new */ /******************************************/ CREATE TABLE `task_new` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',`task_name` varchar(128) NOT NULL COMMENT '任務名稱',`image` varchar(128) DEFAULT NULL COMMENT '任務圖標',`description` varchar(1024) NOT NULL COMMENT '任務描述',`content` varchar(1024) NOT NULL COMMENT '任務內(nèi)容',`finished_message` varchar(128) DEFAULT NULL COMMENT '任務完成提示信息',`task_scope` int(11) NOT NULL COMMENT '任務范圍, 0-平臺任務, 1-游戲任務',`series_task` int(11) NOT NULL DEFAULT '0' COMMENT '任務類型: 系列任務,單獨任務',`task_type` int(11) NOT NULL DEFAULT '0' COMMENT '任務類型: 固定任務, 推廣任務, 日常任務',`pre_task` varchar(128) DEFAULT NULL COMMENT '前置任務',`post_task` varchar(128) DEFAULT NULL COMMENT '后置任務',`task_status` int(11) NOT NULL COMMENT '任務狀態(tài), 待審核、未開始、生效中、已暫停、已完成、審核未通過',`auto_task` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否手動任務, 0-否, 1-是',`is_required` tinyint(4) NOT NULL COMMENT '是否必須任務',`event_type` varchar(64) DEFAULT NULL COMMENT '關心的事件類型',`task_target` bigint(20) DEFAULT '0' COMMENT '任務目標',`reset_num` int(11) NOT NULL COMMENT '重置次數(shù)',`reset_cycle` int(11) NOT NULL COMMENT '重置周期',`task_interval` int(11) NOT NULL COMMENT '任務間隔',`xiaoer` bigint(20) unsigned NOT NULL COMMENT '創(chuàng)建人',`review_id` bigint(20) unsigned NOT NULL COMMENT '審核人ID',`last_start_time` datetime DEFAULT NULL COMMENT '上次生效時間',`gmt_create` datetime NOT NULL COMMENT '創(chuàng)建時間',`gmt_modified` datetime NOT NULL COMMENT '修改時間',`start_time` datetime NOT NULL COMMENT '開始時間',`end_time` datetime NOT NULL COMMENT '結束時間',`start_condition` varchar(1024) NOT NULL COMMENT '任務觸發(fā)條件',`end_condition` varchar(1024) NOT NULL COMMENT '任務完成條件',`enable` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否可用',`rule` varchar(4096) NOT NULL COMMENT '任務規(guī)則',`priority` int(11) NOT NULL DEFAULT '1' COMMENT '任務優(yōu)先級',`progress_rule` varchar(2048) NOT NULL DEFAULT '' COMMENT '進度計算規(guī)則',`order_no` int(11) DEFAULT '1' COMMENT '排序號',`classification` int(11) DEFAULT '0' COMMENT '0:默認分類\n1:玩游戲\n2:抽獎',`level` int(11) DEFAULT '0' COMMENT '針對同一個分類,不同的等級',`ext1` longtext COMMENT '擴展字段1(UU中使用該字段指示按鈕跳轉(zhuǎn))',`ext2` longtext COMMENT '擴展字段2,暫時預留',`channel` int(11) DEFAULT '0' COMMENT '任務渠道:0-uu或者1-game_box',`consecutive_day` int(11) DEFAULT '1' COMMENT '連續(xù)完成任務的天數(shù)',`activity` varchar(256) DEFAULT 'default' COMMENT '任務所屬的活動名字',`device` text COMMENT '機型',`packages` text COMMENT '應用',PRIMARY KEY (`id`),KEY `name_channel` (`task_name`,`channel`),KEY `activity` (`activity`(255)) ) ENGINE=InnoDB AUTO_INCREMENT=1194 DEFAULT CHARSET=utf8 COMMENT='任務表'; --------------------------------------------------------------------------------------- 數(shù)據(jù)庫表設計總結 一、實體與表對應關系表<=>實體,字段<=>屬性。二、表與表的關系(實體間的關系):一對一、一對多、多對多一對一:一條記錄只對應其他表中的一條記錄有關系學生基本信息表t_student,成績表t_studentScore含有一個外鍵studentId。基本信息表中的studentId和成績表中的studentId就是一對一的關系。一對多:A表一條記錄對應B表中多條記錄有關系,B表的記錄不被A表記錄共享(有關系)。班級表和學生表,一個班級有多個學生,對班級來說就是一對多的關系。多對多:A表一條記錄和B表多條記錄有關系,B表的一條記錄也和A表的多條記錄有關系(互相共享)。學生表和科目表,學生可以選擇多個科目,每個科目可以被多個學生選擇。三、基本表的完整性(1)原子性。字段是不可再分解的。 (2)原始性。記錄是原始數(shù)據(jù)(基礎數(shù)據(jù))的記錄。 (3)穩(wěn)定性。結構是相對穩(wěn)定的,表中的記錄是要長期保存的。 (4)演繹性。由基本表與代碼表中的數(shù)據(jù),可以派生出所有的輸出數(shù)據(jù)。四、其他常用表1.中間表中間表是針對多對多關系的。就比如做公交查詢系統(tǒng),里面有兩個表,分別是車站表t_busstation、線路表t_road,根據(jù)常識,一個站有多個線路經(jīng)過,而每個線路又有多個車站,怎么才能將兩個表聯(lián)系起來呢,如果是一對一,一對多,我們一個表, 兩個表就可以將他們實現(xiàn)了。但是多對多呢,這樣我們就必須借助中間表用來連接兩個表。一般中間表只有一個自增主鍵+兩個表的主鍵。中間表是沒有屬性的因為它不是一個基本表。2.臨時表臨時表是那些以#號開頭為名字的數(shù)據(jù)表,它主要是用來存放臨時數(shù)據(jù)的,當用戶斷開連接但沒有清除臨時表里的數(shù)據(jù)時,系統(tǒng)會自動把臨時表里的數(shù)據(jù)清空。臨時表是放在系統(tǒng)數(shù)據(jù)庫 tempdb中的,而不是當前數(shù)據(jù)庫。臨時表分兩種:本地臨時表和全局臨時表。a.本地臨時表本地臨時表是以#開頭的,只對當前的數(shù)據(jù)庫用戶可見,而其他的用戶是不可見的。當數(shù)據(jù)庫實例斷開后當然也就丟失了數(shù)據(jù)了,不管是顯式清空還是系統(tǒng)回收。 b.全局臨時表以“##”開頭的,而且是對所有的用戶都是可見,當你斷開數(shù)據(jù)庫實例連接時,只要還有別的系統(tǒng)項目在引用它,連著數(shù)據(jù)庫,那么數(shù)據(jù)就存在,只有當別的系統(tǒng)也全部斷開連接時,系統(tǒng)才會清除全局臨時表的數(shù)據(jù)。建立臨時表的語句:復制代碼本地臨時表:create table #student (studentID int ,studentName nvarchar (40),classID int) 復制代碼 復制代碼全局臨時表:create table ##student (studentID int ,studentName nvarchar (40).classID int) 復制代碼 也可以用SQL語句完成:select * from employee into #student五、三大范式第一范式:如果每列(或者每個屬性)都是不可再分的最小數(shù)據(jù)單元(也稱為最小的原子單元),則滿足第一范式.比如一個工人的基本信息表,里面有工人的工號,性別,年齡,這些屬性都是不可分割的,所以這個表就符合了第一范式。第二范式: 就是在第一范式的基礎上延伸,使之表里的每個字段都與主鍵發(fā)生關系。假如一個關系滿足第一范式,并且除了主鍵以外的其它字段,都依賴于該主鍵,則滿足第二范式. 例如:訂單表(訂單編號、產(chǎn)品編號、定購日期、價格、……),"訂單編號"為主鍵,"產(chǎn)品編號"和主鍵列沒有直接的關系,即"產(chǎn)品編號"列不依賴于主鍵列,這個列我們就可以把它刪除。第三范式:在第二范式的基礎上更進一步,也就是為了實現(xiàn)表里的列都與主鍵列直接相關,不是間接相關。這個我們可以用“Armstrong 公理”中的傳遞規(guī)則來推理。定義: 設U是關系模式R 的屬性集,F 是R 上成立的只涉及U 中屬性的函數(shù)依賴集。若X→Y 和 Y→Z在R 上成立,則X →Z 在R 上成立。因此我們就來看在網(wǎng)上搜索到的例子:例如:訂單表(訂單編號,定購日期,顧客編號,顧客姓名,……),初看該表沒有問題,滿足第二范式,每列都和主鍵列"訂單編號"相關,再細看你會發(fā)現(xiàn)"顧客姓名"和"顧客編號"相關,"顧客編號"和"訂單編號"又相關,最后經(jīng)過傳遞依賴,"顧客姓名"也和"訂單編號"相關。為了滿足第三范式,應去掉"顧客姓名"列,放入客戶表中。這里其實就是為了說明數(shù)據(jù)庫的表里步要出現(xiàn)冗余,在顧客表里已經(jīng)有了"顧客姓名"了,而在訂單表里就別出現(xiàn)了,而直接根據(jù)顧客編號相關聯(lián)就可以,否則造成資源浪費。三大范式延伸:第一范式:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解; 第二范式:2NF是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性; 第三范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余。其實在設計數(shù)據(jù)庫的時候我們最多的要遵循的就是第三范式,但是并不是越滿足第三范式數(shù)據(jù)庫就設計的越完美,這種錯誤是錯誤的。有時候增加點冗余相反的會提高訪問速率,因此在實際的設計過程中應降低對范式的要求。以前對數(shù)據(jù)冗余并不是很了解,在百度知道里的定義是這樣的:在一個數(shù)據(jù)集合中重復的數(shù)據(jù)稱為數(shù)據(jù)冗余. 但是不是說我們表的主鍵在其他表里重復出現(xiàn)就是冗余,這不是,而是為了連接兩個表。只有非鍵字段就是既不是主鍵外鍵等約束的鍵如果重復出現(xiàn),就會形成數(shù)據(jù)冗余。數(shù)據(jù)冗余也包括重復性冗余和派生冗余。比如工人表里有"基本工資","獎金"兩列,然后還有一個"總工資"的列,這個總工資就是派生冗余。低級的重復性冗余一定要避免,杜絕,但是像派生冗余還是提倡的因為它能提高訪問的效率。個人總結:事物的屬性對應表的屬性,將一張表看作一個事物。如,書的屬性有價格、重量、等等。(一般表都有Id來區(qū)分每條記錄) ----------------------------------------------------------------------------數(shù)據(jù)庫分層
數(shù)據(jù)倉庫分層的原因1通過數(shù)據(jù)預處理提高效率,因為預處理,所以會存在冗余數(shù)據(jù)2如果不分層而業(yè)務系統(tǒng)的業(yè)務規(guī)則發(fā)生變化,就會影響整個數(shù)據(jù)清洗過程,工作量巨大3通過分層管理來實現(xiàn)分步完成工作,這樣每一層的處理邏輯就簡單了標準的數(shù)據(jù)倉庫分層:ods(臨時存儲層),pdw(數(shù)據(jù)倉庫層),mid(數(shù)據(jù)集市層),app(應用層)ods:歷史存儲層,它和源系統(tǒng)數(shù)據(jù)是同構的,而且這一層數(shù)據(jù)粒度是最細的,這層的表分為兩種,一種是存儲當前需要加載的數(shù)據(jù),一種是用于存儲處理完后的數(shù)據(jù)。pdw:數(shù)據(jù)倉庫層,它的數(shù)據(jù)是干凈的數(shù)據(jù),是一致的準確的,也就是清洗后的數(shù)據(jù),它的數(shù)據(jù)一般都遵循數(shù)據(jù)庫第三范式,數(shù)據(jù)粒度和ods的粒度相同,它會保存bi系統(tǒng)中所有歷史數(shù)據(jù)mid:數(shù)據(jù)集市層,它是面向主題組織數(shù)據(jù)的,通常是星狀和雪花狀數(shù)據(jù),從數(shù)據(jù)粒度將,它是輕度匯總級別的數(shù)據(jù),已經(jīng)不存在明細的數(shù)據(jù)了,從廣度來說,它包含了所有業(yè)務數(shù)量。從分析角度講,大概就是近幾年app:應用層,數(shù)據(jù)粒度高度匯總,倒不一定涵蓋所有業(yè)務數(shù)據(jù),只是mid層數(shù)據(jù)的一個子集。數(shù)據(jù)倉庫的目的是構建面向分析的集成化數(shù)據(jù)環(huán)境,為企業(yè)提供決策支持。數(shù)據(jù)倉庫的context也可以理解為:數(shù)據(jù)源,數(shù)據(jù)倉庫,數(shù)據(jù)應用數(shù)據(jù)倉庫可以理解為中間集成化數(shù)據(jù)管理的一個平臺etl(抽取extra,轉(zhuǎn)化transfer,裝載load)是數(shù)據(jù)倉庫的流水線,也可以認為是數(shù)據(jù)倉庫的血液。數(shù)據(jù)倉庫的存儲并不需要存儲所有原始數(shù)據(jù),因為比如你存儲冗長的文本數(shù)據(jù)完全沒必要,但需要存儲細節(jié)數(shù)據(jù),因為需求是多變的,而且數(shù)據(jù)倉庫是導入數(shù)據(jù)必須經(jīng)過整理和轉(zhuǎn)換使它面向主題,因為前臺數(shù)據(jù)庫的數(shù)據(jù)是基于oltp操作組織優(yōu)化的,這些可能不適合做分析,面向主題的組織形式才有利于分析。多維數(shù)據(jù)模型就是說可以多維度交叉查詢和細分,應用一般都是基于聯(lián)機分析處理(online analytical process OLAP),面向特定需求群體的數(shù)據(jù)集市會基于多位數(shù)據(jù)模型構建而報表展示就是將聚合數(shù)據(jù)和多維分析數(shù)據(jù)展示到報表,提供簡單和直觀的數(shù)據(jù)。元數(shù)據(jù),也叫解釋性數(shù)據(jù),或者數(shù)據(jù)字典,會記錄數(shù)據(jù)倉庫中模型的定義,各層級之間的映射關系,監(jiān)控數(shù)據(jù)倉庫的數(shù)據(jù)狀態(tài)和etl的任務運行狀態(tài)。一般通過元數(shù)據(jù)資料庫來統(tǒng)一存儲和管理元數(shù)據(jù)。------------------------------------------------------------------------------ -基本查詢 select id,c_mmcode,c_mmroomname,c_parentId from s_mmroom; --層次化查詢 select id,c_mmcode,c_mmroomname,c_parentId from s_mmroom start with c_parentId='0' connect by prior id = c_parentId; --使用level節(jié)點 select level,id,c_mmcode,c_mmroomname,c_parentId from s_mmroom start with c_parentId='0' connect by prior id = c_parentId; --查詢層次數(shù) select count(distinct level) from s_mmroom start with c_parentId='0' connect by prior id = c_parentId; ---查詢結果的層次化 select level,LPAD(' ',2*LEVEL-1)||' '||c_mmcode||' '||c_mmroomname,c_parentId from s_mmroom start with c_parentId='0' connect by prior id = c_parentId; --從非根節(jié)點開始遍歷 select level,LPAD(' ',2*LEVEL-1)||' '||c_mmcode||' '||c_mmroomname,c_parentId from s_mmroom start with c_parentId='00000000000000000000000000000000' connect by prior id = c_parentId; --在START WITH中使用子查詢? 下面這個查詢使用子查詢來選擇指定節(jié)點的。然后傳給START WITH子句。 select level,lpad(' ',2*level-1)||' '||c_mmroomname from s_mmroom start with c_parentId=(select id from s_mmroom where c_mmroomname like '%中國船級社%') connect by prior id =c_parentId; --從下向上遍歷樹? 不一定非要按照從父節(jié)點到子節(jié)點的順序從上至下遍歷樹;也可以從某個子節(jié)點開始,從下而上遍歷。實現(xiàn)的方法是交換父節(jié)點和子節(jié)點在CONNECT BY PRIOR子句中的順序 select level,lpad(' ',2*level-1)||' '||c_mmroomname from s_mmroom start with c_parentId='00000000000000000000000000000000' connect by prior id = c_parentId; --從層次化查詢中刪除節(jié)點和分支?? 略 表名后面加where --在層次化查詢中加入其它條件????? 略 表名后面加where ------------------------------------------------------------------ BLOCK(塊)block 是oracle中最小的分配單位,也是最小的I/O單位,可以在創(chuàng)建數(shù)據(jù)庫時設定block的大小,可以設為任意的大小,但為了支持與兼容方面,建議現(xiàn)實中設為2的冪,例如:2KB、4KB、8KB,最大為32KB。EXTENT(區(qū))extent 是由邏輯連續(xù)的block組成的,注意是邏輯上的,一般來講,文件本身在磁盤上不是連續(xù)的,extent的大小可能是一個block的大小,也可能大到2GB,SEGMENT(段)segment 是由一個或多個extent組成的,segment就是占用存儲空間的數(shù)據(jù)庫對象,例如表、索引等,segment在tablespace中,但可以包含這個tablespace中的多個數(shù)據(jù)文件中的數(shù)據(jù)TABLESPACE(表空間)ORACLE數(shù)據(jù)庫是由一個或多個TABLESPACE構成,什么是TABLESPACE? 一種邏輯上的存儲容器,包括一個或多個datafile(數(shù)據(jù)文件)。tablespace可以包含多個segment(表段,索引段等),但一個segment只能屬于一個tablespace。上圖中圓柱形代表datafile(user_data01.db和user_data02.dbf),T1,T2,I1是3個segment(可能是2個表和1個索引),這個USER_DATA ?TABLESPACE分配了4個extent,T1和I1各有一個extent。如果這個TABLESPACE需要更多的空間,可以調(diào)整已分配給該TABLESPACE的datafile的大小,也可以增加第三個datafile。要說明的是上述所討論的概念除了block都是邏輯上的概念,所謂連續(xù)的也是邏輯上連續(xù)的。 -------------------------------------------------------------------------------myslq水平拆分
mysql的水平拆分和垂直拆分 1,水平分割:例:QQ的登錄表。假設QQ的用戶有100億,如果只有一張表,每個用戶登錄的時候數(shù)據(jù)庫都要從這100億中查找,會很慢很慢。如果將這一張表分成100份,每張表有1億條,就小了很多,比如qq0,qq1,qq1...qq99表。用戶登錄的時候,可以將用戶的id%100,那么會得到0-99的數(shù),查詢表的時候,將表名qq跟取模的數(shù)連接起來,就構建了表名。比如123456789用戶,取模的89,那么就到qq89表查詢,查詢的時間將會大大縮短。這就是水平分割。2,垂直分割:垂直分割指的是:表的記錄并不多,但是字段卻很長,表占用空間很大,檢索表的時候需要執(zhí)行大量的IO,嚴重降低了性能。這時需要把大的字段拆分到另一個表,并且該表與原表是一對一的關系。例如學生答題表tt:有如下字段:Id name 分數(shù) 題目 回答其中題目和回答是比較大的字段,id name 分數(shù)比較小。如果我們只想查詢id為8的學生的分數(shù):select 分數(shù) from tt where id = 8;雖然知識查詢分數(shù),但是題目和回答這兩個大字段也是要被掃描的,很消耗性能。但是我們只關心分數(shù),并不想查詢題目和回答。這就可以使用垂直分割。我們可以把題目單獨放到一張表中,通過id與tt表建立一對一的關系,同樣將回答單獨放到一張表中。這樣我們插敘tt中的分數(shù)的時候就不會掃描題目和回答了。3,其他要點:1)存放圖片、文件等大文件用文件系統(tǒng)存儲。數(shù)據(jù)庫只存儲路徑,圖片和文件存放在文件系統(tǒng),甚至單獨存放在一臺服務器(圖床)。2)數(shù)據(jù)參數(shù)配置。最重要的參數(shù)就是內(nèi)存,我們主要用的innodb引擎,所以下面兩個參數(shù)調(diào)的很大:innodb_additional_mem_pool_size=64Minnodb_buffer_pool_size=1G對于MyISAM,需要調(diào)整key_buffer_size,當然調(diào)整參數(shù)還是要看狀態(tài),用show status語句可以看到當前狀態(tài),以決定該調(diào)整哪些參數(shù)。4,合理的硬件資源和操作系統(tǒng)如果機器的內(nèi)存超過4G,那么應當采用64位操作系統(tǒng)和64位MySQL。案例:簡單購物系統(tǒng)暫設涉及如下表:1.產(chǎn)品表(數(shù)據(jù)量10w,穩(wěn)定)2.訂單表(數(shù)據(jù)量200w,且有增長趨勢)3.用戶表 (數(shù)據(jù)量100w,且有增長趨勢)以mysql為例講述下水平拆分和垂直拆分,mysql能容忍的數(shù)量級在百萬靜態(tài)數(shù)據(jù)可以到千萬垂直拆分:解決問題:表與表之間的io競爭不解決問題:單表中數(shù)據(jù)量增長出現(xiàn)的壓力方案:把產(chǎn)品表和用戶表放到一個server上訂單表單獨放到一個server上水平拆分:解決問題:單表中數(shù)據(jù)量增長出現(xiàn)的壓力不解決問題:表與表之間的io爭奪方案:用戶表通過性別拆分為男用戶表和女用戶表訂單表通過已完成和完成中拆分為已完成訂單和未完成訂單產(chǎn)品表 未完成訂單放一個server上已完成訂單表盒男用戶表放一個server上女用戶表放一個server上 ----------------------------------------------------------------------------- 目前很多互聯(lián)網(wǎng)系統(tǒng)都存在單表數(shù)據(jù)量過大的問題,這就降低了查詢速度,影響了客戶體驗。為了提高查詢速度,我們可以優(yōu)化sql語句,優(yōu)化表結構和索引,不過對那些百萬級千萬級的數(shù)據(jù)庫表,即便是優(yōu)化過后,查詢速度還是滿足不了要求。這時候我們就可以通過分表降低單次查詢數(shù)據(jù)量,從而提高查詢速度,一般分表的方式有兩種:水平拆分和垂直拆分,兩者各有利弊,適用于不同的情況。水平拆分 水平拆分是指數(shù)據(jù)表行的拆分,表的行數(shù)超過200萬行時,就會變慢,這時可以把一張的表的數(shù)據(jù)拆成多張表來存放。 這里寫圖片描述 這里寫圖片描述 通常情況下,我們使用取模的方式來進行表的拆分;比如一張有400W的用戶表users,為提高其查詢效率我們把其分成4張表users1,users2,users3,users4 通過用ID取模的方法把數(shù)據(jù)分散到四張表內(nèi)Id%4+1 = [1,2,3,4] 然后查詢,更新,刪除也是通過取模的方法來查詢。例:QQ的登錄表。假設QQ的用戶有100億,如果只有一張表,每個用戶登錄的時候數(shù)據(jù)庫都要從這100億中查找,會很慢很慢。如果將這一張表分成100份,每張表有1億條,就小了很多,比如qq0,qq1,qq1…qq99表。用戶登錄的時候,可以將用戶的id%100,那么會得到0-99的數(shù),查詢表的時候,將表名qq跟取模的數(shù)連接起來,就構建了表名。比如123456789用戶,取模的89,那么就到qq89表查詢,查詢的時間將會大大縮短。另外部分業(yè)務邏輯也可以通過地區(qū),年份等字段來進行歸檔拆分;進行拆分后的表,只能滿足部分查詢的高效查詢需求,這時我們就要在產(chǎn)品策劃上,從界面上約束用戶查詢行為。比如我們是按年來進行歸檔拆分的,這個時候在頁面設計上就約束用戶必須要先選擇年,然后才能進行查詢;在做分析或者統(tǒng)計時,由于是自己人的需求,多點等待其實是沒關系的,并且并發(fā)很低,這個時候可以用union把所有表都組合成一張視圖來進行查詢,然后再進行查詢。水平拆分的優(yōu)點: ◆表關聯(lián)基本能夠在數(shù)據(jù)庫端全部完成; ◆不會存在某些超大型數(shù)據(jù)量和高負載的表遇到瓶頸的問題; ◆應用程序端整體架構改動相對較少; ◆事務處理相對簡單; ◆只要切分規(guī)則能夠定義好,基本上較難遇到擴展性限制;水平切分的缺點: ◆切分規(guī)則相對更為復雜,很難抽象出一個能夠滿足整個數(shù)據(jù)庫的切分規(guī)則; ◆后期數(shù)據(jù)的維護難度有所增加,人為手工定位數(shù)據(jù)更困難; ◆應用系統(tǒng)各模塊耦合度較高,可能會對后面數(shù)據(jù)的遷移拆分造成一定的困難。垂直拆分 垂直拆分是指數(shù)據(jù)表列的拆分,把一張列比較多的表拆分為多張表。表的記錄并不多,但是字段卻很長,表占用空間很大,檢索表的時候需要執(zhí)行大量的IO,嚴重降低了性能。這時需要把大的字段拆分到另一個表,并且該表與原表是一對一的關系。 這里寫圖片描述 這里寫圖片描述通常我們按以下原則進行垂直拆分: 1,把不常用的字段單獨放在一張表;, 2,把text,blob等大字段拆分出來放在附表中; 3,經(jīng)常組合查詢的列放在一張表中;例如學生答題表tt:有如下字段: Id name 分數(shù) 題目 回答 其中題目和回答是比較大的字段,id name 分數(shù)比較小。如果我們只想查詢id為8的學生的分數(shù):select 分數(shù) from tt where id = 8;雖然知識查詢分數(shù),但是題目和回答這兩個大字段也是要被掃描的,很消耗性能。但是我們只關心分數(shù),并不想查詢題目和回答。這就可以使用垂直分割。我們可以把題目單獨放到一張表中,通過id與tt表建立一對一的關系,同樣將回答單獨放到一張表中。這樣我們插敘tt中的分數(shù)的時候就不會掃描題目和回答了。垂直切分的優(yōu)點 ◆ 數(shù)據(jù)庫的拆分簡單明了,拆分規(guī)則明確; ◆ 應用程序模塊清晰明確,整合容易; ◆ 數(shù)據(jù)維護方便易行,容易定位;垂直切分的缺點 ◆ 部分表關聯(lián)無法在數(shù)據(jù)庫級別完成,需要在程序中完成; ◆ 對于訪問極其頻繁且數(shù)據(jù)量超大的表仍然存在性能平靜,不一定能滿足要求; ◆ 事務處理相對更為復雜; ◆ 切分達到一定程度之后,擴展性會遇到限制; ◆ 過讀切分可能會帶來系統(tǒng)過渡復雜而難以維護。 ----------------------------------------------------------------------- 數(shù)據(jù)庫垂直拆分 水平拆分當我們使用讀寫分離、緩存后,數(shù)據(jù)庫的壓力還是很大的時候,這就需要使用到數(shù)據(jù)庫拆分了。數(shù)據(jù)庫拆分簡單來說,就是指通過某種特定的條件,按照某個維度,將我們存放在同一個數(shù)據(jù)庫中的數(shù)據(jù)分散存放到多個數(shù)據(jù)庫(主機)上面以達到分散單庫(主機)負載的效果。 切分模式: 垂直(縱向)拆分、水平拆分。垂直拆分專庫專用一個數(shù)據(jù)庫由很多表的構成,每個表對應著不同的業(yè)務,垂直切分是指按照業(yè)務將表進行分類,分布到不同的數(shù)據(jù)庫上面,這樣也就將數(shù)據(jù)或者說壓力分擔到不同的庫上面,如下圖:優(yōu)點:1. 拆分后業(yè)務清晰,拆分規(guī)則明確。2. 系統(tǒng)之間整合或擴展容易。3. 數(shù)據(jù)維護簡單。缺點:1. 部分業(yè)務表無法join,只能通過接口方式解決,提高了系統(tǒng)復雜度。2. 受每種業(yè)務不同的限制存在單庫性能瓶頸,不易數(shù)據(jù)擴展跟性能提高。3. 事務處理復雜。水平拆分垂直拆分后遇到單機瓶頸,可以使用水平拆分。相對于垂直拆分的區(qū)別是:垂直拆分是把不同的表拆到不同的數(shù)據(jù)庫中,而水平拆分是把同一個表拆到不同的數(shù)據(jù)庫中。相對于垂直拆分,水平拆分不是將表的數(shù)據(jù)做分類,而是按照某個字段的某種規(guī)則來分散到多個庫之中,每個表中包含一部分數(shù)據(jù)。簡單來說,我們可以將數(shù)據(jù)的水平切分理解為是按照數(shù)據(jù)行的切分,就是將表中 的某些行切分到一個數(shù)據(jù)庫,而另外的某些行又切分到其他的數(shù)據(jù)庫中,主要有分表,分庫兩種模式,如圖:優(yōu)點:1. 不存在單庫大數(shù)據(jù),高并發(fā)的性能瓶頸。2. 對應用透明,應用端改造較少。 3. 按照合理拆分規(guī)則拆分,join操作基本避免跨庫。4. 提高了系統(tǒng)的穩(wěn)定性跟負載能力。缺點:1. 拆分規(guī)則難以抽象。2. 分片事務一致性難以解決。3. 數(shù)據(jù)多次擴展難度跟維護量極大。4. 跨庫join性能較差。拆分的處理難點兩張方式共同缺點1. 引入分布式事務的問題。2. 跨節(jié)點Join 的問題。3. 跨節(jié)點合并排序分頁問題。針對數(shù)據(jù)源管理,目前主要有兩種思路:A. 客戶端模式,在每個應用程序模塊中配置管理自己需要的一個(或者多個)數(shù)據(jù)源,直接訪問各個 數(shù)據(jù)庫,在模塊內(nèi)完成數(shù)據(jù)的整合。 優(yōu)點:相對簡單,無性能損耗。 缺點:不夠通用,數(shù)據(jù)庫連接的處理復雜,對業(yè)務不夠透明,處理復雜。B. 通過中間代理層來統(tǒng)一管理所有的數(shù)據(jù)源,后端數(shù)據(jù)庫集群對前端應用程序透明; 優(yōu)點:通用,對應用透明,改造少。 缺點:實現(xiàn)難度大,有二次轉(zhuǎn)發(fā)性能損失。拆分原則1. 盡量不拆分,架構是進化而來,不是一蹴而就。(SOA)2. 最大可能的找到最合適的切分維度。3. 由于數(shù)據(jù)庫中間件對數(shù)據(jù)Join 實現(xiàn)的優(yōu)劣難以把握,而且實現(xiàn)高性能難度極大,業(yè)務讀取 盡量少使用多表Join -盡量通過數(shù)據(jù)冗余,分組避免數(shù)據(jù)垮庫多表join。4. 盡量避免分布式事務。5. 單表拆分到數(shù)據(jù)1000萬以內(nèi)。切分方案范圍、枚舉、時間、取模、哈希、指定等案例分析場景一 建立一個歷史his系統(tǒng),將公司的一些歷史個人游戲數(shù)據(jù)保存到這個his系統(tǒng)中,主要是寫入,還有部分查詢,讀寫比約為1:4;由于是所有數(shù)據(jù)的歷史存取,所以并發(fā)要求比較高; 分析: 歷史數(shù)據(jù) 寫多都少 越近日期查詢越頻繁? 什么業(yè)務數(shù)據(jù)?用戶游戲數(shù)據(jù) 有沒有大規(guī)模分析查詢? 數(shù)據(jù)量多大? 保留多久? 機器資源有多少?方案1:按照日期每月一個分片 帶來的問題:1.數(shù)據(jù)熱點問題(壓力不均勻)方案2:按照用戶取模, --by Jerome 就這個比較合適了 帶來的問題:后續(xù)擴容困難方案3:按用戶ID范圍分片(1-1000萬=分片1,xxx) 帶來的問題:用戶活躍度無法掌握,可能存在熱點問題場景二 建立一個商城訂單系統(tǒng),保存用戶訂單信息。分析: 電商系統(tǒng) 一號店或京東類?淘寶或天貓? 實時性要求高 存在瞬時壓力 基本不存在大規(guī)模分析 數(shù)據(jù)規(guī)模? 機器資源有多少? 維度?商品?用戶?商戶?方案1:按照用戶取模, 帶來的問題:后續(xù)擴容困難方案2:按用戶ID范圍分片(1-1000萬=分片1,xxx) 帶來的問題:用戶活躍度無法掌握,可能存在熱點問題方案3:按省份地區(qū)或者商戶取模 數(shù)據(jù)分配不一定均勻場景3 上海公積金,養(yǎng)老金,社保系統(tǒng)分析: 社保系統(tǒng) 實時性要求不高 不存在瞬時壓力 大規(guī)模分析? 數(shù)據(jù)規(guī)模大 數(shù)據(jù)重要不可丟失 偏于查詢?方案1:按照用戶取模, 帶來的問題:后續(xù)擴容困難方案2:按用戶ID范圍分片(1-1000萬=分片1,xxx) 帶來的問題:用戶活躍度無法掌握,可能存在熱點問題方案3:按省份區(qū)縣地區(qū)枚舉 數(shù)據(jù)分配不一定均勻數(shù)據(jù)庫問題解決后,應用面對的新挑戰(zhàn)就是拆分應用等參考Mycat在線視頻培訓【鏈接:http://pan.baidu.com/s/1nuR26rZ 密碼:1gr9 (2015)】大型網(wǎng)站系統(tǒng)與Java中間件實踐.pdfMySQL數(shù)據(jù)庫的演化可以參考:http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=207666963&idx=2&sn=0d0710e071420c6fc6af8d4a3bc3dfe6&scene=1#rdhttp://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651959773&idx=1&sn=7e4ad0dcd050f6662dfaf39d9de36f2c&chksm=bd2d04018a5a8d17b92098b4840aac23982e32d179cdd957e4c55011f6a08f6bd31f9ba5cfee&mpshare=1&scene=23&srcid=1220t4ttl8wZaYHlQRzO0xYB#rd【一分鐘掌握數(shù)據(jù)庫垂直拆分-沈劍】垂直拆分垂直拆分就是要把表按模塊劃分到不同數(shù)據(jù)庫表中(當然原則還是不破壞第三范式),這種拆分在大型網(wǎng)站的演變過程中是很常見的。當一個網(wǎng)站還在很小的時候,只有小量的人來開發(fā)和維護,各模塊和表都在一起,當網(wǎng)站不斷豐富和壯大的時候,也會變成多個子系統(tǒng)來支撐,這時就有按模塊和功能把表劃分出來的需求。其實,相對于垂直切分更進一步的是服務化改造,說得簡單就是要把原來強耦合的系統(tǒng)拆分成多個弱耦合的服務,通過服務間的調(diào)用來滿足業(yè)務需求看,因此表拆出來后要通過服務的形式暴露出去,而不是直接調(diào)用不同模塊的表,淘寶在架構不斷演變過程,最重要的一環(huán)就是服務化改造,把用戶、交易、店鋪、寶貝這些核心的概念抽取成獨立的服務,也非常有利于進行局部的優(yōu)化和治理,保障核心模塊的穩(wěn)定性垂直拆分:單表大數(shù)據(jù)量依然存在性能瓶頸水平拆分上面談到垂直切分只是把表按模塊劃分到不同數(shù)據(jù)庫,但沒有解決單表大數(shù)據(jù)量的問題,而水平切分就是要把一個表按照某種規(guī)則把數(shù)據(jù)劃分到不同表或數(shù)據(jù)庫里。例如像計費系統(tǒng),通過按時間來劃分表就比較合適,因為系統(tǒng)都是處理某一時間段的數(shù)據(jù)。而像SaaS應用,通過按用戶維度來劃分數(shù)據(jù)比較合適,因為用戶與用戶之間的隔離的,一般不存在處理多個用戶數(shù)據(jù)的情況,簡單的按user_id范圍來水平切分通俗理解:水平拆分行,行數(shù)據(jù)拆分到不同表中, 垂直拆分列,表數(shù)據(jù)拆分到不同表中垂直與水平聯(lián)合切分由上面可知垂直切分能更清晰化模塊劃分,區(qū)分治理,水平切分能解決大數(shù)據(jù)量性能瓶頸問題,因此常常就會把兩者結合使用,這在大型網(wǎng)站里是種常見的策略案例:以mysql為例,簡單購物系統(tǒng)暫設涉及如下表:1.產(chǎn)品表(數(shù)據(jù)量10w,穩(wěn)定)2.訂單表(數(shù)據(jù)量200w,且有增長趨勢)3.用戶表 (數(shù)據(jù)量100w,且有增長趨勢)以mysql為例講述下水平拆分和垂直拆分,mysql能容忍的數(shù)量級在百萬靜態(tài)數(shù)據(jù)可以到千萬垂直拆分:解決問題:表與表之間的io競爭不解決問題:單表中數(shù)據(jù)量增長出現(xiàn)的壓力方案:把產(chǎn)品表和用戶表放到一個server上訂單表單獨放到一個server上水平拆分:解決問題:單表中數(shù)據(jù)量增長出現(xiàn)的壓力不解決問題:表與表之間的io爭奪方案:用戶表通過性別拆分為男用戶表和女用戶表訂單表通過已完成和完成中拆分為已完成訂單和未完成訂單產(chǎn)品表 未完成訂單放一個server上已完成訂單表盒男用戶表放一個server上女用戶表放一個server上(女的愛購物)《大型網(wǎng)站系統(tǒng)與Java中間件實踐》本書圍繞大型網(wǎng)站和支撐大型網(wǎng)站架構的 Java 中間件的實踐展開介紹。從分布式系統(tǒng)的知識切入,讓讀者對分布式系統(tǒng)有基本的了解;然后介紹大型網(wǎng)站隨著數(shù)據(jù)量、訪問量增長而發(fā)生的架構變遷;接著講述構建 Java 中間件的相關知識;之后的幾章都是根據(jù)筆者的經(jīng)驗來介紹支撐大型網(wǎng)站架構的 Java 中間件系統(tǒng)的設計和實踐。本節(jié)為大家介紹專庫專用,數(shù)據(jù)垂直拆分。AD: 51CTO 網(wǎng)+ 第十二期沙龍:大話數(shù)據(jù)之美_如何用數(shù)據(jù)驅(qū)動用戶體驗2.2.7 讀寫分離后,數(shù)據(jù)庫又遇到瓶頸通過讀寫分離以及在某些場景用分布式存儲系統(tǒng)替換關系型數(shù)據(jù)庫的方式,能夠降低主庫的壓力,解決數(shù)據(jù)存儲方面的問題。不過隨著業(yè)務的發(fā)展,我們的主庫也會遇到瓶頸。我們的網(wǎng)站演進到現(xiàn)在,交易、商品、用戶的數(shù)據(jù)還都在一個數(shù)據(jù)庫中。盡管采取了增加緩存、讀寫分離的方式,這個數(shù)據(jù)庫的壓力還是在繼續(xù)增加,因此我們需要去解決這個問題,我們有數(shù)據(jù)垂直拆分和水平拆分兩種選擇。2.2.7.1 專庫專用,數(shù)據(jù)垂直拆分垂直拆分的意思是把數(shù)據(jù)庫中不同的業(yè)務數(shù)據(jù)拆分到不同的數(shù)據(jù)庫中。結合現(xiàn)在的例子,就是把交易、商品、用戶的數(shù)據(jù)分開,如圖2-20 所示。這樣的變化給我們帶來的影響是什么呢?應用需要配置多個數(shù)據(jù)源,這就增加了所需的配置,不過帶來的是每個數(shù)據(jù)庫連接池的隔離。不同業(yè)務的數(shù)據(jù)從原來的一個數(shù)據(jù)庫中拆分到了多個數(shù)據(jù)庫中,那么就需要考慮如何處理原來單機中跨業(yè)務的事務。一種辦法是使用分布式事務,其性能要明顯低于之前的單機事務;而另一種辦法就是去掉事務或者不去追求強事務支持,則原來在單庫中可以使用的表關聯(lián)的查詢也就需要改變實現(xiàn)了。對數(shù)據(jù)進行垂直拆分之后,解決了把所有業(yè)務數(shù)據(jù)放在一個數(shù)據(jù)庫中的壓力問題。并且也可以根據(jù)不同業(yè)務的特點進行更多優(yōu)化。2.2.7.2 垂直拆分后的單機遇到瓶頸,數(shù)據(jù)水平拆分與數(shù)據(jù)垂直拆分對應的還有數(shù)據(jù)水平拆分。數(shù)據(jù)水平拆分就是把同一個表的數(shù)據(jù)拆到兩個數(shù)據(jù)庫中。產(chǎn)生數(shù)據(jù)水平拆分的原因是某個業(yè)務的數(shù)據(jù)表的數(shù)據(jù)量或者更新量達到了單個數(shù)據(jù)庫的瓶頸,這時就可以把這個表拆到兩個或者多個數(shù)據(jù)庫中。數(shù)據(jù)水平拆分與讀寫分離的區(qū)別是,讀寫分離解決的是讀壓力大的問題,對于數(shù)據(jù)量大或者更新量的情況并不起作用。數(shù)據(jù)水平拆分與數(shù)據(jù)垂直拆分的區(qū)別是,垂直拆分是把不同的表拆到不同的數(shù)據(jù)庫中,而水平拆分是把同一個表拆到不同的數(shù)據(jù)庫中。例如,經(jīng)過垂直拆分后,用戶表與交易表、商品表不在一個數(shù)據(jù)庫中了,如果數(shù)據(jù)量或者更新量太大,我們可以進一步把用戶表拆分到兩個數(shù)據(jù)庫中,它們擁有結構一模一樣的用戶表,而且每個庫中的用戶表都只涵蓋了一部分的用戶,兩個數(shù)據(jù)庫的用戶合在一起就相當于沒有拆分之前的用戶表。我們先來簡單看一下引入數(shù)據(jù)水平拆分后的結構,如圖2-21 所示。我們來分析一下水平拆分后給業(yè)務應用帶來的影響。首先,訪問用戶信息的應用系統(tǒng)需要解決SQL 路由的問題,因為現(xiàn)在用戶信息分在了兩個數(shù)據(jù)庫中,需要在進行數(shù)據(jù)庫操作時了解需要操作的數(shù)據(jù)在哪里。此外,主鍵的處理也會變得不同。原來依賴單個數(shù)據(jù)庫的一些機制需要變化,例如原來使用Oracle 的Sequence 或者MySQL 表上的自增字段的,現(xiàn)在不能簡單地繼續(xù)使用了。并且在不同的數(shù)據(jù)庫中也不能直接使用一些數(shù)據(jù)庫的限制來保證主鍵不重復了。最后,由于同一個業(yè)務的數(shù)據(jù)被拆分到了不同的數(shù)據(jù)庫中,因此一些查詢需要從兩個數(shù)據(jù)庫中取數(shù)據(jù),如果數(shù)據(jù)量太大而需要分頁,就會比較難處理了。不過,一旦我們能夠完成數(shù)據(jù)的水平拆分,我們將能夠很好地應對數(shù)據(jù)量及寫入量增長的情況。具體如何完成數(shù)據(jù)水平拆分,在后面分布式數(shù)據(jù)訪問層的章節(jié)中我們將進行更加詳細的介紹。2.2.8 數(shù)據(jù)庫問題解決后,應用面對的新挑戰(zhàn)2.2.8.1 拆分應用前面所講的讀寫分離、分布式存儲、數(shù)據(jù)垂直拆分和數(shù)據(jù)水平拆分都是在解決數(shù)據(jù)方面的問題。下面我們來看看應用方面的變化。之前解決了應用服務器從單機到多機的擴展,應用就可以在一定范圍內(nèi)水平擴展了。隨著業(yè)務的發(fā)展,應用的功能會越來越多,應用也會越來越大。我們需要考慮如何不讓應用持續(xù)變大,這就需要把應用拆開,從一個應用變?yōu)閮蓚€甚至多個應用。我們來看兩種方式。第一種方式,根據(jù)業(yè)務的特性把應用拆開。在我們的例子中,主要的業(yè)務功能分為三大部分:交易、商品和用戶。我們可以把原來的一個應用拆成分別以交易和商品為主的兩個應用,對于交易和商品都會有涉及用戶的地方,我們讓這兩個系統(tǒng)自己完成涉及用戶的工作,而類似用戶注冊、登錄等基礎的用戶工作,可以暫時交給兩系統(tǒng)之一來完成(注意,我們在這里主要是通過例子說明拆分的做法),如圖2-22 所示,這樣的拆分可以使大的應用變小。我們還可以按照用戶注冊、用戶登錄、用戶信息維護等再拆分,使之變成三個系統(tǒng)。不過,這樣拆分后在不同系統(tǒng)中會有一些相似的代碼,例如用戶相關的代碼。如何能夠保證這部分代碼的一致以及如何對其復用是需要解決的問題。此外,按這樣的方式拆分出來的新系統(tǒng)之間一般沒有直接的相互調(diào)用。而且,新拆出來的應用可能會連接同樣的數(shù)據(jù)庫。來看一個具體的例子,如圖2-23 所示。我們根據(jù)業(yè)務的不同功能拆分了幾個業(yè)務應用,而且這些業(yè)務應用之間不存在直接的調(diào)用,它們都依賴底層的數(shù)據(jù)庫、緩存、文件系統(tǒng)、搜索等。這樣的應用拆分確實能夠解決當下的一些問題,不過也有一些缺點。 2.2.8.2 走服務化的路我們再來看一下服務化的做法。圖2-24 是一個示意圖。從中可以看到我們把應用分為了三層,處于最上端的是Web 系統(tǒng),用于完成不同的業(yè)務功能;處于中間的是一些服務中心,不同的服務中心提供不同的業(yè)務服務;處于下層的則是業(yè)務的數(shù)據(jù)庫。當然,我們在這個圖中省去了緩存等基礎的系統(tǒng),因此可以說是服務化系統(tǒng)結構的一個簡圖。圖2-24 與之前的圖相比有幾個很重要的變化。首先,業(yè)務功能之間的訪問不僅是單機內(nèi)部的方法調(diào)用了,還引入了遠程的服務調(diào)用。其次,共享的代碼不再是散落在不同的應用中了,這些實現(xiàn)被放在了各個服務中心。第三,數(shù)據(jù)庫的連接也發(fā)生了一些變化,我們把與數(shù)據(jù)庫的交互工作放到了服務中心,讓前端的Web 應用更加注重與瀏覽器交互的工作,而不必過多關注業(yè)務邏輯的事情。連接數(shù)據(jù)庫的任務交給相應的業(yè)務服務中心了,這樣可以降低數(shù)據(jù)庫的連接數(shù)。而服務中心不僅把一些可以共用的之前散落在各個業(yè)務的代碼集中了起來,并且能夠使這些代碼得到更好的維護。第四,通過服務化,無論是前端Web 應用還是服務中心,都可以是由固定小團隊來維護的系統(tǒng),這樣能夠更好地保持穩(wěn)定性,并能更好地控制系統(tǒng)本身的發(fā)展,況且穩(wěn)定的服務中心日常發(fā)布的次數(shù)也遠小于前端Web 應用,因此這個方式也減小了不穩(wěn)定的風險。要做到服務化還需要一些基礎組件的支撐,在后面服務框架的章節(jié)我們會具體介紹。通過某種特定的條件,將存放在同一個數(shù)據(jù)庫中的數(shù)據(jù)分散存放到多個數(shù)據(jù)庫上,實現(xiàn)分布存儲,通過路由規(guī)則路由訪問特定的數(shù)據(jù)庫,這樣一來每次訪問面對的就不是單臺服務器了,而是N臺服務器,這樣就可以降低單臺機器的負載壓力。提示:sqlserver 2005版本之后,可以友好的支持“表分區(qū)”。垂直(縱向)拆分:是指按功能模塊拆分,比如分為訂單庫、商品庫、用戶庫...這種方式多個數(shù)據(jù)庫之間的表結構不同。水平(橫向)拆分:將同一個表的數(shù)據(jù)進行分塊保存到不同的數(shù)據(jù)庫中,這些數(shù)據(jù)庫中的表結構完全相同。SQL Server:數(shù)據(jù)庫/數(shù)據(jù)表 拆分 ▲(縱向拆分)SQL Server:數(shù)據(jù)庫/數(shù)據(jù)表 拆分 ▲(橫向拆分)1,實現(xiàn)原理:使用垂直拆分,主要要看應用類型是否合適這種拆分方式,如系統(tǒng)可以分為,訂單系統(tǒng),商品管理系統(tǒng),用戶管理系統(tǒng)業(yè)務系統(tǒng)比較明的,垂直拆分能很好的起到分散數(shù)據(jù)庫壓力的作用。業(yè)務模塊不明晰,耦合(表關聯(lián))度比較高的系統(tǒng)不適合使用這種拆分方式。但是垂直拆分方式并不能徹底解決所有壓力問題,例如 有一個5000w的訂單表,操作起來訂單庫的壓力仍然很大,如我們需要在這個表中增加(insert)一條新的數(shù)據(jù),insert完畢后,數(shù)據(jù)庫會針對這張表重新建立索引,5000w行數(shù)據(jù)建立索引的系統(tǒng)開銷還是不容忽視的,反過來,假如我們將這個表分成100個table呢,從table_001一直到table_100,5000w行數(shù)據(jù)平均下來,每個子表里邊就只有50萬行數(shù)據(jù),這時候我們向一張只有50w行數(shù)據(jù)的table中insert數(shù)據(jù)后建立索引的時間就會呈數(shù)量級的下降,極大了提高了DB的運行時效率,提高了DB的并發(fā)量,這種拆分就是橫向拆分2,實現(xiàn)方法:垂直拆分,拆分方式實現(xiàn)起來比較簡單,根據(jù)表名訪問不同的數(shù)據(jù)庫就可以了。橫向拆分的規(guī)則很多,這里總結前人的幾點,(1)順序拆分:如可以按訂單的日前按年份才分,2003年的放在db1中,2004年的db2,以此類推。當然也可以按主鍵標準拆分。優(yōu)點:可部分遷移缺點:數(shù)據(jù)分布不均,可能2003年的訂單有100W,2008年的有500W。(2)hash取模分: 對user_id進行hash(或者如果user_id是數(shù)值型的話直接使用user_id的值也可),然后用一個特定的數(shù)字,比如應用中需要將一個數(shù)據(jù)庫切分成4個數(shù)據(jù)庫的話,我們就用4這個數(shù)字對user_id的hash值進行取模運算,也就是user_id%4,這樣的話每次運算就有四種可能:結果為1的時候?qū)狣B1;結果為2的時候?qū)狣B2;結果為3的時候?qū)狣B3;結果為0的時候?qū)狣B4,這樣一來就非常均勻的將數(shù)據(jù)分配到4個DB中。優(yōu)點:數(shù)據(jù)分布均勻缺點:數(shù)據(jù)遷移的時候麻煩;不能按照機器性能分攤數(shù)據(jù) 。(3)在認證庫中保存數(shù)據(jù)庫配置就是建立一個DB,這個DB單獨保存user_id到DB的映射關系,每次訪問數(shù)據(jù)庫的時候都要先查詢一次這個數(shù)據(jù)庫,以得到具體的DB信息,然后才能進行我們需要的查詢操作。優(yōu)點:靈活性強,一對一關系缺點:每次查詢之前都要多一次查詢,會造成一定的性能損失。------------------------------------------------------------------------------ mysql數(shù)據(jù)庫的水平拆分與垂直拆分 近端時間在面試,發(fā)現(xiàn)很多面試官或者面試都把數(shù)據(jù)的水平拆分合垂直拆分給搞混了,今天特意寫了一篇博客來說說水平拆分和垂直拆分希望對程序猿們有所幫助。數(shù)據(jù)庫水平與垂直拆分:垂直(縱向)拆分:是指按功能模塊拆分,比如分為訂單庫、商品庫、用戶庫...這種方式多個數(shù)據(jù)庫之間的表結構不同。水平(橫向)拆分:將同一個表的數(shù)據(jù)進行分塊保存到不同的數(shù)據(jù)庫中,這些數(shù)據(jù)庫中的表結構完全相同。數(shù)據(jù)表的水平與垂直拆分:垂直拆分:按字段功能主次拆分,比如最常見的商品表、商品圖片表、商品詳細信息...表與表之間的結構不同水平拆分:同數(shù)據(jù)庫的水平拆分原理一樣主要是將數(shù)據(jù)進行拆分保存到不同的表當中,這些表的結構完全相同。、使用用垂直拆分要主要看系統(tǒng)是否適合這種拆分方式,如系統(tǒng)可分為用戶系統(tǒng),商品系統(tǒng)、訂單系統(tǒng)等這些業(yè)務比較明確的比較適合使用垂直拆分,垂直拆分能很好分散數(shù)據(jù)庫壓力。業(yè)務模塊不清晰,模塊耦合度較高的系統(tǒng)并不適合垂直拆分。垂直拆分并不能徹底解決所有的壓力問題,例如有一張8000w的訂單表而且訂單隨著時間還在一直增加,操作起這張訂單表壓力依然很大,如我們需要在這個表中增加(insert)一條新的數(shù)據(jù),insert完畢后,數(shù)據(jù)庫會針對這張表重新建立索引,8000w行數(shù)據(jù)建立索引的系統(tǒng)開銷還是不容忽視的,這類情況就可以使用到水平拆分了,可以將表分成100個table,table_001一直到table_100,8000w數(shù)據(jù)平均分下來就是80萬的數(shù)據(jù)(經(jīng)過實際測試mysql數(shù)據(jù)量達到400w的時候性能明顯降低,故而應將單個mysql的數(shù)據(jù)量控制在300W以內(nèi)),這時候我們向一張只有80w行數(shù)據(jù)的table中insert數(shù)據(jù)后建立索引的時間就會呈數(shù)量級的下降,極大了提高了DB的運行時效率,提高了DB的并發(fā)量,這種拆分就是水平(橫向)拆分數(shù)據(jù)庫拆的實現(xiàn)方式:垂直拆分,拆分方式實現(xiàn)起來比較簡單,根據(jù)表名訪問不同的數(shù)據(jù)庫就可以了這里不多講。橫向拆分的規(guī)則很多,這里總結了以下幾點:1、順序拆分:例如訂單表可以按訂單的日期按年份才分,2016年的放在db1中,2017年的db2,以此類推。當然也可以按主鍵標準拆分。優(yōu)點:可部分遷移缺點:數(shù)據(jù)分布不均,可能2016年的訂單有200W,2017年的有800W。2、hash取模分: 例如訂單表對user_id進行hash(或者如果user_id是數(shù)值型的話直接使用user_id的值也可),然后用一個特定的數(shù)字,比如應用中需要將一個數(shù)據(jù)庫切分成4個數(shù)據(jù)庫的話,我們就用4這個數(shù)字對user_id的hash值進行取模運算,也就是user_id%4,這樣的話每次運算就有四種可能:結果為1的時候?qū)狣B1;結果為2的時候?qū)狣B2;結果為3的時候?qū)狣B3;結果為0的時候?qū)狣B4,這樣一來就非常均勻的將數(shù)據(jù)分配到4個DB中。優(yōu)點:數(shù)據(jù)分布均勻缺點:數(shù)據(jù)遷移的時候麻煩;不能按照機器性能分攤數(shù)據(jù) 。3、在認證庫中保存數(shù)據(jù)庫配置,就是建立一個DB,這個DB單獨保存user_id到DB的映射關系,每次訪問數(shù)據(jù)庫的時候都要先查詢一次這個數(shù)據(jù)庫,以得到具體的DB信息,然后才能進行我們需要的查詢操作。優(yōu)點:靈活性強,一對一關系缺點:每次查詢之前都要多一次查詢,會造成一定的性能損失。ps:暫時只想到這些希望對大家有幫助,如果有更好的方法歡迎留言區(qū)評論交流 ----------------------------------------------------------------------------oracle表分區(qū)
oracle表分區(qū)詳解(按天、按月、按年等)分區(qū)表的概念:當表中的數(shù)據(jù)量不斷增大,查詢數(shù)據(jù)的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區(qū)。表進行分區(qū)后,邏輯上表仍然是一張完整的表,只是將表中的數(shù)據(jù)在物理上存放到多個表空間(物理文件上),這樣查詢數(shù)據(jù)時,不至于每次都掃描整張表。分區(qū)表的優(yōu)點:1) 改善查詢性能:對分區(qū)對象的查詢可以僅搜索自己關心的分區(qū),提高檢索速度。2) 增強可用性:如果表的某個分區(qū)出現(xiàn)故障,表在其他分區(qū)的數(shù)據(jù)仍然可用;3) 維護方便:如果表的某個分區(qū)出現(xiàn)故障,需要修復數(shù)據(jù),只修復該分區(qū)即可;4) 均衡I/O:可以把不同的分區(qū)映射到磁盤以平衡I/O,改善整個系統(tǒng)性能。分區(qū)表的種類:1.范圍分區(qū) 概念: 范圍分區(qū)將數(shù)據(jù)基于范圍映射到每一個分區(qū),這個范圍是你在創(chuàng)建分區(qū)時指定的分區(qū)鍵決定的。這種分區(qū)方式是最為常用的,并且分區(qū)鍵經(jīng)常采用日期。舉個例子:你可能會將銷售數(shù)據(jù)按照月份進行分區(qū)。-- 按行分區(qū) SQL> CREATE TABLE part_andy12 (3 andy_ID NUMBER NOT NULL PRIMARY KEY,4 FIRST_NAME VARCHAR2(30) NOT NULL,5 LAST_NAME VARCHAR2(30) NOT NULL,6 PHONE VARCHAR2(15) NOT NULL,7 EMAIL VARCHAR2(80),8 STATUS CHAR(1)9 )10 PARTITION BY RANGE (andy_ID)11 (12 PARTITION PART1 VALUES LESS THAN (10000) ,13 PARTITION PART2 VALUES LESS THAN (20000)14 );Table created.-- 按時間分區(qū)SQL> CREATE TABLE part_andy22 (3 ORDER_ID NUMBER(7) NOT NULL,4 ORDER_DATE DATE,5 OTAL_AMOUNT NUMBER,6 CUSTOTMER_ID NUMBER(7),7 PAID CHAR(1)8 )9 PARTITION BY RANGE (ORDER_DATE)10 (11 PARTITION p1 VALUES LESS THAN (TO_DATE('2014-10-1', 'yyyy-mm-dd')) ,12 PARTITION p2 VALUES LESS THAN (TO_DATE('2015-10-1', 'yyyy-mm-dd')) ,13 PARTITION p3 VALUES LESS THAN (TO_DATE('2016-10-1', 'yyyy-mm-dd')) ,14 partition p4 values less than (maxvalue)15 );Table created.2. Hash分區(qū)概念: 對于那些無法有效劃分范圍的表,可以使用hash分區(qū),這樣對于提高性能還是會有一定的幫助。hash分區(qū)會將表中的數(shù)據(jù)平均分配到你指定的幾個分區(qū)中,列所在分區(qū)是依據(jù)分區(qū)列的hash值自動分配,因此你并不能控制也不知道哪條記錄會被放到哪個分區(qū)中,hash分區(qū)也可以支持多個依賴列。注意: hash分區(qū)最主要的機制是根據(jù)hash算法來計算具體某條紀錄應該插入到哪個分區(qū)中,hash算法中最重要的是hash函數(shù),Oracle中如果你要使用hash分區(qū),只需指定分區(qū)的數(shù)量即可。建議分區(qū)的數(shù)量采用2的n次方,這樣可以使得各個分區(qū)間數(shù)據(jù)分布更加均勻。--按hash分區(qū) SQL> create table part_andy32 (3 transaction_id number primary key,4 item_id number(8) not null5 )6 partition by hash(transaction_id)7 (8 partition part_01 ,9 partition part_02 ,10 partition part_0311 );Table created.3. List分區(qū)概念: List分區(qū)也需要指定列的值,其分區(qū)值必須明確指定,該分區(qū)列只能有一個,不能像range或者hash分區(qū)那樣同時指定多個列做為分區(qū)依賴列,但它的單個分區(qū)對應值可以是多個。注意: 在分區(qū)時必須確定分區(qū)列可能存在的值,一旦插入的列值不在分區(qū)范圍內(nèi),則插入/更新就會失敗,因此通常建議使用list分區(qū)時,要創(chuàng)建一個default分區(qū)存儲那些不在指定范圍內(nèi)的記錄,類似range分區(qū)中的maxvalue分區(qū)。-- 按list分區(qū) SQL> create table part_andy42 (3 id varchar2(15 byte) not null,4 city varchar2(20)5 )6 partition by list (city)7 (8 partition t_list025 values ('beijing'),9 partition t_list372 values ('shanghai') ,10 partition t_list510 values ('changsha'),11 partition p_other values (default)12 );Table created.4. 組合分區(qū)Oracle10g提供兩種分區(qū)組合 – Range-hash SQL> create table part_andy52 (3 transaction_id number primary key,4 item_id number(8) not null,5 item_description varchar2(300),6 transaction_date date7 )8 partition by range(transaction_date)subpartition by hash(transaction_id)9 (10 partition part_01 values less than(TO_DATE('2014-10-1', 'yyyy-mm-dd')),11 partition part_02 values less than(TO_DATE('2015-10-1', 'yyyy-mm-dd')),12 partition part_03 values less than(maxvalue)13 );Table created.– Range-list SQL> CREATE TABLE SALES2 (3 PRODUCT_ID VARCHAR2(5),4 SALES_DATE DATE,5 SALES_COST NUMBER(10),6 STATUS VARCHAR2(20)7 )8 PARTITION BY RANGE(SALES_DATE) SUBPARTITION BY LIST (STATUS)9 (10 PARTITION P1 VALUES LESS THAN(TO_DATE('2014-10-1', 'yyyy-mm-dd'))11 (SUBPARTITION P1SUB1 VALUES ('ACTIVE') ,SUBPARTITION P1SUB2 VALUES ('INACTIVE')12 ),PARTITION P2 VALUES LESS THAN (TO_DATE('2015-10-1', 'yyyy-mm-dd'))13 (14 SUBPARTITION P2SUB1 VALUES ('ACTIVE') ,15 SUBPARTITION P2SUB2 VALUES ('INACTIVE')16 )17 );Table created.Oracle11g增加了四種組合 – RANGE-RANGE – LIST-RANGE – LIST-HASH – LIST-LIST Oracle 11g 中虛擬列來實現(xiàn)。在11g之前 分區(qū)表的partition key必須是物理存在的。11g開始提供了虛擬列,并且可以作為partition key 。 --按星期分區(qū) SQL> CREATE TABLE part_andy62 (3 getdate date NOT NULL,4 wd NUMBER GENERATED ALWAYS AS (TO_NUMBER (TO_CHAR (getdate, 'D'))) VIRTUAL5 )6 PARTITION BY LIST (wd)7 (8 PARTITION Mon VALUES (1),9 PARTITION Tue VALUES (2),10 PARTITION Wed VALUES (3),11 PARTITION Thu VALUES (4),12 PARTITION Fri VALUES (5),13 PARTITION Sat VALUES (6),14 PARTITION Sun VALUES (7)15 );Table created.SQL> SQL> insert into part_andy6(getdate) values(sysdate);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-1);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-2);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-3);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-4);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-5);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-6);1 row created.SQL> insert into part_andy6(getdate) values(sysdate-7);1 row created.-- 檢查測試成功 SQL> select * from part_andy6;GETDATE WD ------------------- ---------- 2014-11-23 16:35:07 1 2014-11-24 16:35:07 2 2014-11-25 16:35:07 3 2014-11-26 16:35:07 4 2014-11-27 16:35:07 5 2014-11-28 16:35:07 6 2014-11-29 16:35:07 7 2014-11-22 16:35:08 78 rows selected.Oracle Database 11g,Interval類型分區(qū)表,可以根據(jù)加載數(shù)據(jù),自動創(chuàng)建指定間隔的分區(qū)。創(chuàng)建按月分區(qū)的分區(qū)表:a. 創(chuàng)建分區(qū)表SQL> CREATE TABLE interval_andy7 (a1 NUMBER, a2 DATE)2 PARTITION BY RANGE (a2)3 INTERVAL ( NUMTOYMINTERVAL (1, 'MONTH') )4 (PARTITION part15 VALUES LESS THAN (TO_DATE('2014-11-1', 'yyyy-mm-dd')),6 PARTITION part27 VALUES LESS THAN (TO_DATE('2014-12-1', 'yyyy-mm-dd'))8 );Table created. 注意:如果在建Interval分區(qū)表是沒有把所有的分區(qū)寫完成,在插入相關數(shù)據(jù)后會自動生成分區(qū) b. 查看現(xiàn)在表的分區(qū): SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY7'; TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVALPART PART1 INTERVALPART PART2 c. 插入測試數(shù)據(jù): SQL> begin2 for i in 0 .. 11 loop3 insert into interval_andy7 values(i,add_months(to_date('2014-11-1','yyyy-mm-dd'),i));4 end loop ;5 commit;6 end;7 /PL/SQL procedure successfully completed.PL/SQL 過程已成功完成。 補充:add_months()函數(shù)獲取前一個月或者下一個月的月份, 參數(shù)中 負數(shù) 代表 往前, 正數(shù) 代表 往后。 --上一個月 select to_char(add_months(trunc(sysdate),-1),'yyyymm') from dual; --下一個月 select to_char(add_months(trunc(sysdate),1),'yyyymm') from dual; d. 觀察自動創(chuàng)建的分區(qū): SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY7';TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVAL_ANDY7 PART1 INTERVAL_ANDY7 PART2 INTERVAL_ANDY7 SYS_P24 INTERVAL_ANDY7 SYS_P25 INTERVAL_ANDY7 SYS_P26 INTERVAL_ANDY7 SYS_P27 INTERVAL_ANDY7 SYS_P28 INTERVAL_ANDY7 SYS_P29 INTERVAL_ANDY7 SYS_P30 INTERVAL_ANDY7 SYS_P31 INTERVAL_ANDY7 SYS_P32TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVAL_ANDY7 SYS_P33 INTERVAL_ANDY7 SYS_P3413 rows selected.下面創(chuàng)建一個以天為間隔的分區(qū)表:1. 創(chuàng)建分區(qū)表: SQL> create table interval_andy82 (3 id number,4 dt date5 )6 partition by range (dt)7 INTERVAL (NUMTODSINTERVAL(1,'day'))8 (9 partition p20141101 values less than (to_date('2014-11-1','yyyy-mm-dd'))10 );Table created.2. 查看表分區(qū): SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY8';TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVAL_ANDY8 P201411013. 插入測試數(shù)據(jù): begin for i in 1 .. 12 loop insert into INTERVAL_ANDY8 values(i,trunc(to_date('2014-11-1','yyyy-mm-dd')+i)); end loop; commit; end; / PL/SQL 過程已成功完成。 4. 觀察自動創(chuàng)建的分區(qū): SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY8';TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVAL_ANDY8 P20141101 INTERVAL_ANDY8 SYS_P35 INTERVAL_ANDY8 SYS_P36 INTERVAL_ANDY8 SYS_P37 INTERVAL_ANDY8 SYS_P38 INTERVAL_ANDY8 SYS_P39 INTERVAL_ANDY8 SYS_P40 INTERVAL_ANDY8 SYS_P41 INTERVAL_ANDY8 SYS_P42 INTERVAL_ANDY8 SYS_P43 INTERVAL_ANDY8 SYS_P44TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVAL_ANDY8 SYS_P45 INTERVAL_ANDY8 SYS_P4613 rows selected. -------------------------------------------------------------------------------------- oracle分區(qū)技術提高查詢效率 概述: 當表中的數(shù)據(jù)量不斷增大,查詢數(shù)據(jù)的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區(qū)。表進行分區(qū)后,邏輯上表仍然是一張完整的表,只是將表中的數(shù)據(jù)在物理上存放到多個表空間(物理文件上),這樣查詢數(shù)據(jù)時,不至于每次都掃描整張表。下面介紹如何使用分區(qū)增加查詢效率range分區(qū):就是區(qū)域分區(qū)復制代碼 CREATE TABLE SALE (PRODUCT_ID VARCHAR2(5),SALE_COUNT NUMBER(10,2) ) PARTITION BY RANGE (SALE_COUNT) (PARTITION P1 VALUES LESS THAN (1000) TABLESPACE CUS_TS01,PARTITION P2 VALUES LESS THAN (2000) TABLESPACE CUS_TS02 ) 復制代碼 查看分區(qū)語法:select * from user_tab_partitions; --查詢所有分區(qū)情況,可以接條件where table_name='sale'查看分區(qū)表結構select * from sale partition(p1); --查詢某表的某一分區(qū)數(shù)據(jù)分區(qū)后,新增數(shù)據(jù)的SALE_COUNT字段如果小于1000就存儲到P1分區(qū)中,如果1000到2000存儲到P2分區(qū)中。但是這時如果我們新增的一條數(shù)據(jù)的SALE_COUNT字段值大于2000,將無法存儲到表中。我們可以擴展分區(qū),語法如下:alter table sale add partition p4 values less than(maxvalue); --大于2000的都會存到此分區(qū)中,當然也可以增加更多的分區(qū)同時可以刪除分區(qū),語法如下:alter table sale drop partition p4; --注意:刪除分區(qū)會把分區(qū)內(nèi)已有的數(shù)據(jù)同時刪除但還存在一個問題,如果現(xiàn)在update分區(qū)p1中的SALE_COUNT值為1500,是不會成功的,需要在update前增加以下語句:alter table sale enable row movement; --使其row能移動這樣再update就可以成功了分區(qū)索引 分區(qū)之后雖然可以提高查詢的效率,但也僅僅是提高了數(shù)據(jù)的范圍,所以我們在有必要的情況下,需要建立分區(qū)索引,從而進一步提高效率。分區(qū)索引大體上分為兩大類,一類叫做local,一類叫做global。local:在每個分區(qū)上建立索引(一般采用這種方式)global:一種在全局上建立索引,這種方式分不分區(qū)都一樣,一般不使用下面進行語法演示:注意:分區(qū)上建立的索引一定是分區(qū)字段create index idx_count on sale(sale_count) local;--建立分區(qū)索引,在sale表的每個分區(qū)都建立了索引select * from user_ind_partitions;--查詢所有分區(qū)索引情況全局索引global寫法就是把上面的local替換成global,但不會使用有些時候,如果你分區(qū)分為0~1000,1000~2000,這時如果說0~1500這個范圍內(nèi)的數(shù)據(jù)會被頻繁查詢,1500之后查詢很少,那么就可以使用這種自定義的全局索引方式對0~1500建立索引,之后的設置maxvalue即可,語法與分區(qū)語法相似global自定義全局索引方式(前綴索引):create index idxname on table(field) globalpartition by range(field) (partition p1 values less than(value), .......partition pN values less than(maxvalue));其他分區(qū)介紹 1.hash分區(qū)hash分區(qū)實現(xiàn)均勻的負載值分配,增加hash分區(qū)可以重新分布數(shù)據(jù),簡單理解就是分區(qū)直接平均分配復制代碼 CREATE TABLE SALE (PRODUCT_ID VARCHAR2(5),SALE_COUNT NUMBER(10,2) ) PARTITION BY HASH (PRODUCT_ID) (PARTITION P1,PARTITION P2 ) 復制代碼 2.list分區(qū)該分區(qū)的特點是某列的值只有幾個,基于這樣的特點我們可以采用列表分區(qū)。復制代碼 CREATE TABLE ListTable (id INT PRIMARY KEY ,name VARCHAR (20),area VARCHAR (10) ) PARTITION BY LIST (area) (PARTITION part1 VALUES ('guangdong','beijing') TABLESPACE Part1_tb,PARTITION part2 VALUES ('shanghai','nanjing') TABLESPACE Part2_tb ); 復制代碼 3.復合分區(qū)(用的不多)復制代碼 create table student(sno number,sname varchar2(10) ) partition by range (sno) subpartition by hash (sname) subpartitions 4 (partition p1 values less than(1000),partition p2 values less than(2000),partition p3 values less than(maxvalue) ); 復制代碼 復合分區(qū)首先大體上分為三個分區(qū)p1,p2,p3,然后每一個分區(qū)內(nèi)部再進行hash分區(qū),分為4份查詢子分區(qū)的語句:select * from user_tab_subpartitions where table_name='student';4.間隔分區(qū)(工作中常用)是一種分區(qū)自動化的分區(qū),可以指定時間間隔進行分區(qū),這是oracle11g的新特性,實際工作中很常用。實際上是由range分區(qū)引申的,最終實現(xiàn)了range分區(qū)的自動化復制代碼 create table interval_sale (sid int,sdate timestamp) partition by range(sdate) interval (numtoyminterval(1,'MONTH')) ( partition p1 values less than (TIMESTAMP '2017-11-12 00:00:00.00') ) 復制代碼 指定時間之前建立一個分區(qū),之后每隔一個月建立一個分區(qū)問題:如果我們drop掉了表,那么這個表的分區(qū)還存在嗎?答案是存在的,oracle提供了很強大的數(shù)據(jù)恢復功能,有一個類似回收站的機制,刪除表后,分區(qū)以特殊的形式仍然存在user_tab_partitions中,使用purge recyclebin語法后,會清空回收站,使用flashback table 表名 to before drop語句可以恢復刪除的表。 ------------------------------------------------------------------------------------- 當大家遇到小數(shù)據(jù)的時候,大家可能想著在where后面多加點約束條件;當數(shù)據(jù)在大點的時候,大家可能就開始考慮給這添加索引了;當大家遇到百萬級千萬級數(shù)據(jù)的時候,大家就可能開始添加表分區(qū)了。so,我就開始了我的分(keng)區(qū)(die)之旅。一開始,由于我的這張大表有100多萬數(shù)據(jù)量,就單單一個存儲過程居然執(zhí)行了一個多鐘,于是,我便把這張大表改成分區(qū)表,并在ID上給這添加索引,優(yōu)化存儲過程。改成分區(qū)表之后,效果果然斐然,從1個多鐘優(yōu)化到了一分半鐘。可惜啊,好景不長,才過了2天,測試姐姐就把我啦過去看問題,說我的存儲過程把整個過程卡住了,700多萬的數(shù)據(jù),存儲過程居然執(zhí)行了將近4個小時沒執(zhí)行完,我嘴上笑嘻嘻,心里媽賣批。自己挖的坑,含著淚也要把它搞定。我首先查了下是不是分區(qū)表的索引失效了,但經(jīng)過排查,發(fā)現(xiàn)并不是(心中一萬頭草擬馬跑過),然后,我就執(zhí)行一樂該id下的700多萬數(shù)據(jù)的存儲過程,果然很慢,難怪他被卡死了,一查下去發(fā)現(xiàn)是select語句查詢很慢,奇怪點就在當我用另一個也是擁有700多萬的id數(shù)據(jù)執(zhí)行存儲過程的時候,奇跡發(fā)現(xiàn)了,居然3分多鐘就完成。為什么同樣是700多萬的數(shù)據(jù),一個執(zhí)行了4個多鐘還沒完成,一個執(zhí)行了3分多鐘就完成了。抱著疑問,我一步一步排查這個分區(qū)表下不同id表有什么區(qū)別呢,最終發(fā)現(xiàn)執(zhí)行快的id,在該分區(qū)表下global_stats=YES,而另一個的global_stats則=false。于是我查到了以下的信息"分區(qū)表里global_stats=YES的全局統(tǒng)計信息是否準確關系到optimizer能否選擇較優(yōu)的執(zhí)行計劃,對分區(qū)表執(zhí)行全局統(tǒng)計會不可避免的產(chǎn)生FTS加重系統(tǒng)負擔,尤其對于DW環(huán)境里規(guī)模較大的分區(qū)表而言更是如此。"而global_stats這個代表該分區(qū)表是否對該分區(qū)進行了統(tǒng)計分析,一般情況下,系統(tǒng)在不知道什么時候都會對這分區(qū)就行統(tǒng)計分析的。而對這個分區(qū)進行統(tǒng)計分析又包含了兩種方式,非incremental方式,incremental方式,而非incremental方式會進行全量掃描分區(qū)表中所有的分區(qū),incremental方式則會增量掃描分區(qū)表中的分區(qū)。incremental statistics collect正是在這一背景下應運而生,簡單的說incremental statistics collect會實時記錄分區(qū)表里每個partition每列值的更新情況,這一信息保存在SYSAUX表空間里,后續(xù)根據(jù)這一信息在執(zhí)行全局統(tǒng)計時僅會針對有變化的partition進行statistics collect,并將收集的結果與沒有變化過的partition原有的統(tǒng)計信息進行整合,計算出準確的global stats,省去了必須去掃描每一個partition的步驟。非incremental方式下新加分區(qū)后對整個分區(qū)表收集統(tǒng)計信息,會全量掃描分區(qū)表中所有的分區(qū),即使那些沒有改變過的分區(qū)也會被重新掃描一遍 ------------------------------------------------------------------------ 深入學習Oracle分區(qū)表及分區(qū)索引關于分區(qū)表和分區(qū)索引(About Partitioned Tables and Indexes)對于10gR2而言,基本上可以分成幾類:? Range(范圍)分區(qū)? Hash(哈希)分區(qū)? List(列表)分區(qū)? 以及組合分區(qū):Range-Hash,Range-List。對于表而言(常規(guī)意義上的堆組織表),上述分區(qū)形式都可以應用(甚至可以對某個分區(qū)指定compress屬性),只不過分區(qū)依賴列不能是lob,long之類數(shù)據(jù)類型,每個表的分區(qū)或子分區(qū)數(shù)的總數(shù)不能超過1023個。對于索引組織表,只能夠支持普通分區(qū)方式,不支持組合分區(qū),常規(guī)表的限制對于索引組織表同樣有效,除此之外呢,還有一些其實的限制,比如要求索引組織表的分區(qū)依賴列必須是主鍵才可以等。注:本篇所有示例僅針對常規(guī)表,即堆組織表!對于索引,需要區(qū)分創(chuàng)建的是全局索引,或本地索引:l 全局索引(global index):即可以分區(qū),也可以不分區(qū)。即可以建range分區(qū),也可以建hash分區(qū),即可建于分區(qū)表,又可創(chuàng)建于非分區(qū)表上,就是說,全局索引是完全獨立的,因此它也需要我們更多的維護操作。l 本地索引(local index):其分區(qū)形式與表的分區(qū)完全相同,依賴列相同,存儲屬性也相同。對于本地索引,其索引分區(qū)的維護自動進行,就是說你add/drop/split/truncate表的分區(qū)時,本地索引會自動維護其索引分區(qū)。Oracle建議如果單個表超過2G就最好對其進行分區(qū),對于大表創(chuàng)建分區(qū)的好處是顯而易見的,這里不多論述why,而將重點放在when以及how。ORACLE對于分區(qū)表方式其實就是將表分段存儲,一般普通表格是一個段存 儲,而分區(qū)表會分成多個段,所以查找數(shù)據(jù)過程都是先定位根據(jù)查詢條件定位分區(qū)范圍,即數(shù)據(jù)在那個分區(qū)或那幾個內(nèi)部,然后在分區(qū)內(nèi)部去查找數(shù)據(jù),一個分區(qū)一 般保證四十多萬條數(shù)據(jù)就比較正常了,但是分區(qū)表并非亂建立,而其維護性也相對較為復雜一點,而索引的創(chuàng)建也是有點講究的,這些以下盡量闡述詳細即可。range分區(qū)方式,也算是最常用的分區(qū)方式,其通過某字段或幾個字段的組合的值,從小到大,按照指定的范圍說明進行分區(qū),我們在INSERT數(shù)據(jù)的時候就會存儲到指定的分區(qū)中。List分區(qū)方式,一般是在range基礎上做的二級分區(qū)較多,是一種列舉方式進行分區(qū),一般講某些地區(qū)、狀態(tài)或指定規(guī)則的編碼等進行劃分。Hash分區(qū)方式,它沒有固定的規(guī)則,由ORACLE管理,只需要將值INSERT進去,ORACLE會自動去根據(jù)一套HASH算法去劃分分區(qū),只需要告訴ORACLE要分幾個區(qū)即可。WHEN一、When使用Range分區(qū)Range分區(qū)呢是應用范圍比較廣的表分區(qū)方式,它是以列的值的范圍來做為分區(qū)的劃分條件,將記錄存放到列值所在的range分區(qū)中,比如按照 時間劃分,2008年1季度的數(shù)據(jù)放到a分區(qū),08年2季度的數(shù)據(jù)放到b分區(qū),因此在創(chuàng)建的時候呢,需要你指定基于的列,以及分區(qū)的范圍值,如果某些記錄 暫無法預測范圍,可以創(chuàng)建maxvalue分區(qū),所有不在指定范圍內(nèi)的記錄都會被存儲到maxvalue所在分區(qū)中,并且支持指定多列做為依賴列,后面在 講how的時候會詳細談到。二、When使用Hash分區(qū)通常呢,對于那些無法有效劃分范圍的表,可以使用hash分區(qū),這樣對于提高性能還是會有一定的幫助。hash分區(qū)會將表中的數(shù)據(jù)平均分配到你 指定的幾個分區(qū)中,列所在分區(qū)是依據(jù)分區(qū)列的hash值自動分配,因此你并不能控制也不知道哪條記錄會被放到哪個分區(qū)中,hash分區(qū)也可以支持多個依賴 列。三、When使用List分區(qū)List分區(qū)與range分區(qū)和hash分區(qū)都有類似之處,該分區(qū)與range分區(qū)類似的是也需要你指定列的值,但這又不同與range分區(qū)的 范圍式列值---其分區(qū)值必須明確指定,也不同與hash分區(qū)---通過明確指定分區(qū)值,你能控制記錄存儲在哪個分區(qū)。它的分區(qū)列只能有一個,而不能像 range或者hash分區(qū)那樣同時指定多個列做為分區(qū)依賴列,不過呢,它的單個分區(qū)對應值可以是多個。你在分區(qū)時必須確定分區(qū)列可能存在的值,一旦插入的列值不在分區(qū)范圍內(nèi),則插入/更新就會失敗,因此通常建議使用list分區(qū)時,要創(chuàng)建一個default分區(qū)存儲那些不在指定范圍內(nèi)的記錄,類似range分區(qū)中的maxvalue分區(qū)。四、When使用組合分區(qū)如果某表按照某列分區(qū)之后,仍然較大,或者是一些其它的需求,還可以通過分區(qū)內(nèi)再建子分區(qū)的方式將分區(qū)再分區(qū),即組合分區(qū)的方式。組合分區(qū)呢在10g中有兩種:range-hash,range-list。注意順序喲,根分區(qū)只能是range分區(qū),子分區(qū)可以是hash分區(qū)或list分區(qū)。提示:11g在組合分區(qū)功能這塊有所增強,又推出了range-range,list-range,list-list,list-hash, 這就相當于除hash外三種分區(qū)方式的笛卡爾形式都有了。為什么會沒有hash做為根分區(qū)的組合分區(qū)形式呢,再仔細回味一下第二點,你一定能夠想明 白~~。深入學習Oracle分區(qū)表及分區(qū)索引(2)一、如何創(chuàng)建如果想對某個表做分區(qū),必須在創(chuàng)建表時就指定分區(qū),我們可以對一個包含分區(qū)的表中的分區(qū)做修改,但不能直接將一個未分區(qū)的表修改成分區(qū)表(起碼在10g是不行的,當然你可能會說,可以通過在線重定義的方式,但是這不是直接喲,這也是借助臨時表間接實現(xiàn)的)。創(chuàng)建表或索引的語法就不說了,大家肯定比我還熟悉,而想在建表(索引)同時指定分區(qū)也非常容易,只需要把創(chuàng)建分區(qū)的子句放到";"前就行啦,同 時需要注意表的row movement屬性,它用來控制是否允許修改列值所造成的記錄移動至其它分區(qū)存儲,有enable|disable兩種狀態(tài),默認是disable row movement,當disable時,如果記錄要被更新至其它分區(qū),則更新語句會報錯。下面分別演示不同分區(qū)方式的表和索引的創(chuàng)建:1、創(chuàng)建range分區(qū)語法如下,需要我們指定的有:l column:分區(qū)依賴列(如果是多個,以逗號分隔);l partition:分區(qū)名稱;l values less than:后跟分區(qū)范圍值(如果依賴列有多個,范圍對應值也應是多個,中間以逗號分隔);l tablespace_clause:分區(qū)的存儲屬性,例如所在表空間等屬性(可為空),默認繼承基表所在表空間的屬性。① 創(chuàng)建一個標準的range分區(qū)表:JSSWEB> create table t_partition_range (id number,name varchar2(50))partition by range(id)(partition t_range_p1 values less than (10) tablespace tbspart01,partition t_range_p2 values less than (20) tablespace tbspart02,partition t_range_p3 values less than (30) tablespace tbspart03,partition t_range_pmax values less than (maxvalue) tablespace tbspart04);表已創(chuàng)建。要查詢創(chuàng)建分區(qū)的信息,可以通過查詢user_part_tables,user_tab_partitions兩個數(shù)據(jù)字典(索引分區(qū)、組織分區(qū)等信息也有對應的數(shù)據(jù)字典,后續(xù)示例會逐步提及)。user_part_tables:記錄分區(qū)的表的信息;user_tab_partitions:記錄表的分區(qū)的信息。例如:JSSWEB> select table_name,partitioning_type,partition_countFrom user_part_tables where table_name='T_PARTITION_RANGE';JSSWEB> select partition_name,high_value,tablespace_namefrom user_tab_partitions where table_name='T_PARTITION_RANGE'order by partition_position;② 創(chuàng)建global索引range分區(qū):JSSWEB> create index idx_parti_range_id on t_partition_range(id)2 global partition by range(id)(3 partition i_range_p1 values less than (10) tablespace tbspart01,4 partition i_range_p2 values less than (40) tablespace tbspart02,5 partition i_range_pmax values less than (maxvalue) tablespace tbspart03);索引已創(chuàng)建。由上例可以看出,創(chuàng)建global索引的分區(qū)與創(chuàng)建表的分區(qū)語句格式完全相同,而且其分區(qū)形式與索引所在表的分區(qū)形式?jīng)]有關聯(lián)關系。注意:我們這里借助上面的表t_partition_range來演示創(chuàng)建range分區(qū)的global索引,并不表示range分區(qū)的表,只能創(chuàng)建range分區(qū)的global索引,只要你想,也可以為其創(chuàng)建hash分區(qū)的global索引。查詢索引的分區(qū)信息可以通過user_part_indexes、user_ind_partitions兩個數(shù)據(jù)字典:JSSWEB> select index_name, partitioning_type, partition_count2 From user_part_indexes3 where index_name = 'IDX_PARTI_RANGE_ID';③ Local分區(qū)索引的創(chuàng)建最簡單,例如:仍然借助t_partition_range表來創(chuàng)建索引--首先刪除之前創(chuàng)建的global索引JSSWEB> drop index IDX_PARTI_RANGE_ID;索引已刪除。JSSWEB> create index IDX_PARTI_RANGE_ID on T_PARTITION_RANGE(id) local;索引已創(chuàng)建。查詢相關數(shù)據(jù)字典:JSSWEB> select index_name, partitioning_type, partition_count2 From user_part_indexes3 where index_name = 'IDX_PARTI_RANGE_ID';JSSWEB> select partition_name, high_value, tablespace_name2 from user_ind_partitions3 where index_name = 'IDX_PARTI_RANGE_ID'4 order by partition_position;可以看出,local索引的分區(qū)完全繼承表的分區(qū)的屬性,包括分區(qū)類型,分區(qū)的范圍值即不需指定也不能更改,這就是前面說的:local索引的分區(qū)維護完全依賴于其索引所在表。不過呢分區(qū)名稱,以及分區(qū)所在表空間等信息是可以自定義的,例如:SQL> create index IDX_PART_RANGE_ID ON T_PARTITION_RANGE(id) local (2 partition i_range_p1 tablespace tbspart01,3 partition i_range_p2 tablespace tbspart01,4 partition i_range_p3 tablespace tbspart02,5 partition i_range_pmax tablespace tbspart026 );索引已創(chuàng)建。SQL> select index_name, partitioning_type, partition_count2 From user_part_indexes3 where index_name = 'IDX_PART_RANGE_ID';SQL> select partition_name, high_value, tablespace_name2 from user_ind_partitions3 where index_name = 'IDX_PART_RANGE_ID'4 order by partition_position;創(chuàng)建hash分區(qū)語法如下:[圖:hash_partitioning.gif]語法看起來比range復雜,其實使用起來比range更簡單,這里需要我們指定的有:l column:分區(qū)依賴列(支持多個,中間以逗號分隔);l partition:指定分區(qū),有兩種方式:n 直接指定分區(qū)名,分區(qū)所在表空間等信息n 只指定分區(qū)數(shù)量,和可供使用的表空間。2、創(chuàng)建hash分區(qū)JSSWEB> create table t_partition_hash (id number,name varchar2(50))2 partition by hash(id)(3 partition t_hash_p1 tablespace tbspart01,4 partition t_hash_p2 tablespace tbspart02,5 partition t_hash_p3 tablespace tbspart03);表已創(chuàng)建。要實現(xiàn)同樣效果,你還可以這樣:JSSWEB> create table t_partition_hash2 (id number,name varchar2(50))2 partition by hash(id)3 partitions 3 store in(tbspart01,tbspart02,tbspart03);表已創(chuàng)建。這就是上面說的,直接指定分區(qū)數(shù)量和可供使用的表空間。提示:這里分區(qū)數(shù)量和可供使用的表空間數(shù)量之間沒有直接對應關系。分區(qū)數(shù)并不一定要等于表空間數(shù)。要查詢表的分區(qū)信息,仍然是通過user_part_tables,user_tab_partitions兩個數(shù)據(jù)字典,這里不再舉例。① Global索引hash分區(qū)Hash分區(qū)索引的子句與hash分區(qū)表的創(chuàng)建子句完全相同,例如:JSSWEB> create index idx_part_hash_id on t_partition_hash(id)2 global partition by hash(id)3 partitions 3 store in(tbspart01,tbspart02,tbspart03);索引已創(chuàng)建。查詢索引的分區(qū)信息也仍是通過user_part_indexes、user_ind_partitions兩個數(shù)據(jù)字典,不再舉例。② 創(chuàng)建Local索引在前面學習range分區(qū)時,我們已經(jīng)對Local索引的特性做了非常清晰的概述,因此這里也不再舉例,如有疑問,建議再仔細復習range分區(qū)的相關示例,如果還有疑問,當面問我好了:)綜上:? 對于global索引分區(qū)而言,在10g中只能支持range分區(qū)和hash分區(qū),因此后續(xù)示例中不會再提及。? 對于local索引分區(qū)而言,其分區(qū)形式完全依賴于索引所在表的分區(qū)形式,不管從創(chuàng)建語法還是理解難度均無技術含量,因此后續(xù)也不再提供示例。? 注意,在創(chuàng)建索引時如果不顯式指定global或local,則默認是global。? 注意,在創(chuàng)建global索引時如果不顯式指定分區(qū)子句,則默認不分區(qū)(廢話)。3、分區(qū)應用: 一般一張表超過2G的大小,ORACLE是推薦使用分區(qū)表的,分區(qū)一般都需要 創(chuàng)建索引,說到分區(qū)索引,就可以分為:全局索引、分區(qū)索引,即:global索引和local索引,前者為默認情況下在分區(qū)表上創(chuàng)建索引時的索引方式,并 不對索引進行分區(qū)(索引也是表結構,索引大了也需要分區(qū),關于索引以后專門寫點)而全局索引可修飾為分區(qū)索引,但是和local索引有所區(qū)別,前者的分區(qū) 方式完全按照自定義方式去創(chuàng)建,和表結構完全無關,所以對于分區(qū)表的全局索引有以下兩幅網(wǎng)上常用的圖解:3.1、對于分區(qū)表的不分區(qū)索引(這個有點繞,不過就是表分區(qū),但其索引不分區(qū)):創(chuàng)建語法(直接創(chuàng)建即可):CREATE INDEX ON ();3.2、對于分區(qū)表的分區(qū)索引:創(chuàng)建語法為:CREATE INDEX INX_TAB_PARTITION_COL1 ON TABLE_PARTITION(COL1)GLOBAL PARTITION BY RANGE(COL1)(PARTITION IDX_P1 values less than (1000000),PARTITION IDX_P2 values less than (2000000),PARTITION IDX_P3 values less than (MAXVALUE));3.3、LOCAL索引結構:創(chuàng)建語法為:CREATE INDEX INX_TAB_PARTITION_COL1 ON TABLE_PARTITION(COL1) LOCAL;也可按照分區(qū)表的的分區(qū)結構給與一一定義,索引的分區(qū)將得到重命名。分區(qū)上的位圖索引只能為LOCAL索引,不能為GLOBAL全局索引。3.4、對比索引方式:一般使用LOCAL索引較為方便,而且維護代價較低,并且LOCAL索引是在分區(qū)的基礎上去創(chuàng)建索引,類似于在一個子表內(nèi)部去創(chuàng)建索引,這樣開銷主要是區(qū) 分分區(qū)上,很規(guī)范的管理起來,在OLAP系統(tǒng)中應用很廣泛;而相對的GLOBAL索引是全局類型的索引,根據(jù)實際情況可以調(diào)整分區(qū)的類別,而并非按照分區(qū) 結構一一定義,相對維護代價較高一些,在OLTP環(huán)境用得相對較多,這里所謂OLTP和OLAP也是相對的,不是特殊的項目,沒有絕對的劃分概念,在應用 過程中依據(jù)實際情況而定,來提高整體的運行性能。4、常用視圖: 1、查詢當前用戶下有哪些是分區(qū)表:SELECT * FROM USER_PART_TABLES;2、查詢當前用戶下有哪些分區(qū)索引:SELECT * FROM USER_PART_INDEXES;3、查詢當前用戶下分區(qū)索引的分區(qū)信息:SELECT * FROM USER_IND_PARTITIONS TWHERE T.INDEX_NAME=?4、查詢當前用戶下分區(qū)表的分區(qū)信息:SELECT * FROM USER_TAB_PARTITIONS TWHERE T.TABLE_NAME=?;5、查詢某分區(qū)下的數(shù)據(jù)量:SELECT COUNT(*) FROM TABLE_PARTITION PARTITION(TAB_PARTOTION_01);6、查詢索引、表上在那些列上創(chuàng)建了分區(qū):SELECT * FROM USER_PART_KEY_COLUMNS;7、查詢某用戶下二級分區(qū)的信息(只有創(chuàng)建了二級分區(qū)才有數(shù)據(jù)):SELECT * FROM USER_TAB_SUBPARTITIONS;5、維護操作: 5.1、刪除分區(qū)ALTER TABLE TABLE_PARTITION DROP PARTITION TAB_PARTOTION_03;如果是全局索引,因為全局索引的分區(qū)結構和表可以不一致,若不一致的情況下,會導致整個全局索引失效,在刪除分區(qū)的時候,語句修改為:ALTER TABLE TABLE_PARTITION DROP PARTITION TAB_PARTOTION_03 UPDATE GLOBAL INDEXES;5.2、分區(qū)合并(從中間刪除掉一個分區(qū),或者兩個分區(qū)需要合并后減少分區(qū)數(shù)量)合并分區(qū)和刪除中間的RANGE有點像,但是合并分區(qū)是不會刪除數(shù)據(jù)的,對于LIST、HASH分區(qū)也是和RANGE分區(qū)不一樣的,其語法為:ALTER TABLE TABLE_PARTITION MERGE PARTITIONS TAB_PARTOTION_01,TAB_PARTOTION_02 INTO PARTITION MERGED_PARTITION;5.3、分隔分區(qū)(一般分區(qū)從擴展分區(qū)從分隔) ALTER TABLE TABLE_PARTITION SPLIT PARTITION TAB_PARTOTION_OTHERE AT(2500000)INTO (PARTITION TAB_PARTOTION_05,PARTITION TAB_PARTOTION_OTHERE);5.4、創(chuàng)建新的分區(qū)(分區(qū)數(shù)據(jù)若不能提供范圍,則插入時會報錯,需要增加分區(qū)來擴大范圍) 一般有擴展分區(qū)的是都是用分隔的方式,若上述創(chuàng)建表時沒有創(chuàng)建TAB_PARTOTION_OTHER分區(qū)時,在插入數(shù)據(jù)較大時(按照上述建立規(guī)則,超過1800000就應該創(chuàng)建新的分區(qū)來存儲),就可以創(chuàng)建新的分區(qū),如:為了試驗,我們將擴展分區(qū)先刪除掉再創(chuàng)建新的分區(qū)(因為ORACLE要求,分區(qū)的數(shù)據(jù)不允許重疊,即按照分區(qū)字段同樣的數(shù)據(jù)不能同時存儲在不同的分區(qū)中):ALTER TABLE TABLE_PARTITION DROP PARTITION TAB_PARTOTION_OTHER;ALTER TABLE TABLE_PARTITION ADD PARTITION TAB_PARTOTION_06 VALUES LESS THAN(2500000);在分區(qū)下創(chuàng)建新的子分區(qū)大致如下(RANGE分區(qū),若為LIST或HASH分區(qū),將創(chuàng)建方式修改為對應的方式即可):ALTER TABLE MODIFY PARTITION ADD SUBPARTITION VALUES LESS THAN(....);5.5、修改分區(qū)名稱(修改相關的屬性信息) ALTER TABLE TABLE_PARTITION RENAME PARTITION MERGED_PARTITION TO MERGED_PARTITION02;5.6、交換分區(qū)(快速交換數(shù)據(jù),其實是交換段名稱指針)首先創(chuàng)建一個交換表,和原表結構相同,如果有數(shù)據(jù),必須符合所交換對應分區(qū)的條件:CREATE TABLE TABLE_PARTITION_2AS SELECT * FROM TABLE_PARTITION WHERE 1=2;然后將第一個分區(qū)的數(shù)據(jù)交換出去:ALTER TABLE TABLE_PARTITION EXCHANGE PARTITION TAB_PARTOTION_01WITH TABLE TABLE_PARTITION_2 INCLUDING INDEXES;此時會發(fā)現(xiàn)第一個分區(qū)的數(shù)據(jù)和表TABLE_PARTITION_2做了瞬間交換,比TRUNCATE還要快,因為這個過程沒有進行數(shù)據(jù)轉(zhuǎn)存,只是段名稱的修改過程,和實際的數(shù)據(jù)量沒有關系。如果是子分區(qū)也可以與外部的表進行交換,只需要將關鍵字修改為:SUBPARTITION 即可。5.7、清空分區(qū)數(shù)據(jù)ALTER TABLE TRUNCATE PARTITION ;ALTER TABLE TRUNCATE subpartition ;6、磁盤碎片壓縮對分區(qū)表的某分區(qū)進行磁盤壓縮,當對分區(qū)內(nèi)部數(shù)據(jù)進行了大量的UPDATE、DELETE操作后,一定時間需要進行磁盤壓縮,否則在查詢時,若通過FULL SCAN掃描數(shù)據(jù),將會把空塊也會掃描到,對表進行磁盤壓縮需要進行行遷移操作,所以首先需要操作:ALTER TABLE ENABLE ROW MOVEMENT ;對分區(qū)表的某分區(qū)壓縮語法為:ALTER TABLEmodify partition shrink space;對普通表壓縮:ALTER TABLE shrink space;對于索引也需要進行壓縮,索引也是表:ALTER INDEX shrink space; ---------------------------------------------------------------------------------------- oracle表空間表分區(qū)詳解及oracle表分區(qū)查詢使用方法(轉(zhuǎn)+整理) 此文從以下幾個方面來整理關于分區(qū)表的概念及操作:1.表空間及分區(qū)表的概念 2.表分區(qū)的具體作用 3.表分區(qū)的優(yōu)缺點 4.表分區(qū)的幾種類型及操作方法 5.對表分區(qū)的維護性操作.表空間及分區(qū)表的概念 表空間:是一個或多個數(shù)據(jù)文件的集合,所有的數(shù)據(jù)對象都存放在指定的表空間中,但主要存放的是表, 所以稱作表空間。 分區(qū)表:當表中的數(shù)據(jù)量不斷增大,查詢數(shù)據(jù)的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區(qū)。表進行分區(qū)后,邏輯上表仍然是一張完整的表,只是將表中的數(shù)據(jù)在物理上存放到多個表空間(物理文件上),這樣查詢數(shù)據(jù)時,不至于每次都掃描整張表。表分區(qū)的具體作用 Oracle的表分區(qū)功能通過改善可管理性、性能和可用性,從而為各式應用程序帶來了極大的好處。通常,分區(qū)可以使某些查詢以及維護操作的性能大大提高。此外,分區(qū)還可以極大簡化常見的管理任務,分區(qū)是構建千兆字節(jié)數(shù)據(jù)系統(tǒng)或超高可用性系統(tǒng)的關鍵工具。分區(qū)功能能夠?qū)⒈怼⑺饕蛩饕M織表進一步細分為段,這些數(shù)據(jù)庫對象的段叫做分區(qū)。每個分區(qū)有自己的名稱,還可以選擇自己的存儲特性。從數(shù)據(jù)庫管理員的角度來看,一個分區(qū)后的對象具有多個段,這些段既可進行集體管理,也可單獨管理,這就使數(shù)據(jù)庫管理員在管理分區(qū)后的對象時有相當大的靈活性。但是,從應用程序的角度來看,分區(qū)后的表與非分區(qū)表完全相同,使用 SQL DML 命令訪問分區(qū)后的表時,無需任何修改。什么時候使用分區(qū)表:表的大小超過2GB。 表中包含歷史數(shù)據(jù),新的數(shù)據(jù)被增加都新的分區(qū)中。 表分區(qū)的優(yōu)缺點 表分區(qū)有以下優(yōu)點:改善查詢性能:對分區(qū)對象的查詢可以僅搜索自己關心的分區(qū),提高檢索速度。 增強可用性:如果表的某個分區(qū)出現(xiàn)故障,表在其他分區(qū)的數(shù)據(jù)仍然可用; 維護方便:如果表的某個分區(qū)出現(xiàn)故障,需要修復數(shù)據(jù),只修復該分區(qū)即可; 均衡I/O:可以把不同的分區(qū)映射到磁盤以平衡I/O,改善整個系統(tǒng)性能。 缺點:已經(jīng)存在的表沒有方法可以直接轉(zhuǎn)化為分區(qū)表。但是有幾種方式可以間接完成這個操作,大家可以參考:oracle分區(qū)表的建立方法(包含已經(jīng)存在的表要分區(qū)):http://blog.csdn.net/wanglilin/article/details/7177338 表分區(qū)的幾種類型及操作方法 范圍分區(qū): 范圍分區(qū)將數(shù)據(jù)基于范圍映射到每一個分區(qū),這個范圍是你在創(chuàng)建分區(qū)時指定的分區(qū)鍵決定的。這種分區(qū)方式是最為常用的,并且分區(qū)鍵經(jīng)常采用日期。舉個例子:你可能會將銷售數(shù)據(jù)按照月份進行分區(qū)。 當使用范圍分區(qū)時,請考慮以下幾個規(guī)則:1、每一個分區(qū)都必須有一個VALUES LESS THEN子句,它指定了一個不包括在該分區(qū)中的上限值。分區(qū)鍵的任何值等于或者大于這個上限值的記錄都會被加入到下一個高一些的分區(qū)中。 2、所有分區(qū),除了第一個,都會有一個隱式的下限值,這個值就是此分區(qū)的前一個分區(qū)的上限值。 3、在最高的分區(qū)中,MAXVALUE被定義。MAXVALUE代表了一個不確定的值。這個值高于其它分區(qū)中的任何分區(qū)鍵的值,也可以理解為高于任何分區(qū)中指定的VALUE LESS THEN的值,同時包括空值。例一:假設有一個CUSTOMER表,表中有數(shù)據(jù)200000行,我們將此表通過CUSTOMER_ID進行分區(qū),每個分區(qū)存儲100000行,我們將每個分區(qū)保存到單獨的表空間中,這樣數(shù)據(jù)文件就可以跨越多個物理磁盤。下面是創(chuàng)建表和分區(qū)的代碼,如下:CREATE TABLE CUSTOMER ( CUSTOMER_ID NUMBER NOT NULL PRIMARY KEY, FIRST_NAME VARCHAR2(30) NOT NULL, LAST_NAME VARCHAR2(30) NOT NULL, PHONEVARCHAR2(15) NOT NULL, EMAILVARCHAR2(80), STATUS CHAR(1) ) PARTITION BY RANGE (CUSTOMER_ID) ( PARTITION CUS_PART1 VALUES LESS THAN (100000) TABLESPACE CUS_TS01, PARTITION CUS_PART2 VALUES LESS THAN (200000) TABLESPACE CUS_TS02 ) 例二:按時間劃分CREATE TABLE ORDER_ACTIVITIES ( ORDER_ID NUMBER(7) NOT NULL, ORDER_DATE DATE, TOTAL_AMOUNT NUMBER, CUSTOTMER_ID NUMBER(7), PAID CHAR(1) ) PARTITION BY RANGE (ORDER_DATE) ( PARTITION ORD_ACT_PART01 VALUES LESS THAN (TO_DATE('01- MAY -2003','DD-MON-YYYY')) TABLESPACEORD_TS01, PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUN-2003','DD-MON-YYYY')) TABLESPACE ORD_TS02, PARTITION ORD_ACT_PART02 VALUES LESS THAN (TO_DATE('01-JUL-2003','DD-MON-YYYY')) TABLESPACE ORD_TS03 ) 例三:MAXVALUECREATE TABLE RangeTable ( idd INT PRIMARY KEY , iNAME VARCHAR(10), grade INT ) PARTITION BY RANGE (grade) ( PARTITION part1 VALUES LESS THEN (1000) TABLESPACE Part1_tb, PARTITION part2 VALUES LESS THEN (MAXVALUE) TABLESPACE Part2_tb ); 列表分區(qū): 該分區(qū)的特點是某列的值只有幾個,基于這樣的特點我們可以采用列表分區(qū)。例一CREATE TABLE PROBLEM_TICKETS ( PROBLEM_ID NUMBER(7) NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR2(2000), CUSTOMER_ID NUMBER(7) NOT NULL, DATE_ENTERED DATE NOT NULL, STATUS VARCHAR2(20) ) PARTITION BY LIST (STATUS) ( PARTITION PROB_ACTIVE VALUES ('ACTIVE') TABLESPACE PROB_TS01, PARTITION PROB_INACTIVE VALUES ('INACTIVE') TABLESPACE PROB_TS02 ) 例二CREATE TABLE ListTable ( id INT PRIMARY KEY , name VARCHAR (20), area VARCHAR (10) ) PARTITION BY LIST (area) ( PARTITION part1 VALUES ('guangdong','beijing') TABLESPACE Part1_tb, PARTITION part2 VALUES ('shanghai','nanjing') TABLESPACE Part2_tb ); ) 散列分區(qū): 這類分區(qū)是在列值上使用散列算法,以確定將行放入哪個分區(qū)中。當列的值沒有合適的條件時,建議使用散列分區(qū)。 散列分區(qū)為通過指定分區(qū)編號來均勻分布數(shù)據(jù)的一種分區(qū)類型,因為通過在I/O設備上進行散列分區(qū),使得這些分區(qū)大小一致。 例一:CREATE TABLE HASH_TABLE ( COL NUMBER(8), INF VARCHAR2(100) ) PARTITION BY HASH (COL) ( PARTITION PART01 TABLESPACE HASH_TS01, PARTITION PART02 TABLESPACE HASH_TS02, PARTITION PART03 TABLESPACE HASH_TS03 ) 簡寫:CREATE TABLE emp ( empno NUMBER (4), ename VARCHAR2 (30), sal NUMBER ) PARTITION BY HASH (empno) PARTITIONS 8 STORE IN (emp1,emp2,emp3,emp4,emp5,emp6,emp7,emp8); hash分區(qū)最主要的機制是根據(jù)hash算法來計算具體某條紀錄應該插入到哪個分區(qū)中,hash算法中最重要的是hash函數(shù),Oracle中如果你要使用hash分區(qū),只需指定分區(qū)的數(shù)量即可。建議分區(qū)的數(shù)量采用2的n次方,這樣可以使得各個分區(qū)間數(shù)據(jù)分布更加均勻。組合范圍散列分區(qū) 這種分區(qū)是基于范圍分區(qū)和列表分區(qū),表首先按某列進行范圍分區(qū),然后再按某列進行列表分區(qū),分區(qū)之中的分區(qū)被稱為子分區(qū)。CREATE TABLE SALES ( PRODUCT_ID VARCHAR2(5), SALES_DATE DATE, SALES_COST NUMBER(10), STATUS VARCHAR2(20) ) PARTITION BY RANGE(SALES_DATE) SUBPARTITION BY LIST (STATUS) ( PARTITION P1 VALUES LESS THAN(TO_DATE('2003-01-01','YYYY-MM-DD'))TABLESPACE rptfact2009 ( SUBPARTITION P1SUB1 VALUES ('ACTIVE') TABLESPACE rptfact2009, SUBPARTITION P1SUB2 VALUES ('INACTIVE') TABLESPACE rptfact2009 ), PARTITION P2 VALUES LESS THAN (TO_DATE('2003-03-01','YYYY-MM-DD')) TABLESPACE rptfact2009 ( SUBPARTITION P2SUB1 VALUES ('ACTIVE') TABLESPACE rptfact2009, SUBPARTITION P2SUB2 VALUES ('INACTIVE') TABLESPACE rptfact2009 ) ) 復合范圍散列分區(qū): 這種分區(qū)是基于范圍分區(qū)和散列分區(qū),表首先按某列進行范圍分區(qū),然后再按某列進行散列分區(qū)。create table dinya_test ( transaction_id number primary key, item_id number(8) not null, item_description varchar2(300), transaction_date date ) partition by range(transaction_date)subpartition by hash(transaction_id) subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03) ( partition part_01 values less than(to_date(‘2006-01-01','yyyy-mm-dd')), partition part_02 values less than(to_date(‘2010-01-01','yyyy-mm-dd')), partition part_03 values less than(maxvalue) ); 有關表分區(qū)的一些維護性操作: 添加分區(qū) 以下代碼給SALES表添加了一個P3分區(qū)ALTER TABLE SALES ADD PARTITION P3 VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD')); 注意:以上添加的分區(qū)界限應該高于最后一個分區(qū)界限。以下代碼給SALES表的P3分區(qū)添加了一個P3SUB1子分區(qū)ALTER TABLE SALES MODIFY PARTITION P3 ADD SUBPARTITION P3SUB1 VALUES('COMPLETE'); 刪除分區(qū) 以下代碼刪除了P3表分區(qū):ALTER TABLE SALES DROP PARTITION P3; 在以下代碼刪除了P4SUB1子分區(qū):ALTER TABLE SALES DROP SUBPARTITION P4SUB1; 注意:如果刪除的分區(qū)是表中唯一的分區(qū),那么此分區(qū)將不能被刪除,要想刪除此分區(qū),必須刪除表。截斷分區(qū) 截斷某個分區(qū)是指刪除某個分區(qū)中的數(shù)據(jù),并不會刪除分區(qū),也不會刪除其它分區(qū)中的數(shù)據(jù)。當表中即使只有一個分區(qū)時,也可以截斷該分區(qū)。通過以下代碼截斷分區(qū):ALTER TABLE SALES TRUNCATE PARTITION P2; 通過以下代碼截斷子分區(qū):ALTER TABLE SALES TRUNCATE SUBPARTITION P2SUB2; 合并分區(qū) 合并分區(qū)是將相鄰的分區(qū)合并成一個分區(qū),結果分區(qū)將采用較高分區(qū)的界限,值得注意的是,不能將分區(qū)合并到界限較低的分區(qū)。以下代碼實現(xiàn)了P1 P2分區(qū)的合并:ALTER TABLE SALES MERGE PARTITIONS P1,P2 INTO PARTITION P2; 拆分分區(qū) 拆分分區(qū)將一個分區(qū)拆分兩個新分區(qū),拆分后原來分區(qū)不再存在。注意不能對HASH類型的分區(qū)進行拆分。ALTER TABLE SALES SBLIT PARTITION P2 AT(TO_DATE('2003-02-01','YYYY-MM-DD')) INTO (PARTITION P21,PARTITION P22); 接合分區(qū)(coalesca) 結合分區(qū)是將散列分區(qū)中的數(shù)據(jù)接合到其它分區(qū)中,當散列分區(qū)中的數(shù)據(jù)比較大時,可以增加散列分區(qū),然后進行接合,值得注意的是,接合分區(qū)只能用于散列分區(qū)中。通過以下代碼進行接合分區(qū):ALTER TABLE SALES COALESCA PARTITION; 重命名表分區(qū) 以下代碼將P21更改為P2ALTER TABLE SALES RENAME PARTITION P21 TO P2; 相關查詢 -- 跨分區(qū)查詢 select sum( ) from (select count() cn from t_table_SS PARTITION (P200709_1) union all select count(*) cn from t_table_SS PARTITION (P200709_2) );--查詢表上有多少分區(qū) SELECT * FROM useR_TAB_PARTITIONS WHERE TABLE_NAME='tableName'--查詢索引信息 select object_name,object_type,tablespace_name,sum(value) from v$segment_statistics where statistic_name IN ('physical reads','physical write','logical reads')and object_type='INDEX' group by object_name,object_type,tablespace_name order by 4 desc--顯示數(shù)據(jù)庫所有分區(qū)表的信息: select * from DBA_PART_TABLES--顯示當前用戶可訪問的所有分區(qū)表信息: select * from ALL_PART_TABLES--顯示當前用戶所有分區(qū)表的信息: select * from USER_PART_TABLES--顯示表分區(qū)信息 顯示數(shù)據(jù)庫所有分區(qū)表的詳細分區(qū)信息: select * from DBA_TAB_PARTITIONS--顯示當前用戶可訪問的所有分區(qū)表的詳細分區(qū)信息: select * from ALL_TAB_PARTITIONS--顯示當前用戶所有分區(qū)表的詳細分區(qū)信息: select * from USER_TAB_PARTITIONS--顯示子分區(qū)信息 顯示數(shù)據(jù)庫所有組合分區(qū)表的子分區(qū)信息: select * from DBA_TAB_SUBPARTITIONS--顯示當前用戶可訪問的所有組合分區(qū)表的子分區(qū)信息: select * from ALL_TAB_SUBPARTITIONS--顯示當前用戶所有組合分區(qū)表的子分區(qū)信息: select * from USER_TAB_SUBPARTITIONS--顯示分區(qū)列 顯示數(shù)據(jù)庫所有分區(qū)表的分區(qū)列信息: select * from DBA_PART_KEY_COLUMNS--顯示當前用戶可訪問的所有分區(qū)表的分區(qū)列信息: select * from ALL_PART_KEY_COLUMNS--顯示當前用戶所有分區(qū)表的分區(qū)列信息: select * from USER_PART_KEY_COLUMNS--顯示子分區(qū)列 顯示數(shù)據(jù)庫所有分區(qū)表的子分區(qū)列信息: select * from DBA_SUBPART_KEY_COLUMNS--顯示當前用戶可訪問的所有分區(qū)表的子分區(qū)列信息: select * from ALL_SUBPART_KEY_COLUMNS--顯示當前用戶所有分區(qū)表的子分區(qū)列信息: select * from USER_SUBPART_KEY_COLUMNS--怎樣查詢出oracle數(shù)據(jù)庫中所有的的分區(qū)表 select * from user_tables a where a.partitioned='YES'--刪除一個表的數(shù)據(jù)是 truncate table table_name;--刪除分區(qū)表一個分區(qū)的數(shù)據(jù)是 alter table table_name truncate partition p5; --------------------------------------------------------------------------------------?
總結
以上是生活随笔為你收集整理的数据库表设计、 数据库分层、myslq水平拆分、oracle表分区的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 物化视图、中间表的方案
- 下一篇: 数据库建立索引、数据表创建规则、备用字段