日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

数据库表设计、 数据库分层、myslq水平拆分、oracle表分区

發布時間:2024/4/13 67 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库表设计、 数据库分层、myslq水平拆分、oracle表分区 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據庫表設計

數據庫表結構設計方法及原則(li)數據庫設計的三大范式:為了建立冗余較小、結構合理的數據庫,設計數據庫時必須遵循一定的規則。在關系型數據庫中這種規則就稱為范式。范式是符合某一種設計要求的總結。要想設計一個結構合理的關系型數據庫,必須滿足一定的范式。在實際開發中最為常見的設計范式有三個:第一范式是最基本的范式。如果數據庫表中的所有字段值都是不可分解的原子值,就說明該數據庫表滿足了第一范式;第二范式在第一范式的基礎之上更進一層。第二范式需要確保數據庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。也就是說在一個數據庫表中,一個表中只能保存一種數據,不可以把多種數據保存在同一張數據庫表中;第三范式需要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。總結一下,就是:第一范式(確保每列保持原子性);第二范式(確保表中的每列都和主鍵相關);第三范式(確保每列都和主鍵列直接相關,而不是間接相關)。在目前的企業信息系統中,數據庫還是最佳的數據存儲方式,雖然已經有很多的書籍在指導我們進行數據庫設計,但應該那種方式是設計數據庫的表結構的最好方法、設計時應遵從什么樣的原則、四個范式如何能夠用一種方式達到順暢的應用等是我一直在思考和總結的問題,下文是我針對這幾個問題根據自己的設計經歷準備總結的一篇文章的提綱,歡迎大家一塊進行探討,集思廣益。其中提到了領域建模的概念,但未作詳細解釋,希望以后能夠有時間我們針對這個命題進行深入探討。1.不應該針對整個系統進行數據庫設計,而應該根據系統架構中的組件劃分,針對每個組件所處理的業務進行組件單元的數據庫設計;不同組件間所對應的數據庫表之間的關聯應盡可能減少,如果不同組件間的表需要外鍵關聯也盡量不要創建外鍵關聯,而只是記錄關聯表的一個主鍵,確保組件對應的表之間的獨立性,為系統或表結構的重構提供可能性。//注意他這里說的是"不要創建外鍵關聯",創建外鍵關聯的語句是: //foreign key(member_id) references member (id); //我們幾乎沒有用到這條語句,因為我們就是這樣做的,用到外鍵時,只是記錄關聯表的主鍵,而非在數據庫級別上創建外鍵。 //也不知道是歪打正著,還是前輩DBA過于強大,已經考慮好了。2.采用領域模型驅動的方式和自頂向下的思路進行數據庫設計,首先分析系統業務,根據職責定義對象。對象要符合封裝的特性,確保與職責相關的數據項被定義在一個對象之內,這些數據項能夠完整描述該職責,不會出現職責描述缺失。并且一個對象有且只有一項職責,如果一個對象要負責兩個或兩個以上的職責,應進行分拆。// 領域模型驅動的方式,目前用的還不是很熟,考慮的不夠多。因為經常的數據庫中的表只是拿來做存儲用而已, //特別是小需求,要加什么字段,找到相關表加上去就行了,不太考慮領域模型。這個在中文站老業務表里很常見3.根據建立的領域模型進行數據庫表的映射,此時應參考數據庫設計第二范式:一個表中的所有非關鍵字屬性都依賴于整個關鍵字。關鍵字可以是一個屬性,也可以是多個屬性的集合,不論那種方式,都應確保關鍵字能夠保證唯一性。在確定關鍵字時,應保證關鍵字不會參與業務且不會出現更新異常,這時,最優解決方案為采用一個自增數值型屬性或一個隨機字符串作為表的關鍵字。4.由于第一點所述的領域模型驅動的方式設計數據庫表結構,領域模型中的每一個對象只有一項職責,所以對象中的數據項不存在傳遞依賴,所以,這種思路的數據庫表結構設計從一開始即滿足第三范式:一個表應滿足第二范式,且屬性間不存在傳遞依賴。//數據庫三范式記不得的同學去查資料溫習一下。 //個人認為第三范式的目的是盡量減少數據冗余,保證相同的數據只存在一份。 //第三范式其實我們遵守的并不是很嚴格,特別是老的數據庫表中會有冗余字段。這個要看情況決定吧。5.同樣,由于對象職責的單一性以及對象之間的關系反映的是業務邏輯之間的關系,所以在領域模型中的對象存在主對象和從對象之分,從對象是從1-N或N-N的角度進一步完善主對象的業務邏輯,所以從對象及對象關系映射為的表及表關聯關系不存在刪除和插入異常。//最后一句看不懂,可能是"所以表及表關聯關系不應該出現刪除和插入異常。"?6.在映射后得出的數據庫表結構中,應再根據第四范式進行進一步修改,確保不存在多值依賴。這時,應根據反向工程的思路反饋給領域模型。如果表結構中存在多值依賴,則證明領域模型中的對象具有至少兩個以上的職責,應根據第一條進行設計修正。第四范式:一個表如果滿足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字段里設置亂七八糟的值,但是這樣需要維護更多的小表,造成數據值表的數量膨脹,DBA可能會覺得管理上有更多的困難。 //我們采用潛規則約定、java枚舉類等其它方式來進行保證。但有時候效果并不是很好,經常發現舊數據庫表中枚舉字段的值五花八門,不全是約定的。 復制代碼7.在經過分析后確認所有的表都滿足二、三、四范式的情況下,表和表之間的關聯盡量采用弱關聯以便于對表字段和表結構的調整和重構。并且,我認為數據庫中的表是用來持久化一個對象實例在特定時間及特定條件下的狀態的,只是一個存儲介質,所以,表和表之間也不應用強關聯來表述業務(數據間的一致性),這一職責應由系統的邏輯層來保證,這種方式也確保了系統對于不正確數據(臟數據)的兼容性。當然,從整個系統的角度來說我們還是要盡最大努力確保系統不會產生臟數據,單從另一個角度來說,臟數據的產生在一定程度上也是不可避免的,我們也要保證系統對這種情況的容錯性。這是一個折中的方案。8.應針對所有表的主鍵和外鍵建立索引,有針對性的(針對一些大數據量和常用檢索方式)建立組合屬性的索引,提高檢索效率。雖然建立索引會消耗部分系統資源,但比較起在檢索時搜索整張表中的數據尤其時表中的數據量較大時所帶來的性能影響,以及無索引時的排序操作所帶來的性能影響,這種方式仍然是值得提倡的。//索引目前都是DBA根據具體的SQL來創建的,不過開發寫SQL時,也應該適當考慮一下字段的索引。9.盡量少采用存儲過程,目前已經有很多技術可以替代存儲過程的功能如"對象/關系映射"等,將數據一致性的保證放在數據庫中,無論對于版本控制、開發和部署、以及數據庫的遷移都會帶來很大的影響。但不可否認,存儲過程具有性能上的優勢,所以,當系統可使用的硬件不會得到提升而性能又是非常重要的質量屬性時,可經過平衡考慮選用存儲過程。//目前都是杜絕使用存儲過程的,我覺得用起來比較方便,對于我們來說,主要原因是會給DBA帶來管理方面的麻煩, //因為時間一長,存儲過程的邏輯和使用場景,往往沒人能了解,容易產生更多問題10.當處理表間的關聯約束所付出的代價(常常是使用性上的代價)超過了保證不會出現修改、刪除、更改異常所付出的代價,并且數據冗余也不是主要的問題時,表設計可以不符合四個范式。四個范式確保了不會出現異常,但也可能由此導致過于純潔的設計,使得表結構難于使用,所以在設計時需要進行綜合判斷,但首先確保符合四個范式,然后再進行精化修正是剛剛進入數據庫設計領域時可以采用的最好辦法。11.設計出的表要具有較好的使用性,主要體現在查詢時是否需要關聯多張表且還需使用復雜的SQL技巧。我感覺遵守的范式越多,就越使SQL復雜,具體情況具體分析。設計出的表要盡可能減少數據冗余,確保數據的準確性,有效的控制冗余有助于提高數據庫的性能因此,考慮了以上條件之后,表設計約定規則如下:復制代碼 //規則1:表必須要有主鍵。 //規則2:一個字段只表示一個含義。 //規則3:總是包含兩個日期字段:gmt_create(創建日期),gmt_modified(修改日期),且這兩個字段不應該包含有額外的業務邏輯。 //規則4:MySQL中,gmt_create、gmt_modified使用DATETIME類型。 //規則5:禁止使用復雜數據類型(數組,自定義類型等)。 //規則6: MySQL中,附屬表拆分后,附屬表id與主表id保持一致。不允許在附屬表新增主鍵字段。 //規則7: MySQL中,存在過期概念的表,在其設計之初就必須有過期機制,且有明確的過期時間。過期數據必須遷移至歷史表中。 //規則8: MySQL中,不再使用的表,必須通知DBA予以更名歸檔。 //規則9: MySQL中,線上表中若有不再使用的字段,為保證數據完整,禁止刪除。 //規則10: MySQL中,禁止使用OCI驅動,全部使用THI驅動。 復制代碼 關于MySQL的部分學習筆記總結:一、事務跟存儲引擎1.四種事務隔離級別:read uncommited, read commited(大多數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(多版本并發控制)來處理并發。mvcc只工作在read commited,repeatable read這兩種事務隔離級別上。read uncommited隔離級別不兼容mvcc是因為在該級別得下的查詢,不讀取符合當前事務版本的數據行,而是最新版本的數據行。seriazable隔離級別不兼容MVCC,因為該級別下的讀操作會對每個返回行進行加鎖。4.選擇存儲引擎,并發選用myisam,事務選擇innodb,myisam比innodb更容易出錯,出錯了恢復的時間也比較長。只有myisam支持全文檢索。5.把表從一種存儲引擎轉到另一種引擎:// 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; 二、數據類型1.盡可能的要把field定義為Not NULL, mysql比較難優化使用了可空列的查詢,它會使索引,索引統計更加復雜。可空列需要更多的存儲空間,還需要mysql內部進行特殊處理,當可空列被索引時,每條記錄都需要一個格外的字節。 即使要在表中存儲"沒有值"的字段,考慮使用0,特殊字段或者空字符串來代替。2.datetime與timestamp能保存同樣的數據:精確度為秒,但是timestamp使用的空間只有datetime的一半,還能保存時區,擁有特殊的自動更新能力。但是timestamp保存的時間范圍要比datetime要小得多。mysql能存儲的最細的時間粒度為秒3.mysql支持很多種別名,如bool,integer,nummeric.4.float與double類型支持使用標準的浮點運算進行近似計算。 Decimal類型保存精確的小數,在>=mysql5.0,mysql服務器自身進行了decimal的運算,因為CPU不支持直接對它進行運算,所以慢一點。5.mysql會把text與blob類型的列當成有實體的對象來進行保存。他們有各自的數據類型家族(tinytext,smalltext,text,mediumtext,longtext; blob類似); mysql對blob與text列排序方式和其他類型有所不同,它不會按照字符串的完整長度來排序。而只是按照max_sort_length規定的若干個字節來進行排序。6.采用enum來代替字符串類型。mysql在內部把每個枚舉值都保存為整數。enum在內部是按照數字進行排序的,而不是按照字符串。enum最不好的就是字符串列表是固定的,添加和刪除必須使用alter table。7.ip地址,一般會采用varchar(15)列來保存。事實上,IP地址是個無符號的32位整數,而不是字符串。mysql提供了inet_aton()和inet_nota()函數在證書與ip地址之間進行轉換。三、索引1.聚集索引不僅僅是一種單獨的索引類型,而且是一種存儲數據的方式。Innodb引擎的聚集索引實際上在同樣的結構中保存了B-Tree索引和數據行。當表有聚集索引時,它的數據行實際上保存在索引的葉子上。注意是存儲引擎來實現索引。2.myisam與innodb數據布局:myisam索引樹(無論是主鍵索引還是非主鍵索引)葉子節點都是指向的數據行,而innodb中聚集索引,主鍵索引樹葉子節點就帶得有數據的內容,而非主鍵索引樹中葉子節點指向主鍵值,而不是數據的位置。3.mysql有兩種產生排序結果的方式:使用文件排序,或者掃描有序的索引。目前只有myisam支持全文索引。4.myisam表有表級鎖;myisam表不支持事務,實際上,myisam并不保證單條命令完成;myisam只緩存了mysql進程內部的索引,并保存在鍵緩存區內。OS緩存了表的數據;行被緊密的保存在一起,磁盤上的數據有很小的磁盤占用和快速的全表掃描。5.innodb支持事務和四種事務隔離級別;在mysql5.0中,只有innodb支持外鍵;支持行級鎖與mvcc;所有的innodb表都是按照主鍵聚集的;所有索引(出開主鍵)都是按主鍵引用行;索引沒有使用前綴壓縮,因此索引可能比myisam大很多;數據轉載緩慢;阻塞auto_increment,也就是用表級鎖來產生每個auto_increment。四、MYSQL性能分析1.mysql提供了一個benchmark(int 循環次數,char* 表達式); 可以分析表達式執行所花時間。 例如:// select BENCHMARK(10000,SHA1('aaaaaaaaaaaaaaaa'))2.mysql有兩種查詢日志:普通日志和慢速日志。五、MYSQL高級特性1.在mysql中,只有myisam存儲引擎支持全文索引。myisam全文索引是一種特殊的具有兩層結構的B樹。2.存儲引擎事務在存儲引擎內部被賦予acid屬性,分布式(XA)是一種高層次事務,它可以歷喲內部個兩段提交的方式將acid屬性擴展到存儲引擎外部,甚至數據庫外部。階段1:通知所有提交者準備提交 階段2:通知所有參與者進行真正提交。3.mysql 的字符集和校對規則有 4 個級別的默認設置:服務器級、數據庫級、表級和字段級。Mysql4.1 開始支持 SQL 的子查詢。復制代碼 /******************************************/ /* 數據庫全名 = 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 '任務內容',`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 '任務狀態, 待審核、未開始、生效中、已暫停、已完成、審核未通過',`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 '重置次數',`reset_cycle` int(11) NOT NULL COMMENT '重置周期',`task_interval` int(11) NOT NULL COMMENT '任務間隔',`xiaoer` bigint(20) unsigned NOT NULL COMMENT '創建人',`review_id` bigint(20) unsigned NOT NULL COMMENT '審核人ID',`last_start_time` datetime DEFAULT NULL COMMENT '上次生效時間',`gmt_create` datetime NOT NULL COMMENT '創建時間',`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 '任務觸發條件',`end_condition` varchar(1024) NOT NULL COMMENT '任務完成條件',`enable` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否可用',`rule` varchar(4096) NOT NULL COMMENT '任務規則',`priority` int(11) NOT NULL DEFAULT '1' COMMENT '任務優先級',`progress_rule` varchar(2048) NOT NULL DEFAULT '' COMMENT '進度計算規則',`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中使用該字段指示按鈕跳轉)',`ext2` longtext COMMENT '擴展字段2,暫時預留',`channel` int(11) DEFAULT '0' COMMENT '任務渠道:0-uu或者1-game_box',`consecutive_day` int(11) DEFAULT '1' COMMENT '連續完成任務的天數',`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='任務表'; --------------------------------------------------------------------------------------- 數據庫表設計總結 一、實體與表對應關系表<=>實體,字段<=>屬性。二、表與表的關系(實體間的關系):一對一、一對多、多對多一對一:一條記錄只對應其他表中的一條記錄有關系學生基本信息表t_student,成績表t_studentScore含有一個外鍵studentId。基本信息表中的studentId和成績表中的studentId就是一對一的關系。一對多:A表一條記錄對應B表中多條記錄有關系,B表的記錄不被A表記錄共享(有關系)。班級表和學生表,一個班級有多個學生,對班級來說就是一對多的關系。多對多:A表一條記錄和B表多條記錄有關系,B表的一條記錄也和A表的多條記錄有關系(互相共享)。學生表和科目表,學生可以選擇多個科目,每個科目可以被多個學生選擇。三、基本表的完整性(1)原子性。字段是不可再分解的。 (2)原始性。記錄是原始數據(基礎數據)的記錄。 (3)穩定性。結構是相對穩定的,表中的記錄是要長期保存的。 (4)演繹性。由基本表與代碼表中的數據,可以派生出所有的輸出數據。四、其他常用表1.中間表中間表是針對多對多關系的。就比如做公交查詢系統,里面有兩個表,分別是車站表t_busstation、線路表t_road,根據常識,一個站有多個線路經過,而每個線路又有多個車站,怎么才能將兩個表聯系起來呢,如果是一對一,一對多,我們一個表, 兩個表就可以將他們實現了。但是多對多呢,這樣我們就必須借助中間表用來連接兩個表。一般中間表只有一個自增主鍵+兩個表的主鍵。中間表是沒有屬性的因為它不是一個基本表。2.臨時表臨時表是那些以#號開頭為名字的數據表,它主要是用來存放臨時數據的,當用戶斷開連接但沒有清除臨時表里的數據時,系統會自動把臨時表里的數據清空。臨時表是放在系統數據庫 tempdb中的,而不是當前數據庫。臨時表分兩種:本地臨時表和全局臨時表。a.本地臨時表本地臨時表是以#開頭的,只對當前的數據庫用戶可見,而其他的用戶是不可見的。當數據庫實例斷開后當然也就丟失了數據了,不管是顯式清空還是系統回收。 b.全局臨時表以“##”開頭的,而且是對所有的用戶都是可見,當你斷開數據庫實例連接時,只要還有別的系統項目在引用它,連著數據庫,那么數據就存在,只有當別的系統也全部斷開連接時,系統才會清除全局臨時表的數據。建立臨時表的語句:復制代碼本地臨時表: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五、三大范式第一范式:如果每列(或者每個屬性)都是不可再分的最小數據單元(也稱為最小的原子單元),則滿足第一范式.比如一個工人的基本信息表,里面有工人的工號,性別,年齡,這些屬性都是不可分割的,所以這個表就符合了第一范式。第二范式: 就是在第一范式的基礎上延伸,使之表里的每個字段都與主鍵發生關系。假如一個關系滿足第一范式,并且除了主鍵以外的其它字段,都依賴于該主鍵,則滿足第二范式. 例如:訂單表(訂單編號、產品編號、定購日期、價格、……),"訂單編號"為主鍵,"產品編號"和主鍵列沒有直接的關系,即"產品編號"列不依賴于主鍵列,這個列我們就可以把它刪除。第三范式:在第二范式的基礎上更進一步,也就是為了實現表里的列都與主鍵列直接相關,不是間接相關。這個我們可以用“Armstrong 公理”中的傳遞規則來推理。定義: 設U是關系模式R 的屬性集,F 是R 上成立的只涉及U 中屬性的函數依賴集。若X→Y 和 Y→Z在R 上成立,則X →Z 在R 上成立。因此我們就來看在網上搜索到的例子:例如:訂單表(訂單編號,定購日期,顧客編號,顧客姓名,……),初看該表沒有問題,滿足第二范式,每列都和主鍵列"訂單編號"相關,再細看你會發現"顧客姓名"和"顧客編號"相關,"顧客編號"和"訂單編號"又相關,最后經過傳遞依賴,"顧客姓名"也和"訂單編號"相關。為了滿足第三范式,應去掉"顧客姓名"列,放入客戶表中。這里其實就是為了說明數據庫的表里步要出現冗余,在顧客表里已經有了"顧客姓名"了,而在訂單表里就別出現了,而直接根據顧客編號相關聯就可以,否則造成資源浪費。三大范式延伸:第一范式:1NF是對屬性的原子性約束,要求屬性具有原子性,不可再分解; 第二范式:2NF是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性; 第三范式:3NF是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余。其實在設計數據庫的時候我們最多的要遵循的就是第三范式,但是并不是越滿足第三范式數據庫就設計的越完美,這種錯誤是錯誤的。有時候增加點冗余相反的會提高訪問速率,因此在實際的設計過程中應降低對范式的要求。以前對數據冗余并不是很了解,在百度知道里的定義是這樣的:在一個數據集合中重復的數據稱為數據冗余. 但是不是說我們表的主鍵在其他表里重復出現就是冗余,這不是,而是為了連接兩個表。只有非鍵字段就是既不是主鍵外鍵等約束的鍵如果重復出現,就會形成數據冗余。數據冗余也包括重復性冗余和派生冗余。比如工人表里有"基本工資","獎金"兩列,然后還有一個"總工資"的列,這個總工資就是派生冗余。低級的重復性冗余一定要避免,杜絕,但是像派生冗余還是提倡的因為它能提高訪問的效率。個人總結:事物的屬性對應表的屬性,將一張表看作一個事物。如,書的屬性有價格、重量、等等。(一般表都有Id來區分每條記錄) ----------------------------------------------------------------------------

數據庫分層

數據倉庫分層的原因1通過數據預處理提高效率,因為預處理,所以會存在冗余數據2如果不分層而業務系統的業務規則發生變化,就會影響整個數據清洗過程,工作量巨大3通過分層管理來實現分步完成工作,這樣每一層的處理邏輯就簡單了標準的數據倉庫分層:ods(臨時存儲層),pdw(數據倉庫層),mid(數據集市層),app(應用層)ods:歷史存儲層,它和源系統數據是同構的,而且這一層數據粒度是最細的,這層的表分為兩種,一種是存儲當前需要加載的數據,一種是用于存儲處理完后的數據。pdw:數據倉庫層,它的數據是干凈的數據,是一致的準確的,也就是清洗后的數據,它的數據一般都遵循數據庫第三范式,數據粒度和ods的粒度相同,它會保存bi系統中所有歷史數據mid:數據集市層,它是面向主題組織數據的,通常是星狀和雪花狀數據,從數據粒度將,它是輕度匯總級別的數據,已經不存在明細的數據了,從廣度來說,它包含了所有業務數量。從分析角度講,大概就是近幾年app:應用層,數據粒度高度匯總,倒不一定涵蓋所有業務數據,只是mid層數據的一個子集。數據倉庫的目的是構建面向分析的集成化數據環境,為企業提供決策支持。數據倉庫的context也可以理解為:數據源,數據倉庫,數據應用數據倉庫可以理解為中間集成化數據管理的一個平臺etl(抽取extra,轉化transfer,裝載load)是數據倉庫的流水線,也可以認為是數據倉庫的血液。數據倉庫的存儲并不需要存儲所有原始數據,因為比如你存儲冗長的文本數據完全沒必要,但需要存儲細節數據,因為需求是多變的,而且數據倉庫是導入數據必須經過整理和轉換使它面向主題,因為前臺數據庫的數據是基于oltp操作組織優化的,這些可能不適合做分析,面向主題的組織形式才有利于分析。多維數據模型就是說可以多維度交叉查詢和細分,應用一般都是基于聯機分析處理(online analytical process OLAP),面向特定需求群體的數據集市會基于多位數據模型構建而報表展示就是將聚合數據和多維分析數據展示到報表,提供簡單和直觀的數據。元數據,也叫解釋性數據,或者數據字典,會記錄數據倉庫中模型的定義,各層級之間的映射關系,監控數據倉庫的數據狀態和etl的任務運行狀態。一般通過元數據資料庫來統一存儲和管理元數據。------------------------------------------------------------------------------ -基本查詢 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節點 select level,id,c_mmcode,c_mmroomname,c_parentId from s_mmroom start with c_parentId='0' connect by prior id = c_parentId; --查詢層次數 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; --從非根節點開始遍歷 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中使用子查詢? 下面這個查詢使用子查詢來選擇指定節點的。然后傳給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; --從下向上遍歷樹? 不一定非要按照從父節點到子節點的順序從上至下遍歷樹;也可以從某個子節點開始,從下而上遍歷。實現的方法是交換父節點和子節點在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; --從層次化查詢中刪除節點和分支?? 略 表名后面加where --在層次化查詢中加入其它條件????? 略 表名后面加where ------------------------------------------------------------------ BLOCK(塊)block 是oracle中最小的分配單位,也是最小的I/O單位,可以在創建數據庫時設定block的大小,可以設為任意的大小,但為了支持與兼容方面,建議現實中設為2的冪,例如:2KB、4KB、8KB,最大為32KB。EXTENT(區)extent 是由邏輯連續的block組成的,注意是邏輯上的,一般來講,文件本身在磁盤上不是連續的,extent的大小可能是一個block的大小,也可能大到2GB,SEGMENT(段)segment 是由一個或多個extent組成的,segment就是占用存儲空間的數據庫對象,例如表、索引等,segment在tablespace中,但可以包含這個tablespace中的多個數據文件中的數據TABLESPACE(表空間)ORACLE數據庫是由一個或多個TABLESPACE構成,什么是TABLESPACE? 一種邏輯上的存儲容器,包括一個或多個datafile(數據文件)。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需要更多的空間,可以調整已分配給該TABLESPACE的datafile的大小,也可以增加第三個datafile。要說明的是上述所討論的概念除了block都是邏輯上的概念,所謂連續的也是邏輯上連續的。 -------------------------------------------------------------------------------

myslq水平拆分

mysql的水平拆分和垂直拆分 1,水平分割:例:QQ的登錄表。假設QQ的用戶有100億,如果只有一張表,每個用戶登錄的時候數據庫都要從這100億中查找,會很慢很慢。如果將這一張表分成100份,每張表有1億條,就小了很多,比如qq0,qq1,qq1...qq99表。用戶登錄的時候,可以將用戶的id%100,那么會得到0-99的數,查詢表的時候,將表名qq跟取模的數連接起來,就構建了表名。比如123456789用戶,取模的89,那么就到qq89表查詢,查詢的時間將會大大縮短。這就是水平分割。2,垂直分割:垂直分割指的是:表的記錄并不多,但是字段卻很長,表占用空間很大,檢索表的時候需要執行大量的IO,嚴重降低了性能。這時需要把大的字段拆分到另一個表,并且該表與原表是一對一的關系。例如學生答題表tt:有如下字段:Id name 分數 題目 回答其中題目和回答是比較大的字段,id name 分數比較小。如果我們只想查詢id為8的學生的分數:select 分數 from tt where id = 8;雖然知識查詢分數,但是題目和回答這兩個大字段也是要被掃描的,很消耗性能。但是我們只關心分數,并不想查詢題目和回答。這就可以使用垂直分割。我們可以把題目單獨放到一張表中,通過id與tt表建立一對一的關系,同樣將回答單獨放到一張表中。這樣我們插敘tt中的分數的時候就不會掃描題目和回答了。3,其他要點:1)存放圖片、文件等大文件用文件系統存儲。數據庫只存儲路徑,圖片和文件存放在文件系統,甚至單獨存放在一臺服務器(圖床)。2)數據參數配置。最重要的參數就是內存,我們主要用的innodb引擎,所以下面兩個參數調的很大:innodb_additional_mem_pool_size=64Minnodb_buffer_pool_size=1G對于MyISAM,需要調整key_buffer_size,當然調整參數還是要看狀態,用show status語句可以看到當前狀態,以決定該調整哪些參數。4,合理的硬件資源和操作系統如果機器的內存超過4G,那么應當采用64位操作系統和64位MySQL。案例:簡單購物系統暫設涉及如下表:1.產品表(數據量10w,穩定)2.訂單表(數據量200w,且有增長趨勢)3.用戶表 (數據量100w,且有增長趨勢)以mysql為例講述下水平拆分和垂直拆分,mysql能容忍的數量級在百萬靜態數據可以到千萬垂直拆分:解決問題:表與表之間的io競爭不解決問題:單表中數據量增長出現的壓力方案:把產品表和用戶表放到一個server上訂單表單獨放到一個server上水平拆分:解決問題:單表中數據量增長出現的壓力不解決問題:表與表之間的io爭奪方案:用戶表通過性別拆分為男用戶表和女用戶表訂單表通過已完成和完成中拆分為已完成訂單和未完成訂單產品表 未完成訂單放一個server上已完成訂單表盒男用戶表放一個server上女用戶表放一個server上 ----------------------------------------------------------------------------- 目前很多互聯網系統都存在單表數據量過大的問題,這就降低了查詢速度,影響了客戶體驗。為了提高查詢速度,我們可以優化sql語句,優化表結構和索引,不過對那些百萬級千萬級的數據庫表,即便是優化過后,查詢速度還是滿足不了要求。這時候我們就可以通過分表降低單次查詢數據量,從而提高查詢速度,一般分表的方式有兩種:水平拆分和垂直拆分,兩者各有利弊,適用于不同的情況。水平拆分 水平拆分是指數據表行的拆分,表的行數超過200萬行時,就會變慢,這時可以把一張的表的數據拆成多張表來存放。 這里寫圖片描述 這里寫圖片描述 通常情況下,我們使用取模的方式來進行表的拆分;比如一張有400W的用戶表users,為提高其查詢效率我們把其分成4張表users1,users2,users3,users4 通過用ID取模的方法把數據分散到四張表內Id%4+1 = [1,2,3,4] 然后查詢,更新,刪除也是通過取模的方法來查詢。例:QQ的登錄表。假設QQ的用戶有100億,如果只有一張表,每個用戶登錄的時候數據庫都要從這100億中查找,會很慢很慢。如果將這一張表分成100份,每張表有1億條,就小了很多,比如qq0,qq1,qq1…qq99表。用戶登錄的時候,可以將用戶的id%100,那么會得到0-99的數,查詢表的時候,將表名qq跟取模的數連接起來,就構建了表名。比如123456789用戶,取模的89,那么就到qq89表查詢,查詢的時間將會大大縮短。另外部分業務邏輯也可以通過地區,年份等字段來進行歸檔拆分;進行拆分后的表,只能滿足部分查詢的高效查詢需求,這時我們就要在產品策劃上,從界面上約束用戶查詢行為。比如我們是按年來進行歸檔拆分的,這個時候在頁面設計上就約束用戶必須要先選擇年,然后才能進行查詢;在做分析或者統計時,由于是自己人的需求,多點等待其實是沒關系的,并且并發很低,這個時候可以用union把所有表都組合成一張視圖來進行查詢,然后再進行查詢。水平拆分的優點: ◆表關聯基本能夠在數據庫端全部完成; ◆不會存在某些超大型數據量和高負載的表遇到瓶頸的問題; ◆應用程序端整體架構改動相對較少; ◆事務處理相對簡單; ◆只要切分規則能夠定義好,基本上較難遇到擴展性限制;水平切分的缺點: ◆切分規則相對更為復雜,很難抽象出一個能夠滿足整個數據庫的切分規則; ◆后期數據的維護難度有所增加,人為手工定位數據更困難; ◆應用系統各模塊耦合度較高,可能會對后面數據的遷移拆分造成一定的困難。垂直拆分 垂直拆分是指數據表列的拆分,把一張列比較多的表拆分為多張表。表的記錄并不多,但是字段卻很長,表占用空間很大,檢索表的時候需要執行大量的IO,嚴重降低了性能。這時需要把大的字段拆分到另一個表,并且該表與原表是一對一的關系。 這里寫圖片描述 這里寫圖片描述通常我們按以下原則進行垂直拆分: 1,把不常用的字段單獨放在一張表;, 2,把text,blob等大字段拆分出來放在附表中; 3,經常組合查詢的列放在一張表中;例如學生答題表tt:有如下字段: Id name 分數 題目 回答 其中題目和回答是比較大的字段,id name 分數比較小。如果我們只想查詢id為8的學生的分數:select 分數 from tt where id = 8;雖然知識查詢分數,但是題目和回答這兩個大字段也是要被掃描的,很消耗性能。但是我們只關心分數,并不想查詢題目和回答。這就可以使用垂直分割。我們可以把題目單獨放到一張表中,通過id與tt表建立一對一的關系,同樣將回答單獨放到一張表中。這樣我們插敘tt中的分數的時候就不會掃描題目和回答了。垂直切分的優點 ◆ 數據庫的拆分簡單明了,拆分規則明確; ◆ 應用程序模塊清晰明確,整合容易; ◆ 數據維護方便易行,容易定位;垂直切分的缺點 ◆ 部分表關聯無法在數據庫級別完成,需要在程序中完成; ◆ 對于訪問極其頻繁且數據量超大的表仍然存在性能平靜,不一定能滿足要求; ◆ 事務處理相對更為復雜; ◆ 切分達到一定程度之后,擴展性會遇到限制; ◆ 過讀切分可能會帶來系統過渡復雜而難以維護。 ----------------------------------------------------------------------- 數據庫垂直拆分 水平拆分當我們使用讀寫分離、緩存后,數據庫的壓力還是很大的時候,這就需要使用到數據庫拆分了。數據庫拆分簡單來說,就是指通過某種特定的條件,按照某個維度,將我們存放在同一個數據庫中的數據分散存放到多個數據庫(主機)上面以達到分散單庫(主機)負載的效果。 切分模式: 垂直(縱向)拆分、水平拆分。垂直拆分專庫專用一個數據庫由很多表的構成,每個表對應著不同的業務,垂直切分是指按照業務將表進行分類,分布到不同的數據庫上面,這樣也就將數據或者說壓力分擔到不同的庫上面,如下圖:優點:1. 拆分后業務清晰,拆分規則明確。2. 系統之間整合或擴展容易。3. 數據維護簡單。缺點:1. 部分業務表無法join,只能通過接口方式解決,提高了系統復雜度。2. 受每種業務不同的限制存在單庫性能瓶頸,不易數據擴展跟性能提高。3. 事務處理復雜。水平拆分垂直拆分后遇到單機瓶頸,可以使用水平拆分。相對于垂直拆分的區別是:垂直拆分是把不同的表拆到不同的數據庫中,而水平拆分是把同一個表拆到不同的數據庫中。相對于垂直拆分,水平拆分不是將表的數據做分類,而是按照某個字段的某種規則來分散到多個庫之中,每個表中包含一部分數據。簡單來說,我們可以將數據的水平切分理解為是按照數據行的切分,就是將表中 的某些行切分到一個數據庫,而另外的某些行又切分到其他的數據庫中,主要有分表,分庫兩種模式,如圖:優點:1. 不存在單庫大數據,高并發的性能瓶頸。2. 對應用透明,應用端改造較少。 3. 按照合理拆分規則拆分,join操作基本避免跨庫。4. 提高了系統的穩定性跟負載能力。缺點:1. 拆分規則難以抽象。2. 分片事務一致性難以解決。3. 數據多次擴展難度跟維護量極大。4. 跨庫join性能較差。拆分的處理難點兩張方式共同缺點1. 引入分布式事務的問題。2. 跨節點Join 的問題。3. 跨節點合并排序分頁問題。針對數據源管理,目前主要有兩種思路:A. 客戶端模式,在每個應用程序模塊中配置管理自己需要的一個(或者多個)數據源,直接訪問各個 數據庫,在模塊內完成數據的整合。 優點:相對簡單,無性能損耗。 缺點:不夠通用,數據庫連接的處理復雜,對業務不夠透明,處理復雜。B. 通過中間代理層來統一管理所有的數據源,后端數據庫集群對前端應用程序透明; 優點:通用,對應用透明,改造少。 缺點:實現難度大,有二次轉發性能損失。拆分原則1. 盡量不拆分,架構是進化而來,不是一蹴而就。(SOA)2. 最大可能的找到最合適的切分維度。3. 由于數據庫中間件對數據Join 實現的優劣難以把握,而且實現高性能難度極大,業務讀取 盡量少使用多表Join -盡量通過數據冗余,分組避免數據垮庫多表join。4. 盡量避免分布式事務。5. 單表拆分到數據1000萬以內。切分方案范圍、枚舉、時間、取模、哈希、指定等案例分析場景一 建立一個歷史his系統,將公司的一些歷史個人游戲數據保存到這個his系統中,主要是寫入,還有部分查詢,讀寫比約為1:4;由于是所有數據的歷史存取,所以并發要求比較高; 分析: 歷史數據 寫多都少 越近日期查詢越頻繁? 什么業務數據?用戶游戲數據 有沒有大規模分析查詢? 數據量多大? 保留多久? 機器資源有多少?方案1:按照日期每月一個分片 帶來的問題:1.數據熱點問題(壓力不均勻)方案2:按照用戶取模, --by Jerome 就這個比較合適了 帶來的問題:后續擴容困難方案3:按用戶ID范圍分片(1-1000萬=分片1,xxx) 帶來的問題:用戶活躍度無法掌握,可能存在熱點問題場景二 建立一個商城訂單系統,保存用戶訂單信息。分析: 電商系統 一號店或京東類?淘寶或天貓? 實時性要求高 存在瞬時壓力 基本不存在大規模分析 數據規模? 機器資源有多少? 維度?商品?用戶?商戶?方案1:按照用戶取模, 帶來的問題:后續擴容困難方案2:按用戶ID范圍分片(1-1000萬=分片1,xxx) 帶來的問題:用戶活躍度無法掌握,可能存在熱點問題方案3:按省份地區或者商戶取模 數據分配不一定均勻場景3 上海公積金,養老金,社保系統分析: 社保系統 實時性要求不高 不存在瞬時壓力 大規模分析? 數據規模大 數據重要不可丟失 偏于查詢?方案1:按照用戶取模, 帶來的問題:后續擴容困難方案2:按用戶ID范圍分片(1-1000萬=分片1,xxx) 帶來的問題:用戶活躍度無法掌握,可能存在熱點問題方案3:按省份區縣地區枚舉 數據分配不一定均勻數據庫問題解決后,應用面對的新挑戰就是拆分應用等參考Mycat在線視頻培訓【鏈接:http://pan.baidu.com/s/1nuR26rZ 密碼:1gr9 (2015)】大型網站系統與Java中間件實踐.pdfMySQL數據庫的演化可以參考: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【一分鐘掌握數據庫垂直拆分-沈劍】垂直拆分垂直拆分就是要把表按模塊劃分到不同數據庫表中(當然原則還是不破壞第三范式),這種拆分在大型網站的演變過程中是很常見的。當一個網站還在很小的時候,只有小量的人來開發和維護,各模塊和表都在一起,當網站不斷豐富和壯大的時候,也會變成多個子系統來支撐,這時就有按模塊和功能把表劃分出來的需求。其實,相對于垂直切分更進一步的是服務化改造,說得簡單就是要把原來強耦合的系統拆分成多個弱耦合的服務,通過服務間的調用來滿足業務需求看,因此表拆出來后要通過服務的形式暴露出去,而不是直接調用不同模塊的表,淘寶在架構不斷演變過程,最重要的一環就是服務化改造,把用戶、交易、店鋪、寶貝這些核心的概念抽取成獨立的服務,也非常有利于進行局部的優化和治理,保障核心模塊的穩定性垂直拆分:單表大數據量依然存在性能瓶頸水平拆分上面談到垂直切分只是把表按模塊劃分到不同數據庫,但沒有解決單表大數據量的問題,而水平切分就是要把一個表按照某種規則把數據劃分到不同表或數據庫里。例如像計費系統,通過按時間來劃分表就比較合適,因為系統都是處理某一時間段的數據。而像SaaS應用,通過按用戶維度來劃分數據比較合適,因為用戶與用戶之間的隔離的,一般不存在處理多個用戶數據的情況,簡單的按user_id范圍來水平切分通俗理解:水平拆分行,行數據拆分到不同表中, 垂直拆分列,表數據拆分到不同表中垂直與水平聯合切分由上面可知垂直切分能更清晰化模塊劃分,區分治理,水平切分能解決大數據量性能瓶頸問題,因此常常就會把兩者結合使用,這在大型網站里是種常見的策略案例:以mysql為例,簡單購物系統暫設涉及如下表:1.產品表(數據量10w,穩定)2.訂單表(數據量200w,且有增長趨勢)3.用戶表 (數據量100w,且有增長趨勢)以mysql為例講述下水平拆分和垂直拆分,mysql能容忍的數量級在百萬靜態數據可以到千萬垂直拆分:解決問題:表與表之間的io競爭不解決問題:單表中數據量增長出現的壓力方案:把產品表和用戶表放到一個server上訂單表單獨放到一個server上水平拆分:解決問題:單表中數據量增長出現的壓力不解決問題:表與表之間的io爭奪方案:用戶表通過性別拆分為男用戶表和女用戶表訂單表通過已完成和完成中拆分為已完成訂單和未完成訂單產品表 未完成訂單放一個server上已完成訂單表盒男用戶表放一個server上女用戶表放一個server上(女的愛購物)《大型網站系統與Java中間件實踐》本書圍繞大型網站和支撐大型網站架構的 Java 中間件的實踐展開介紹。從分布式系統的知識切入,讓讀者對分布式系統有基本的了解;然后介紹大型網站隨著數據量、訪問量增長而發生的架構變遷;接著講述構建 Java 中間件的相關知識;之后的幾章都是根據筆者的經驗來介紹支撐大型網站架構的 Java 中間件系統的設計和實踐。本節為大家介紹專庫專用,數據垂直拆分。AD: 51CTO 網+ 第十二期沙龍:大話數據之美_如何用數據驅動用戶體驗2.2.7 讀寫分離后,數據庫又遇到瓶頸通過讀寫分離以及在某些場景用分布式存儲系統替換關系型數據庫的方式,能夠降低主庫的壓力,解決數據存儲方面的問題。不過隨著業務的發展,我們的主庫也會遇到瓶頸。我們的網站演進到現在,交易、商品、用戶的數據還都在一個數據庫中。盡管采取了增加緩存、讀寫分離的方式,這個數據庫的壓力還是在繼續增加,因此我們需要去解決這個問題,我們有數據垂直拆分和水平拆分兩種選擇。2.2.7.1 專庫專用,數據垂直拆分垂直拆分的意思是把數據庫中不同的業務數據拆分到不同的數據庫中。結合現在的例子,就是把交易、商品、用戶的數據分開,如圖2-20 所示。這樣的變化給我們帶來的影響是什么呢?應用需要配置多個數據源,這就增加了所需的配置,不過帶來的是每個數據庫連接池的隔離。不同業務的數據從原來的一個數據庫中拆分到了多個數據庫中,那么就需要考慮如何處理原來單機中跨業務的事務。一種辦法是使用分布式事務,其性能要明顯低于之前的單機事務;而另一種辦法就是去掉事務或者不去追求強事務支持,則原來在單庫中可以使用的表關聯的查詢也就需要改變實現了。對數據進行垂直拆分之后,解決了把所有業務數據放在一個數據庫中的壓力問題。并且也可以根據不同業務的特點進行更多優化。2.2.7.2 垂直拆分后的單機遇到瓶頸,數據水平拆分與數據垂直拆分對應的還有數據水平拆分。數據水平拆分就是把同一個表的數據拆到兩個數據庫中。產生數據水平拆分的原因是某個業務的數據表的數據量或者更新量達到了單個數據庫的瓶頸,這時就可以把這個表拆到兩個或者多個數據庫中。數據水平拆分與讀寫分離的區別是,讀寫分離解決的是讀壓力大的問題,對于數據量大或者更新量的情況并不起作用。數據水平拆分與數據垂直拆分的區別是,垂直拆分是把不同的表拆到不同的數據庫中,而水平拆分是把同一個表拆到不同的數據庫中。例如,經過垂直拆分后,用戶表與交易表、商品表不在一個數據庫中了,如果數據量或者更新量太大,我們可以進一步把用戶表拆分到兩個數據庫中,它們擁有結構一模一樣的用戶表,而且每個庫中的用戶表都只涵蓋了一部分的用戶,兩個數據庫的用戶合在一起就相當于沒有拆分之前的用戶表。我們先來簡單看一下引入數據水平拆分后的結構,如圖2-21 所示。我們來分析一下水平拆分后給業務應用帶來的影響。首先,訪問用戶信息的應用系統需要解決SQL 路由的問題,因為現在用戶信息分在了兩個數據庫中,需要在進行數據庫操作時了解需要操作的數據在哪里。此外,主鍵的處理也會變得不同。原來依賴單個數據庫的一些機制需要變化,例如原來使用Oracle 的Sequence 或者MySQL 表上的自增字段的,現在不能簡單地繼續使用了。并且在不同的數據庫中也不能直接使用一些數據庫的限制來保證主鍵不重復了。最后,由于同一個業務的數據被拆分到了不同的數據庫中,因此一些查詢需要從兩個數據庫中取數據,如果數據量太大而需要分頁,就會比較難處理了。不過,一旦我們能夠完成數據的水平拆分,我們將能夠很好地應對數據量及寫入量增長的情況。具體如何完成數據水平拆分,在后面分布式數據訪問層的章節中我們將進行更加詳細的介紹。2.2.8 數據庫問題解決后,應用面對的新挑戰2.2.8.1 拆分應用前面所講的讀寫分離、分布式存儲、數據垂直拆分和數據水平拆分都是在解決數據方面的問題。下面我們來看看應用方面的變化。之前解決了應用服務器從單機到多機的擴展,應用就可以在一定范圍內水平擴展了。隨著業務的發展,應用的功能會越來越多,應用也會越來越大。我們需要考慮如何不讓應用持續變大,這就需要把應用拆開,從一個應用變為兩個甚至多個應用。我們來看兩種方式。第一種方式,根據業務的特性把應用拆開。在我們的例子中,主要的業務功能分為三大部分:交易、商品和用戶。我們可以把原來的一個應用拆成分別以交易和商品為主的兩個應用,對于交易和商品都會有涉及用戶的地方,我們讓這兩個系統自己完成涉及用戶的工作,而類似用戶注冊、登錄等基礎的用戶工作,可以暫時交給兩系統之一來完成(注意,我們在這里主要是通過例子說明拆分的做法),如圖2-22 所示,這樣的拆分可以使大的應用變小。我們還可以按照用戶注冊、用戶登錄、用戶信息維護等再拆分,使之變成三個系統。不過,這樣拆分后在不同系統中會有一些相似的代碼,例如用戶相關的代碼。如何能夠保證這部分代碼的一致以及如何對其復用是需要解決的問題。此外,按這樣的方式拆分出來的新系統之間一般沒有直接的相互調用。而且,新拆出來的應用可能會連接同樣的數據庫。來看一個具體的例子,如圖2-23 所示。我們根據業務的不同功能拆分了幾個業務應用,而且這些業務應用之間不存在直接的調用,它們都依賴底層的數據庫、緩存、文件系統、搜索等。這樣的應用拆分確實能夠解決當下的一些問題,不過也有一些缺點。 2.2.8.2 走服務化的路我們再來看一下服務化的做法。圖2-24 是一個示意圖。從中可以看到我們把應用分為了三層,處于最上端的是Web 系統,用于完成不同的業務功能;處于中間的是一些服務中心,不同的服務中心提供不同的業務服務;處于下層的則是業務的數據庫。當然,我們在這個圖中省去了緩存等基礎的系統,因此可以說是服務化系統結構的一個簡圖。圖2-24 與之前的圖相比有幾個很重要的變化。首先,業務功能之間的訪問不僅是單機內部的方法調用了,還引入了遠程的服務調用。其次,共享的代碼不再是散落在不同的應用中了,這些實現被放在了各個服務中心。第三,數據庫的連接也發生了一些變化,我們把與數據庫的交互工作放到了服務中心,讓前端的Web 應用更加注重與瀏覽器交互的工作,而不必過多關注業務邏輯的事情。連接數據庫的任務交給相應的業務服務中心了,這樣可以降低數據庫的連接數。而服務中心不僅把一些可以共用的之前散落在各個業務的代碼集中了起來,并且能夠使這些代碼得到更好的維護。第四,通過服務化,無論是前端Web 應用還是服務中心,都可以是由固定小團隊來維護的系統,這樣能夠更好地保持穩定性,并能更好地控制系統本身的發展,況且穩定的服務中心日常發布的次數也遠小于前端Web 應用,因此這個方式也減小了不穩定的風險。要做到服務化還需要一些基礎組件的支撐,在后面服務框架的章節我們會具體介紹。通過某種特定的條件,將存放在同一個數據庫中的數據分散存放到多個數據庫上,實現分布存儲,通過路由規則路由訪問特定的數據庫,這樣一來每次訪問面對的就不是單臺服務器了,而是N臺服務器,這樣就可以降低單臺機器的負載壓力。提示:sqlserver 2005版本之后,可以友好的支持“表分區”。垂直(縱向)拆分:是指按功能模塊拆分,比如分為訂單庫、商品庫、用戶庫...這種方式多個數據庫之間的表結構不同。水平(橫向)拆分:將同一個表的數據進行分塊保存到不同的數據庫中,這些數據庫中的表結構完全相同。SQL Server:數據庫/數據表 拆分 ▲(縱向拆分)SQL Server:數據庫/數據表 拆分 ▲(橫向拆分)1,實現原理:使用垂直拆分,主要要看應用類型是否合適這種拆分方式,如系統可以分為,訂單系統,商品管理系統,用戶管理系統業務系統比較明的,垂直拆分能很好的起到分散數據庫壓力的作用。業務模塊不明晰,耦合(表關聯)度比較高的系統不適合使用這種拆分方式。但是垂直拆分方式并不能徹底解決所有壓力問題,例如 有一個5000w的訂單表,操作起來訂單庫的壓力仍然很大,如我們需要在這個表中增加(insert)一條新的數據,insert完畢后,數據庫會針對這張表重新建立索引,5000w行數據建立索引的系統開銷還是不容忽視的,反過來,假如我們將這個表分成100個table呢,從table_001一直到table_100,5000w行數據平均下來,每個子表里邊就只有50萬行數據,這時候我們向一張只有50w行數據的table中insert數據后建立索引的時間就會呈數量級的下降,極大了提高了DB的運行時效率,提高了DB的并發量,這種拆分就是橫向拆分2,實現方法:垂直拆分,拆分方式實現起來比較簡單,根據表名訪問不同的數據庫就可以了。橫向拆分的規則很多,這里總結前人的幾點,(1)順序拆分:如可以按訂單的日前按年份才分,2003年的放在db1中,2004年的db2,以此類推。當然也可以按主鍵標準拆分。優點:可部分遷移缺點:數據分布不均,可能2003年的訂單有100W,2008年的有500W。(2)hash取模分: 對user_id進行hash(或者如果user_id是數值型的話直接使用user_id的值也可),然后用一個特定的數字,比如應用中需要將一個數據庫切分成4個數據庫的話,我們就用4這個數字對user_id的hash值進行取模運算,也就是user_id%4,這樣的話每次運算就有四種可能:結果為1的時候對應DB1;結果為2的時候對應DB2;結果為3的時候對應DB3;結果為0的時候對應DB4,這樣一來就非常均勻的將數據分配到4個DB中。優點:數據分布均勻缺點:數據遷移的時候麻煩;不能按照機器性能分攤數據 。(3)在認證庫中保存數據庫配置就是建立一個DB,這個DB單獨保存user_id到DB的映射關系,每次訪問數據庫的時候都要先查詢一次這個數據庫,以得到具體的DB信息,然后才能進行我們需要的查詢操作。優點:靈活性強,一對一關系缺點:每次查詢之前都要多一次查詢,會造成一定的性能損失。------------------------------------------------------------------------------ mysql數據庫的水平拆分與垂直拆分 近端時間在面試,發現很多面試官或者面試都把數據的水平拆分合垂直拆分給搞混了,今天特意寫了一篇博客來說說水平拆分和垂直拆分希望對程序猿們有所幫助。數據庫水平與垂直拆分:垂直(縱向)拆分:是指按功能模塊拆分,比如分為訂單庫、商品庫、用戶庫...這種方式多個數據庫之間的表結構不同。水平(橫向)拆分:將同一個表的數據進行分塊保存到不同的數據庫中,這些數據庫中的表結構完全相同。數據表的水平與垂直拆分:垂直拆分:按字段功能主次拆分,比如最常見的商品表、商品圖片表、商品詳細信息...表與表之間的結構不同水平拆分:同數據庫的水平拆分原理一樣主要是將數據進行拆分保存到不同的表當中,這些表的結構完全相同。、使用用垂直拆分要主要看系統是否適合這種拆分方式,如系統可分為用戶系統,商品系統、訂單系統等這些業務比較明確的比較適合使用垂直拆分,垂直拆分能很好分散數據庫壓力。業務模塊不清晰,模塊耦合度較高的系統并不適合垂直拆分。垂直拆分并不能徹底解決所有的壓力問題,例如有一張8000w的訂單表而且訂單隨著時間還在一直增加,操作起這張訂單表壓力依然很大,如我們需要在這個表中增加(insert)一條新的數據,insert完畢后,數據庫會針對這張表重新建立索引,8000w行數據建立索引的系統開銷還是不容忽視的,這類情況就可以使用到水平拆分了,可以將表分成100個table,table_001一直到table_100,8000w數據平均分下來就是80萬的數據(經過實際測試mysql數據量達到400w的時候性能明顯降低,故而應將單個mysql的數據量控制在300W以內),這時候我們向一張只有80w行數據的table中insert數據后建立索引的時間就會呈數量級的下降,極大了提高了DB的運行時效率,提高了DB的并發量,這種拆分就是水平(橫向)拆分數據庫拆的實現方式:垂直拆分,拆分方式實現起來比較簡單,根據表名訪問不同的數據庫就可以了這里不多講。橫向拆分的規則很多,這里總結了以下幾點:1、順序拆分:例如訂單表可以按訂單的日期按年份才分,2016年的放在db1中,2017年的db2,以此類推。當然也可以按主鍵標準拆分。優點:可部分遷移缺點:數據分布不均,可能2016年的訂單有200W,2017年的有800W。2、hash取模分: 例如訂單表對user_id進行hash(或者如果user_id是數值型的話直接使用user_id的值也可),然后用一個特定的數字,比如應用中需要將一個數據庫切分成4個數據庫的話,我們就用4這個數字對user_id的hash值進行取模運算,也就是user_id%4,這樣的話每次運算就有四種可能:結果為1的時候對應DB1;結果為2的時候對應DB2;結果為3的時候對應DB3;結果為0的時候對應DB4,這樣一來就非常均勻的將數據分配到4個DB中。優點:數據分布均勻缺點:數據遷移的時候麻煩;不能按照機器性能分攤數據 。3、在認證庫中保存數據庫配置,就是建立一個DB,這個DB單獨保存user_id到DB的映射關系,每次訪問數據庫的時候都要先查詢一次這個數據庫,以得到具體的DB信息,然后才能進行我們需要的查詢操作。優點:靈活性強,一對一關系缺點:每次查詢之前都要多一次查詢,會造成一定的性能損失。ps:暫時只想到這些希望對大家有幫助,如果有更好的方法歡迎留言區評論交流 ----------------------------------------------------------------------------

oracle表分區

oracle表分區詳解(按天、按月、按年等)分區表的概念:當表中的數據量不斷增大,查詢數據的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區。表進行分區后,邏輯上表仍然是一張完整的表,只是將表中的數據在物理上存放到多個表空間(物理文件上),這樣查詢數據時,不至于每次都掃描整張表。分區表的優點:1) 改善查詢性能:對分區對象的查詢可以僅搜索自己關心的分區,提高檢索速度。2) 增強可用性:如果表的某個分區出現故障,表在其他分區的數據仍然可用;3) 維護方便:如果表的某個分區出現故障,需要修復數據,只修復該分區即可;4) 均衡I/O:可以把不同的分區映射到磁盤以平衡I/O,改善整個系統性能。分區表的種類:1.范圍分區 概念: 范圍分區將數據基于范圍映射到每一個分區,這個范圍是你在創建分區時指定的分區鍵決定的。這種分區方式是最為常用的,并且分區鍵經常采用日期。舉個例子:你可能會將銷售數據按照月份進行分區。-- 按行分區 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.-- 按時間分區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分區概念: 對于那些無法有效劃分范圍的表,可以使用hash分區,這樣對于提高性能還是會有一定的幫助。hash分區會將表中的數據平均分配到你指定的幾個分區中,列所在分區是依據分區列的hash值自動分配,因此你并不能控制也不知道哪條記錄會被放到哪個分區中,hash分區也可以支持多個依賴列。注意: hash分區最主要的機制是根據hash算法來計算具體某條紀錄應該插入到哪個分區中,hash算法中最重要的是hash函數,Oracle中如果你要使用hash分區,只需指定分區的數量即可。建議分區的數量采用2的n次方,這樣可以使得各個分區間數據分布更加均勻。--按hash分區 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分區概念: List分區也需要指定列的值,其分區值必須明確指定,該分區列只能有一個,不能像range或者hash分區那樣同時指定多個列做為分區依賴列,但它的單個分區對應值可以是多個。注意: 在分區時必須確定分區列可能存在的值,一旦插入的列值不在分區范圍內,則插入/更新就會失敗,因此通常建議使用list分區時,要創建一個default分區存儲那些不在指定范圍內的記錄,類似range分區中的maxvalue分區。-- 按list分區 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. 組合分區Oracle10g提供兩種分區組合 – 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 中虛擬列來實現。在11g之前 分區表的partition key必須是物理存在的。11g開始提供了虛擬列,并且可以作為partition key 。 --按星期分區 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類型分區表,可以根據加載數據,自動創建指定間隔的分區。創建按月分區的分區表:a. 創建分區表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分區表是沒有把所有的分區寫完成,在插入相關數據后會自動生成分區 b. 查看現在表的分區: SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY7'; TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVALPART PART1 INTERVALPART PART2 c. 插入測試數據: 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()函數獲取前一個月或者下一個月的月份, 參數中 負數 代表 往前, 正數 代表 往后。 --上一個月 select to_char(add_months(trunc(sysdate),-1),'yyyymm') from dual; --下一個月 select to_char(add_months(trunc(sysdate),1),'yyyymm') from dual; d. 觀察自動創建的分區: 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.下面創建一個以天為間隔的分區表:1. 創建分區表: 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. 查看表分區: SQL> select table_name,partition_name from user_tab_partitions where table_name='INTERVAL_ANDY8';TABLE_NAME PARTITION_NAME ------------------------------ ------------------------------ INTERVAL_ANDY8 P201411013. 插入測試數據: 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. 觀察自動創建的分區: 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分區技術提高查詢效率 概述: 當表中的數據量不斷增大,查詢數據的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區。表進行分區后,邏輯上表仍然是一張完整的表,只是將表中的數據在物理上存放到多個表空間(物理文件上),這樣查詢數據時,不至于每次都掃描整張表。下面介紹如何使用分區增加查詢效率range分區:就是區域分區復制代碼 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 ) 復制代碼 查看分區語法:select * from user_tab_partitions; --查詢所有分區情況,可以接條件where table_name='sale'查看分區表結構select * from sale partition(p1); --查詢某表的某一分區數據分區后,新增數據的SALE_COUNT字段如果小于1000就存儲到P1分區中,如果1000到2000存儲到P2分區中。但是這時如果我們新增的一條數據的SALE_COUNT字段值大于2000,將無法存儲到表中。我們可以擴展分區,語法如下:alter table sale add partition p4 values less than(maxvalue); --大于2000的都會存到此分區中,當然也可以增加更多的分區同時可以刪除分區,語法如下:alter table sale drop partition p4; --注意:刪除分區會把分區內已有的數據同時刪除但還存在一個問題,如果現在update分區p1中的SALE_COUNT值為1500,是不會成功的,需要在update前增加以下語句:alter table sale enable row movement; --使其row能移動這樣再update就可以成功了分區索引 分區之后雖然可以提高查詢的效率,但也僅僅是提高了數據的范圍,所以我們在有必要的情況下,需要建立分區索引,從而進一步提高效率。分區索引大體上分為兩大類,一類叫做local,一類叫做global。local:在每個分區上建立索引(一般采用這種方式)global:一種在全局上建立索引,這種方式分不分區都一樣,一般不使用下面進行語法演示:注意:分區上建立的索引一定是分區字段create index idx_count on sale(sale_count) local;--建立分區索引,在sale表的每個分區都建立了索引select * from user_ind_partitions;--查詢所有分區索引情況全局索引global寫法就是把上面的local替換成global,但不會使用有些時候,如果你分區分為0~1000,1000~2000,這時如果說0~1500這個范圍內的數據會被頻繁查詢,1500之后查詢很少,那么就可以使用這種自定義的全局索引方式對0~1500建立索引,之后的設置maxvalue即可,語法與分區語法相似global自定義全局索引方式(前綴索引):create index idxname on table(field) globalpartition by range(field) (partition p1 values less than(value), .......partition pN values less than(maxvalue));其他分區介紹 1.hash分區hash分區實現均勻的負載值分配,增加hash分區可以重新分布數據,簡單理解就是分區直接平均分配復制代碼 CREATE TABLE SALE (PRODUCT_ID VARCHAR2(5),SALE_COUNT NUMBER(10,2) ) PARTITION BY HASH (PRODUCT_ID) (PARTITION P1,PARTITION P2 ) 復制代碼 2.list分區該分區的特點是某列的值只有幾個,基于這樣的特點我們可以采用列表分區。復制代碼 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.復合分區(用的不多)復制代碼 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) ); 復制代碼 復合分區首先大體上分為三個分區p1,p2,p3,然后每一個分區內部再進行hash分區,分為4份查詢子分區的語句:select * from user_tab_subpartitions where table_name='student';4.間隔分區(工作中常用)是一種分區自動化的分區,可以指定時間間隔進行分區,這是oracle11g的新特性,實際工作中很常用。實際上是由range分區引申的,最終實現了range分區的自動化復制代碼 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') ) 復制代碼 指定時間之前建立一個分區,之后每隔一個月建立一個分區問題:如果我們drop掉了表,那么這個表的分區還存在嗎?答案是存在的,oracle提供了很強大的數據恢復功能,有一個類似回收站的機制,刪除表后,分區以特殊的形式仍然存在user_tab_partitions中,使用purge recyclebin語法后,會清空回收站,使用flashback table 表名 to before drop語句可以恢復刪除的表。 ------------------------------------------------------------------------------------- 當大家遇到小數據的時候,大家可能想著在where后面多加點約束條件;當數據在大點的時候,大家可能就開始考慮給這添加索引了;當大家遇到百萬級千萬級數據的時候,大家就可能開始添加表分區了。so,我就開始了我的分(keng)區(die)之旅。一開始,由于我的這張大表有100多萬數據量,就單單一個存儲過程居然執行了一個多鐘,于是,我便把這張大表改成分區表,并在ID上給這添加索引,優化存儲過程。改成分區表之后,效果果然斐然,從1個多鐘優化到了一分半鐘。可惜啊,好景不長,才過了2天,測試姐姐就把我啦過去看問題,說我的存儲過程把整個過程卡住了,700多萬的數據,存儲過程居然執行了將近4個小時沒執行完,我嘴上笑嘻嘻,心里媽賣批。自己挖的坑,含著淚也要把它搞定。我首先查了下是不是分區表的索引失效了,但經過排查,發現并不是(心中一萬頭草擬馬跑過),然后,我就執行一樂該id下的700多萬數據的存儲過程,果然很慢,難怪他被卡死了,一查下去發現是select語句查詢很慢,奇怪點就在當我用另一個也是擁有700多萬的id數據執行存儲過程的時候,奇跡發現了,居然3分多鐘就完成。為什么同樣是700多萬的數據,一個執行了4個多鐘還沒完成,一個執行了3分多鐘就完成了。抱著疑問,我一步一步排查這個分區表下不同id表有什么區別呢,最終發現執行快的id,在該分區表下global_stats=YES,而另一個的global_stats則=false。于是我查到了以下的信息"分區表里global_stats=YES的全局統計信息是否準確關系到optimizer能否選擇較優的執行計劃,對分區表執行全局統計會不可避免的產生FTS加重系統負擔,尤其對于DW環境里規模較大的分區表而言更是如此。"而global_stats這個代表該分區表是否對該分區進行了統計分析,一般情況下,系統在不知道什么時候都會對這分區就行統計分析的。而對這個分區進行統計分析又包含了兩種方式,非incremental方式,incremental方式,而非incremental方式會進行全量掃描分區表中所有的分區,incremental方式則會增量掃描分區表中的分區。incremental statistics collect正是在這一背景下應運而生,簡單的說incremental statistics collect會實時記錄分區表里每個partition每列值的更新情況,這一信息保存在SYSAUX表空間里,后續根據這一信息在執行全局統計時僅會針對有變化的partition進行statistics collect,并將收集的結果與沒有變化過的partition原有的統計信息進行整合,計算出準確的global stats,省去了必須去掃描每一個partition的步驟。非incremental方式下新加分區后對整個分區表收集統計信息,會全量掃描分區表中所有的分區,即使那些沒有改變過的分區也會被重新掃描一遍 ------------------------------------------------------------------------ 深入學習Oracle分區表及分區索引關于分區表和分區索引(About Partitioned Tables and Indexes)對于10gR2而言,基本上可以分成幾類:?    Range(范圍)分區?    Hash(哈希)分區?    List(列表)分區?    以及組合分區:Range-Hash,Range-List。對于表而言(常規意義上的堆組織表),上述分區形式都可以應用(甚至可以對某個分區指定compress屬性),只不過分區依賴列不能是lob,long之類數據類型,每個表的分區或子分區數的總數不能超過1023個。對于索引組織表,只能夠支持普通分區方式,不支持組合分區,常規表的限制對于索引組織表同樣有效,除此之外呢,還有一些其實的限制,比如要求索引組織表的分區依賴列必須是主鍵才可以等。注:本篇所有示例僅針對常規表,即堆組織表!對于索引,需要區分創建的是全局索引,或本地索引:l 全局索引(global index):即可以分區,也可以不分區。即可以建range分區,也可以建hash分區,即可建于分區表,又可創建于非分區表上,就是說,全局索引是完全獨立的,因此它也需要我們更多的維護操作。l 本地索引(local index):其分區形式與表的分區完全相同,依賴列相同,存儲屬性也相同。對于本地索引,其索引分區的維護自動進行,就是說你add/drop/split/truncate表的分區時,本地索引會自動維護其索引分區。Oracle建議如果單個表超過2G就最好對其進行分區,對于大表創建分區的好處是顯而易見的,這里不多論述why,而將重點放在when以及how。ORACLE對于分區表方式其實就是將表分段存儲,一般普通表格是一個段存 儲,而分區表會分成多個段,所以查找數據過程都是先定位根據查詢條件定位分區范圍,即數據在那個分區或那幾個內部,然后在分區內部去查找數據,一個分區一 般保證四十多萬條數據就比較正常了,但是分區表并非亂建立,而其維護性也相對較為復雜一點,而索引的創建也是有點講究的,這些以下盡量闡述詳細即可。range分區方式,也算是最常用的分區方式,其通過某字段或幾個字段的組合的值,從小到大,按照指定的范圍說明進行分區,我們在INSERT數據的時候就會存儲到指定的分區中。List分區方式,一般是在range基礎上做的二級分區較多,是一種列舉方式進行分區,一般講某些地區、狀態或指定規則的編碼等進行劃分。Hash分區方式,它沒有固定的規則,由ORACLE管理,只需要將值INSERT進去,ORACLE會自動去根據一套HASH算法去劃分分區,只需要告訴ORACLE要分幾個區即可。WHEN一、When使用Range分區Range分區呢是應用范圍比較廣的表分區方式,它是以列的值的范圍來做為分區的劃分條件,將記錄存放到列值所在的range分區中,比如按照 時間劃分,2008年1季度的數據放到a分區,08年2季度的數據放到b分區,因此在創建的時候呢,需要你指定基于的列,以及分區的范圍值,如果某些記錄 暫無法預測范圍,可以創建maxvalue分區,所有不在指定范圍內的記錄都會被存儲到maxvalue所在分區中,并且支持指定多列做為依賴列,后面在 講how的時候會詳細談到。二、When使用Hash分區通常呢,對于那些無法有效劃分范圍的表,可以使用hash分區,這樣對于提高性能還是會有一定的幫助。hash分區會將表中的數據平均分配到你 指定的幾個分區中,列所在分區是依據分區列的hash值自動分配,因此你并不能控制也不知道哪條記錄會被放到哪個分區中,hash分區也可以支持多個依賴 列。三、When使用List分區List分區與range分區和hash分區都有類似之處,該分區與range分區類似的是也需要你指定列的值,但這又不同與range分區的 范圍式列值---其分區值必須明確指定,也不同與hash分區---通過明確指定分區值,你能控制記錄存儲在哪個分區。它的分區列只能有一個,而不能像 range或者hash分區那樣同時指定多個列做為分區依賴列,不過呢,它的單個分區對應值可以是多個。你在分區時必須確定分區列可能存在的值,一旦插入的列值不在分區范圍內,則插入/更新就會失敗,因此通常建議使用list分區時,要創建一個default分區存儲那些不在指定范圍內的記錄,類似range分區中的maxvalue分區。四、When使用組合分區如果某表按照某列分區之后,仍然較大,或者是一些其它的需求,還可以通過分區內再建子分區的方式將分區再分區,即組合分區的方式。組合分區呢在10g中有兩種:range-hash,range-list。注意順序喲,根分區只能是range分區,子分區可以是hash分區或list分區。提示:11g在組合分區功能這塊有所增強,又推出了range-range,list-range,list-list,list-hash, 這就相當于除hash外三種分區方式的笛卡爾形式都有了。為什么會沒有hash做為根分區的組合分區形式呢,再仔細回味一下第二點,你一定能夠想明 白~~。深入學習Oracle分區表及分區索引(2)一、如何創建如果想對某個表做分區,必須在創建表時就指定分區,我們可以對一個包含分區的表中的分區做修改,但不能直接將一個未分區的表修改成分區表(起碼在10g是不行的,當然你可能會說,可以通過在線重定義的方式,但是這不是直接喲,這也是借助臨時表間接實現的)。創建表或索引的語法就不說了,大家肯定比我還熟悉,而想在建表(索引)同時指定分區也非常容易,只需要把創建分區的子句放到";"前就行啦,同 時需要注意表的row movement屬性,它用來控制是否允許修改列值所造成的記錄移動至其它分區存儲,有enable|disable兩種狀態,默認是disable row movement,當disable時,如果記錄要被更新至其它分區,則更新語句會報錯。下面分別演示不同分區方式的表和索引的創建:1、創建range分區語法如下,需要我們指定的有:l column:分區依賴列(如果是多個,以逗號分隔);l partition:分區名稱;l values less than:后跟分區范圍值(如果依賴列有多個,范圍對應值也應是多個,中間以逗號分隔);l tablespace_clause:分區的存儲屬性,例如所在表空間等屬性(可為空),默認繼承基表所在表空間的屬性。① 創建一個標準的range分區表: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);表已創建。要查詢創建分區的信息,可以通過查詢user_part_tables,user_tab_partitions兩個數據字典(索引分區、組織分區等信息也有對應的數據字典,后續示例會逐步提及)。user_part_tables:記錄分區的表的信息;user_tab_partitions:記錄表的分區的信息。例如: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;② 創建global索引range分區: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);索引已創建。由上例可以看出,創建global索引的分區與創建表的分區語句格式完全相同,而且其分區形式與索引所在表的分區形式沒有關聯關系。注意:我們這里借助上面的表t_partition_range來演示創建range分區的global索引,并不表示range分區的表,只能創建range分區的global索引,只要你想,也可以為其創建hash分區的global索引。查詢索引的分區信息可以通過user_part_indexes、user_ind_partitions兩個數據字典:JSSWEB> select index_name, partitioning_type, partition_count2 From user_part_indexes3 where index_name = 'IDX_PARTI_RANGE_ID';③ Local分區索引的創建最簡單,例如:仍然借助t_partition_range表來創建索引--首先刪除之前創建的global索引JSSWEB> drop index IDX_PARTI_RANGE_ID;索引已刪除。JSSWEB> create index IDX_PARTI_RANGE_ID on T_PARTITION_RANGE(id) local;索引已創建。查詢相關數據字典: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索引的分區完全繼承表的分區的屬性,包括分區類型,分區的范圍值即不需指定也不能更改,這就是前面說的:local索引的分區維護完全依賴于其索引所在表。不過呢分區名稱,以及分區所在表空間等信息是可以自定義的,例如: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 );索引已創建。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;創建hash分區語法如下:[圖:hash_partitioning.gif]語法看起來比range復雜,其實使用起來比range更簡單,這里需要我們指定的有:l column:分區依賴列(支持多個,中間以逗號分隔);l partition:指定分區,有兩種方式:n 直接指定分區名,分區所在表空間等信息n 只指定分區數量,和可供使用的表空間。2、創建hash分區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);表已創建。要實現同樣效果,你還可以這樣:JSSWEB> create table t_partition_hash2 (id number,name varchar2(50))2 partition by hash(id)3 partitions 3 store in(tbspart01,tbspart02,tbspart03);表已創建。這就是上面說的,直接指定分區數量和可供使用的表空間。提示:這里分區數量和可供使用的表空間數量之間沒有直接對應關系。分區數并不一定要等于表空間數。要查詢表的分區信息,仍然是通過user_part_tables,user_tab_partitions兩個數據字典,這里不再舉例。① Global索引hash分區Hash分區索引的子句與hash分區表的創建子句完全相同,例如: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);索引已創建。查詢索引的分區信息也仍是通過user_part_indexes、user_ind_partitions兩個數據字典,不再舉例。② 創建Local索引在前面學習range分區時,我們已經對Local索引的特性做了非常清晰的概述,因此這里也不再舉例,如有疑問,建議再仔細復習range分區的相關示例,如果還有疑問,當面問我好了:)綜上:? 對于global索引分區而言,在10g中只能支持range分區和hash分區,因此后續示例中不會再提及。? 對于local索引分區而言,其分區形式完全依賴于索引所在表的分區形式,不管從創建語法還是理解難度均無技術含量,因此后續也不再提供示例。? 注意,在創建索引時如果不顯式指定global或local,則默認是global。? 注意,在創建global索引時如果不顯式指定分區子句,則默認不分區(廢話)。3、分區應用: 一般一張表超過2G的大小,ORACLE是推薦使用分區表的,分區一般都需要 創建索引,說到分區索引,就可以分為:全局索引、分區索引,即:global索引和local索引,前者為默認情況下在分區表上創建索引時的索引方式,并 不對索引進行分區(索引也是表結構,索引大了也需要分區,關于索引以后專門寫點)而全局索引可修飾為分區索引,但是和local索引有所區別,前者的分區 方式完全按照自定義方式去創建,和表結構完全無關,所以對于分區表的全局索引有以下兩幅網上常用的圖解:3.1、對于分區表的不分區索引(這個有點繞,不過就是表分區,但其索引不分區):創建語法(直接創建即可):CREATE INDEX ON ();3.2、對于分區表的分區索引:創建語法為: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索引結構:創建語法為:CREATE INDEX INX_TAB_PARTITION_COL1 ON TABLE_PARTITION(COL1) LOCAL;也可按照分區表的的分區結構給與一一定義,索引的分區將得到重命名。分區上的位圖索引只能為LOCAL索引,不能為GLOBAL全局索引。3.4、對比索引方式:一般使用LOCAL索引較為方便,而且維護代價較低,并且LOCAL索引是在分區的基礎上去創建索引,類似于在一個子表內部去創建索引,這樣開銷主要是區 分分區上,很規范的管理起來,在OLAP系統中應用很廣泛;而相對的GLOBAL索引是全局類型的索引,根據實際情況可以調整分區的類別,而并非按照分區 結構一一定義,相對維護代價較高一些,在OLTP環境用得相對較多,這里所謂OLTP和OLAP也是相對的,不是特殊的項目,沒有絕對的劃分概念,在應用 過程中依據實際情況而定,來提高整體的運行性能。4、常用視圖: 1、查詢當前用戶下有哪些是分區表:SELECT * FROM USER_PART_TABLES;2、查詢當前用戶下有哪些分區索引:SELECT * FROM USER_PART_INDEXES;3、查詢當前用戶下分區索引的分區信息:SELECT * FROM USER_IND_PARTITIONS TWHERE T.INDEX_NAME=?4、查詢當前用戶下分區表的分區信息:SELECT * FROM USER_TAB_PARTITIONS TWHERE T.TABLE_NAME=?;5、查詢某分區下的數據量:SELECT COUNT(*) FROM TABLE_PARTITION PARTITION(TAB_PARTOTION_01);6、查詢索引、表上在那些列上創建了分區:SELECT * FROM USER_PART_KEY_COLUMNS;7、查詢某用戶下二級分區的信息(只有創建了二級分區才有數據):SELECT * FROM USER_TAB_SUBPARTITIONS;5、維護操作: 5.1、刪除分區ALTER TABLE TABLE_PARTITION DROP PARTITION TAB_PARTOTION_03;如果是全局索引,因為全局索引的分區結構和表可以不一致,若不一致的情況下,會導致整個全局索引失效,在刪除分區的時候,語句修改為:ALTER TABLE TABLE_PARTITION DROP PARTITION TAB_PARTOTION_03 UPDATE GLOBAL INDEXES;5.2、分區合并(從中間刪除掉一個分區,或者兩個分區需要合并后減少分區數量)合并分區和刪除中間的RANGE有點像,但是合并分區是不會刪除數據的,對于LIST、HASH分區也是和RANGE分區不一樣的,其語法為:ALTER TABLE TABLE_PARTITION MERGE PARTITIONS TAB_PARTOTION_01,TAB_PARTOTION_02 INTO PARTITION MERGED_PARTITION;5.3、分隔分區(一般分區從擴展分區從分隔) ALTER TABLE TABLE_PARTITION SPLIT PARTITION TAB_PARTOTION_OTHERE AT(2500000)INTO (PARTITION TAB_PARTOTION_05,PARTITION TAB_PARTOTION_OTHERE);5.4、創建新的分區(分區數據若不能提供范圍,則插入時會報錯,需要增加分區來擴大范圍) 一般有擴展分區的是都是用分隔的方式,若上述創建表時沒有創建TAB_PARTOTION_OTHER分區時,在插入數據較大時(按照上述建立規則,超過1800000就應該創建新的分區來存儲),就可以創建新的分區,如:為了試驗,我們將擴展分區先刪除掉再創建新的分區(因為ORACLE要求,分區的數據不允許重疊,即按照分區字段同樣的數據不能同時存儲在不同的分區中):ALTER TABLE TABLE_PARTITION DROP PARTITION TAB_PARTOTION_OTHER;ALTER TABLE TABLE_PARTITION ADD PARTITION TAB_PARTOTION_06 VALUES LESS THAN(2500000);在分區下創建新的子分區大致如下(RANGE分區,若為LIST或HASH分區,將創建方式修改為對應的方式即可):ALTER TABLE MODIFY PARTITION ADD SUBPARTITION VALUES LESS THAN(....);5.5、修改分區名稱(修改相關的屬性信息) ALTER TABLE TABLE_PARTITION RENAME PARTITION MERGED_PARTITION TO MERGED_PARTITION02;5.6、交換分區(快速交換數據,其實是交換段名稱指針)首先創建一個交換表,和原表結構相同,如果有數據,必須符合所交換對應分區的條件:CREATE TABLE TABLE_PARTITION_2AS SELECT * FROM TABLE_PARTITION WHERE 1=2;然后將第一個分區的數據交換出去:ALTER TABLE TABLE_PARTITION EXCHANGE PARTITION TAB_PARTOTION_01WITH TABLE TABLE_PARTITION_2 INCLUDING INDEXES;此時會發現第一個分區的數據和表TABLE_PARTITION_2做了瞬間交換,比TRUNCATE還要快,因為這個過程沒有進行數據轉存,只是段名稱的修改過程,和實際的數據量沒有關系。如果是子分區也可以與外部的表進行交換,只需要將關鍵字修改為:SUBPARTITION 即可。5.7、清空分區數據ALTER TABLE TRUNCATE PARTITION ;ALTER TABLE TRUNCATE subpartition ;6、磁盤碎片壓縮對分區表的某分區進行磁盤壓縮,當對分區內部數據進行了大量的UPDATE、DELETE操作后,一定時間需要進行磁盤壓縮,否則在查詢時,若通過FULL SCAN掃描數據,將會把空塊也會掃描到,對表進行磁盤壓縮需要進行行遷移操作,所以首先需要操作:ALTER TABLE ENABLE ROW MOVEMENT ;對分區表的某分區壓縮語法為:ALTER TABLEmodify partition shrink space;對普通表壓縮:ALTER TABLE shrink space;對于索引也需要進行壓縮,索引也是表:ALTER INDEX shrink space; ---------------------------------------------------------------------------------------- oracle表空間表分區詳解及oracle表分區查詢使用方法(轉+整理) 此文從以下幾個方面來整理關于分區表的概念及操作:1.表空間及分區表的概念 2.表分區的具體作用 3.表分區的優缺點 4.表分區的幾種類型及操作方法 5.對表分區的維護性操作.表空間及分區表的概念 表空間:是一個或多個數據文件的集合,所有的數據對象都存放在指定的表空間中,但主要存放的是表, 所以稱作表空間。 分區表:當表中的數據量不斷增大,查詢數據的速度就會變慢,應用程序的性能就會下降,這時就應該考慮對表進行分區。表進行分區后,邏輯上表仍然是一張完整的表,只是將表中的數據在物理上存放到多個表空間(物理文件上),這樣查詢數據時,不至于每次都掃描整張表。表分區的具體作用 Oracle的表分區功能通過改善可管理性、性能和可用性,從而為各式應用程序帶來了極大的好處。通常,分區可以使某些查詢以及維護操作的性能大大提高。此外,分區還可以極大簡化常見的管理任務,分區是構建千兆字節數據系統或超高可用性系統的關鍵工具。分區功能能夠將表、索引或索引組織表進一步細分為段,這些數據庫對象的段叫做分區。每個分區有自己的名稱,還可以選擇自己的存儲特性。從數據庫管理員的角度來看,一個分區后的對象具有多個段,這些段既可進行集體管理,也可單獨管理,這就使數據庫管理員在管理分區后的對象時有相當大的靈活性。但是,從應用程序的角度來看,分區后的表與非分區表完全相同,使用 SQL DML 命令訪問分區后的表時,無需任何修改。什么時候使用分區表:表的大小超過2GB。 表中包含歷史數據,新的數據被增加都新的分區中。 表分區的優缺點 表分區有以下優點:改善查詢性能:對分區對象的查詢可以僅搜索自己關心的分區,提高檢索速度。 增強可用性:如果表的某個分區出現故障,表在其他分區的數據仍然可用; 維護方便:如果表的某個分區出現故障,需要修復數據,只修復該分區即可; 均衡I/O:可以把不同的分區映射到磁盤以平衡I/O,改善整個系統性能。 缺點:已經存在的表沒有方法可以直接轉化為分區表。但是有幾種方式可以間接完成這個操作,大家可以參考:oracle分區表的建立方法(包含已經存在的表要分區):http://blog.csdn.net/wanglilin/article/details/7177338 表分區的幾種類型及操作方法 范圍分區: 范圍分區將數據基于范圍映射到每一個分區,這個范圍是你在創建分區時指定的分區鍵決定的。這種分區方式是最為常用的,并且分區鍵經常采用日期。舉個例子:你可能會將銷售數據按照月份進行分區。 當使用范圍分區時,請考慮以下幾個規則:1、每一個分區都必須有一個VALUES LESS THEN子句,它指定了一個不包括在該分區中的上限值。分區鍵的任何值等于或者大于這個上限值的記錄都會被加入到下一個高一些的分區中。 2、所有分區,除了第一個,都會有一個隱式的下限值,這個值就是此分區的前一個分區的上限值。 3、在最高的分區中,MAXVALUE被定義。MAXVALUE代表了一個不確定的值。這個值高于其它分區中的任何分區鍵的值,也可以理解為高于任何分區中指定的VALUE LESS THEN的值,同時包括空值。例一:假設有一個CUSTOMER表,表中有數據200000行,我們將此表通過CUSTOMER_ID進行分區,每個分區存儲100000行,我們將每個分區保存到單獨的表空間中,這樣數據文件就可以跨越多個物理磁盤。下面是創建表和分區的代碼,如下: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 ); 列表分區: 該分區的特點是某列的值只有幾個,基于這樣的特點我們可以采用列表分區。例一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 ); ) 散列分區: 這類分區是在列值上使用散列算法,以確定將行放入哪個分區中。當列的值沒有合適的條件時,建議使用散列分區。 散列分區為通過指定分區編號來均勻分布數據的一種分區類型,因為通過在I/O設備上進行散列分區,使得這些分區大小一致。 例一: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分區最主要的機制是根據hash算法來計算具體某條紀錄應該插入到哪個分區中,hash算法中最重要的是hash函數,Oracle中如果你要使用hash分區,只需指定分區的數量即可。建議分區的數量采用2的n次方,這樣可以使得各個分區間數據分布更加均勻。組合范圍散列分區 這種分區是基于范圍分區和列表分區,表首先按某列進行范圍分區,然后再按某列進行列表分區,分區之中的分區被稱為子分區。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 ) ) 復合范圍散列分區: 這種分區是基于范圍分區和散列分區,表首先按某列進行范圍分區,然后再按某列進行散列分區。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) ); 有關表分區的一些維護性操作: 添加分區 以下代碼給SALES表添加了一個P3分區ALTER TABLE SALES ADD PARTITION P3 VALUES LESS THAN(TO_DATE('2003-06-01','YYYY-MM-DD')); 注意:以上添加的分區界限應該高于最后一個分區界限。以下代碼給SALES表的P3分區添加了一個P3SUB1子分區ALTER TABLE SALES MODIFY PARTITION P3 ADD SUBPARTITION P3SUB1 VALUES('COMPLETE'); 刪除分區 以下代碼刪除了P3表分區:ALTER TABLE SALES DROP PARTITION P3; 在以下代碼刪除了P4SUB1子分區:ALTER TABLE SALES DROP SUBPARTITION P4SUB1; 注意:如果刪除的分區是表中唯一的分區,那么此分區將不能被刪除,要想刪除此分區,必須刪除表。截斷分區 截斷某個分區是指刪除某個分區中的數據,并不會刪除分區,也不會刪除其它分區中的數據。當表中即使只有一個分區時,也可以截斷該分區。通過以下代碼截斷分區:ALTER TABLE SALES TRUNCATE PARTITION P2; 通過以下代碼截斷子分區:ALTER TABLE SALES TRUNCATE SUBPARTITION P2SUB2; 合并分區 合并分區是將相鄰的分區合并成一個分區,結果分區將采用較高分區的界限,值得注意的是,不能將分區合并到界限較低的分區。以下代碼實現了P1 P2分區的合并:ALTER TABLE SALES MERGE PARTITIONS P1,P2 INTO PARTITION P2; 拆分分區 拆分分區將一個分區拆分兩個新分區,拆分后原來分區不再存在。注意不能對HASH類型的分區進行拆分。ALTER TABLE SALES SBLIT PARTITION P2 AT(TO_DATE('2003-02-01','YYYY-MM-DD')) INTO (PARTITION P21,PARTITION P22); 接合分區(coalesca) 結合分區是將散列分區中的數據接合到其它分區中,當散列分區中的數據比較大時,可以增加散列分區,然后進行接合,值得注意的是,接合分區只能用于散列分區中。通過以下代碼進行接合分區:ALTER TABLE SALES COALESCA PARTITION; 重命名表分區 以下代碼將P21更改為P2ALTER TABLE SALES RENAME PARTITION P21 TO P2; 相關查詢 -- 跨分區查詢 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) );--查詢表上有多少分區 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--顯示數據庫所有分區表的信息: select * from DBA_PART_TABLES--顯示當前用戶可訪問的所有分區表信息: select * from ALL_PART_TABLES--顯示當前用戶所有分區表的信息: select * from USER_PART_TABLES--顯示表分區信息 顯示數據庫所有分區表的詳細分區信息: select * from DBA_TAB_PARTITIONS--顯示當前用戶可訪問的所有分區表的詳細分區信息: select * from ALL_TAB_PARTITIONS--顯示當前用戶所有分區表的詳細分區信息: select * from USER_TAB_PARTITIONS--顯示子分區信息 顯示數據庫所有組合分區表的子分區信息: select * from DBA_TAB_SUBPARTITIONS--顯示當前用戶可訪問的所有組合分區表的子分區信息: select * from ALL_TAB_SUBPARTITIONS--顯示當前用戶所有組合分區表的子分區信息: select * from USER_TAB_SUBPARTITIONS--顯示分區列 顯示數據庫所有分區表的分區列信息: select * from DBA_PART_KEY_COLUMNS--顯示當前用戶可訪問的所有分區表的分區列信息: select * from ALL_PART_KEY_COLUMNS--顯示當前用戶所有分區表的分區列信息: select * from USER_PART_KEY_COLUMNS--顯示子分區列 顯示數據庫所有分區表的子分區列信息: select * from DBA_SUBPART_KEY_COLUMNS--顯示當前用戶可訪問的所有分區表的子分區列信息: select * from ALL_SUBPART_KEY_COLUMNS--顯示當前用戶所有分區表的子分區列信息: select * from USER_SUBPART_KEY_COLUMNS--怎樣查詢出oracle數據庫中所有的的分區表 select * from user_tables a where a.partitioned='YES'--刪除一個表的數據是 truncate table table_name;--刪除分區表一個分區的數據是 alter table table_name truncate partition p5; --------------------------------------------------------------------------------------

?

總結

以上是生活随笔為你收集整理的数据库表设计、 数据库分层、myslq水平拆分、oracle表分区的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。