NoSQL誕生的原因和優缺點

雲計算背後的祕密:NoSQL誕生的原因和優缺點

我本來一直覺得NoSQL其實很容易理解的,我本身也已經對NoSQL有了非常深入的研究,但是在最近準備YunTable的Chart的時候,發現NoSQL不僅非常博大精深,而且我個人對NoSQL的理解也只是皮毛而已,但我還算是一個“知恥而後勇”的人,所以經過一段時間的學習之後,從本系列第六篇開始,就將和大家聊聊NoSQL,而本篇將主要給大家做一下NoSQL數據庫的綜述。
首先將和大家聊聊爲什麼NoSQL會在關係型數據庫已經非常普及的情況下異軍突起?

誕生的原因
隨着互聯網的不斷髮展,各種類型的應用層出不窮,所以導致在這個雲計算的時代,對技術提出了更多的需求,主要體現在下面這四個方面:

  1. 低延遲的讀寫速度:應用快速地反應能極大地提升用戶的滿意度;
  2. 支撐海量的數據和流量:對於搜索這樣大型應用而言,需要利用PB級別的數據和能應對百萬級的流量;
  3. 大規模集羣的管理:系統管理員希望分佈式應用能更簡單的部署和管理;

龐大運營成本的考量:IT經理們希望在硬件成本、軟件成本和人力成本能夠有大幅度地降低;
目前世界上主流的存儲系統大部分還是採用了關係型數據庫,其主要有一下優點:

1.事務處理—保持數據的一致性;

2.由於以標準化爲前提,數據更新的開銷很小(相同的字段基本上只有一處);

3.可以進行Join等複雜查詢。

雖然關係型數據庫已經在業界的數據存儲方面佔據不可動搖的地位,但是由於其天生的幾個限制,使其很難滿足上面這幾個需求:

  1. 擴展困難:由於存在類似Join這樣多表查詢機制,使得數據庫在擴展方面很艱難;
  2. 讀寫慢:這種情況主要發生在數據量達到一定規模時由於關係型數據庫的系統邏輯非常複雜,使得其非常容易發生死鎖等的併發問題,所以導致其讀寫速度下滑非常嚴重;
  3. 成本高:企業級數據庫的License價格很驚人,並且隨着系統的規模,而不斷上升;
  4. 有限的支撐容量:現有關係型解決方案還無法支撐Google這樣海量的數據存儲;
    業界爲了解決上面提到的幾個需求,推出了多款新類型的數據庫,並且由於它們在設計上和傳統的NoSQL數據庫相比有很大的不同,所以被統稱爲“NoSQL”系列數據庫。總的來說,在設計上,它們非常關注對數據高併發地讀寫和對海量數據的存儲等,與關係型數據庫相比,它們在架構和數據模型方量面做了“減法”,而在擴展和併發等方面做了“加法”。現在主流的NoSQL數據庫有BigTable、Hbase、Cassandra、SimpleDB、CouchDB、MongoDB和Redis等。接下來,將關注NoSQL數據庫到底存在哪些優缺點。

優缺點
在優勢方面,主要體現在下面這三點:

  1. 簡單的擴展:典型例子是Cassandra,由於其架構是類似於經典的P2P,所以能通過輕鬆地添加新的節點來擴展這個集羣;
  2. 快速的讀寫:主要例子有redis,由於其邏輯簡單,而且純內存操作,使得其性能非常出色,單節點每秒可以處理超過10萬次讀寫操作;
  3. 低廉的成本:這是大多數分佈式數據庫共有的特點,因爲主要都是開源軟件,沒有昂貴的License成本;
  4. 但瑕不掩瑜,NoSQL數據庫還存在着很多的不足,常見主要有下面這幾個:

  5. 不提供對SQL的支持:如果不支持SQL這樣的工業標準,將會對用戶產生一定的學習和應用遷移成本;
  6. 支持的特性不夠豐富:現有產品所提供的功能都比較有限,大多數NoSQL數據庫都不支持事務,也不像MS SQL Server和Oracle那樣能提供各種附加功能,比如BI和報表等;
  7. 現有產品的不夠成熟:大多數產品都還處於初創期,和關係型數據庫幾十年的完善不可同日而語;
    上面NoSQL產品的優缺點都是些比較共通的,在實際情況下,每個產品都會根據自己所遵從的數據模型和CAP理念而有所不同,接下來,將給大家介紹NoSQL兩個最重要的概念:數據模型和CAP理念,並在本文最後,對主流的NoSQL數據庫進行分類。

Naresh Kumar是位軟件工程師與熱情的博主,對於編程與新事物擁有極大的興趣,非常樂於與其他開發者和程序員分享技術上的研究成果。近日,Naresh撰文比較了NoSQL與RDBMS,並詳細介紹了他們各自的特點與適用的場景。

NoSQL並不是關係型數據庫管理系統,本文將會介紹NoSQL數據庫與關係型數據庫之間的差別,同時還會討論在何種場景下應該使用NoSQL,何種場景下不應該使用。由於NoSQL還是個相對較新的技術,因此它還面臨着很多挑戰。

時至今日,互聯網上有數以億計的用戶。大數據與雲計算已經成爲很多主要的互聯網應用都在使用或是準備使用的技術,這是因爲互聯網用戶每天都在不斷增長,數據也變得越來越複雜,而且有很多非結構化的數據存在,這是很難通過傳統的關係型數據庫管理系統來處理的。NoSQL技術則能比較好地解決這個問題,它主要用於非結構化的大數據與雲計算上。從這個角度來看,NoSQL是一種全新的數據庫思維方式。

爲何要使用NoSQL數據庫?
1.NoSQL具有靈活的數據模型,可以處理非結構化/半結構化的大數據

現在,我們可以通過Facebook、D&B等第三方輕鬆獲得與訪問數據,如個人用戶信息、地理位置數據、社交圖譜、用戶產生的內容、機器日誌數據以及傳感器生成的數據等。對這些數據的使用正在快速改變着通信、購物、廣告、娛樂以及關係管理的特質。沒有使用這些數據的應用很快就會被用戶所遺忘。開發者希望使用非常靈活的數據庫,能夠輕鬆容納新的數據類型,並且不會被第三方數據提供商內容結構的變化所累。很多新數據都是非結構化或是半結構化的,因此開發者還需要能夠高效存儲這種數據的數據庫。但遺憾的是,關係型數據庫所使用的定義嚴格、基於模式的方式是無法快速容納新的數據類型的,對於非結構化或是半結構化的數據更是無能爲力。NoSQL提供的數據模型則能很好地滿足這種需求。很多應用都會從這種非結構化數據模型中獲益,比如說CRM、ERP、BPM等等,他們可以通過這種靈活性存儲數據而無需修改表或是創建更多的列。這些數據庫也非常適合於創建原型或是快速應用,因爲這種靈活性使得新特性的開發變得非常容易。

2.NoSQL很容易實現可伸縮性(向上擴展與水平擴展)

如果有很多用戶在頻繁且併發地使用你的應用,那麼你就需要考慮可伸縮的數據庫技術而非傳統的RDBMS了。對於關係型技術來說,很多應用開發者會發現動態的可伸縮性是難以實現的,這時就應該考慮切換到NoSQL數據庫上。對於雲應用來說,關係型數據庫一開始是普遍的選擇。然而,在使用過程中卻遇到了越來越多的問題,原因就在於他們是中心化的,向上擴展而非水平擴展的。這使得他們不適合於那些需要簡單且動態可伸縮性的應用。NoSQL數據庫從一開始就是分佈式、水平擴展的,因此非常適合於互聯網應用分佈式的特性。

在三層互聯網架構的Web/應用層上,多年來向上擴展已經成爲默認的擴展方式了。隨着應用使用人數的激增,我們需要添加更多的服務器,性能則是通過負載均衡來實現的,這時的代價與用戶數量成線性比例關係。在NoSQL數據庫之前,數據庫層的默認擴展方式就是向上擴展。爲了支持更多的併發用戶以及存儲更多的數據,你需要越來越好的服務器,更好的CPU、更多的內存、更大的磁盤來維護所有表。然而,好的服務器意味着更加複雜、私有、並且也更加昂貴。這與Web/應用層所使用的便宜的硬件形成了鮮明的對比。

3.動態模式

關係型數據庫需要在添加數據前先定義好模式。比如說,你需要存儲客戶的電話號碼、姓名、地址、城市與州等信息,SQL數據庫需要提前知曉你要存的是什麼。這對於敏捷開發模式來說是場災難,因爲每次完成新特性時,數據庫的模式通常都需要改變。因此,如果在開發過程中想將客戶喜歡的條目加到數據庫中,那就得向表中添加這一列才行,然後要做的就是將整個數據庫遷移到新的模式上。

4.自動分片

由於是結構化的,關係型數據庫通常會垂直擴展,單臺服務器要持有整個數據庫來確保可靠性與數據的持續可用性。這樣做的代價就是非常昂貴、擴展受到限制,並且數據庫基礎設施會成爲失敗點。這個問題的解決方案就是水平擴展,添加服務器而不是爲單臺服務器增加更多的能力。NoSQL數據庫通常都支持自動分片,這意味着他們本質上就會自動在多臺服務器上分發數據,應用甚至都不知道這些事情。數據與查詢負載會自動在多臺服務器上做到平衡,當某臺服務器當機時,它能快速且透明地被替換掉。

5.複製

大多數NoSQL數據庫也支持自動複製,這意味着你可以獲得高可用性與災備恢復功能。從開發者的角度來看,存儲環境本質上是虛擬化的。

NoSQL數據庫面臨的挑戰
1.成熟度

RDBMS系統由來已久。NoSQL擁護者們會說RDBMS的高齡是其衰退的標誌,不過對於大多數CIO來說,RDBMS的成熟讓人放心。對於大多數情況來說,RDBMS系統是穩定且功能豐富的。相比較而言,大多數NoSQL數據庫則還有很多特性有待實現。

2.支持

企業需要的是安心,如果關鍵系統出現了故障,他們可以獲得即時的支持。所有RDBMS廠商都在不遺餘力地提供良好的企業支持。與之相反,大多數NoSQL系統都是開源項目,雖然每種數據庫都有那麼幾家公司提供支持,不過這些公司大多都是小的初創公司,沒有全球支持資源,也沒有oracle、微軟或是IBM那種令人放心的公信力。

3.分析與商業智能

NoSQL數據庫在Web 2.0應用時代開始出現。因此,大多數特性都是面向這些應用的需要的。然而,應用中的數據對於業務來說是有價值的,這種價值遠遠超出了Web應用那種CRUD。企業數據庫中的業務信息可以幫助改進效率並提升競爭力,商業智能對於大中型企業來說是個非常關鍵的IT問題。

4.管理

NoSQL的設計目標是提供零管理的解決方案,不過當今的現實卻離這個目標還相去甚遠。現在的NoSQL需要很多技巧才能用好,並且需要不少人力、物力來維護。

5.專業

全球有很多開發者,每個業務部門都會有熟悉RDBMS概念與編程的人。相反,幾乎每個NoSQL開發者都處於學習模式。這種狀況會隨着時間的流逝而發生改觀。但現在,找到一個有經驗的RDBMS程序員或是管理員要比NoSQL專家容易多了。

結論
NoSQL數據庫正在成爲數據庫領域的重要力量。如果使用恰當,那麼它會帶來很多好處。然而,企業應該非常小心並注意到這些數據庫的限制與問題。

NoSQL這兩年越來越熱,尤其是大型互聯網公司非常熱衷這門技術。根據筆者的經驗,並不是任何場景,NoSQL都要優於關係型數據庫。下面我們來具體聊聊,什麼時候使用NoSQL比較給力:

1) 數據庫表schema經常變化
比如在線商城,維護產品的屬性經常要增加字段,這就意味着ORMapping層的代碼和配置要改,如果該表的數據量過百萬,新增字段會帶來額外開銷(重建索引等)。NoSQL應用在這種場景,可以極大提升DB的可伸縮性,開發人員可以將更多的精力放在業務層。

2)數據庫表字段是複雜數據類型

對於複雜數據類型,比如SQL Sever提供了可擴展性的支持,像xml類型的字段。很多用過的同學應該知道,該字段不管是查詢還是更改,效率非常一般。主要原因是是DB層對xml字段很難建高效索引,應用層又要做從字符流到dom的解析轉換。NoSQL以json方式存儲,提供了原生態的支持,在效率方便遠遠高於傳統關係型數據庫。

3)高併發數據庫請求

此類應用常見於web2.0的網站,很多應用對於數據一致性要求很低,而關係型數據庫的事務以及大表join反而成了”性能殺手”。在高併發情況下,sql與no-sql的性能對比由於環境和角度不同一直是存在爭議的,並不是說在任何場景,no-sql總是會比sql快。有篇article和大家分享下,http://artur.ejsmont.org/blog/content/insert-performance-comparison-of-nosql-vs-sql-servers

4)海量數據的分佈式存儲

海量數據的存儲如果選用大型商用數據,如Oracle,那麼整個解決方案的成本是非常高的,要花很多錢在軟硬件上。NoSQL分佈式存儲,可以部署在廉價的硬件上,是一個性價比非常高的解決方案。Mongo的auto-sharding已經運用到了生產環境。http://www.mongodb.org/display/DOCS/Sharding

並不是說NoSQL可以解決一切問題,像ERP系統、BI系統,在大部分情況還是推薦使用傳統關係型數據庫。主要的原因是此類系統的業務模型複雜,使用NoSQL將導致系統的維護成本增加。

爲什麼要使用NoSQL
NoSQL概念
隨着web2.0的快速發展,非關係型、分佈式數據存儲得到了快速的發展,它們不保證關係數據的ACID特性。NoSQL概念在2009年被提了出來。NoSQL最常見的解釋是“non-relational”,“Not Only SQL”也被很多人接受。(“NoSQL”一詞最早於1998年被用於一個輕量級的關係數據庫的名字。)

NoSQL被我們用得最多的當數key-value存儲,當然還有其他的文檔型的、列存儲、圖型數據庫、xml數據庫等。在NoSQL概念提出之前,這些數據庫就被用於各種系統當中,但是卻很少用於web互聯網應用。比如cdb、qdbm、bdb數據庫。

傳統關係數據庫的瓶頸
傳統的關係數據庫具有不錯的性能,高穩定型,久經歷史考驗,而且使用簡單,功能強大,同時也積累了大量的成功案例。在互聯網領域,MySQL成爲了絕對靠前的王者,毫不誇張的說,mysql爲互聯網的發展做出了卓越的貢獻。

在90年代,一個網站的訪問量一般都不大,用單個數據庫完全可以輕鬆應付。在那個時候,更多的都是靜態網頁,動態交互類型的網站不多。

到了最近10年,網站開始快速發展。火爆的論壇、博客、sns、微博逐漸引領web領域的潮流。在初期,論壇的流量其實也不大,如果你接觸網絡比較早,你可能還記得那個時候還有文本型存儲的論壇程序,可以想象一般的論壇的流量有多大。

Memcached+MySQL
後來,隨着訪問量的上升,幾乎大部分使用MySQL架構的網站在數據庫上都開始出現了性能問題,web程序不再僅僅專注在功能上,同時也在追求性能。程序員們開始大量的使用緩存技術來緩解數據庫的壓力,優化數據庫的結構和索引。開始比較流行的是通過文件緩存來緩解數據庫壓力,但是當訪問量繼續增大的時候,多臺web機器通過文件緩存不能共享,大量的小文件緩存也帶了了比較高的IO壓力。在這個時候,Memcached就自然的成爲一個非常時尚的技術產品。

Memcached作爲一個獨立的分佈式的緩存服務器,爲多個web服務器提供了一個共享的高性能緩存服務,在Memcached服務器上,又發展了根據hash算法來進行多臺Memcached緩存服務的擴展,然後又出現了一致性hash來解決增加或減少緩存服務器導致重新hash帶來的大量緩存失效的弊端。當時,如果你去面試,你說你有Memcached經驗,肯定會加分的。

Mysql主從讀寫分離
由於數據庫的寫入壓力增加,Memcached只能緩解數據庫的讀取壓力。讀寫集中在一個數據庫上讓數據庫不堪重負,大部分網站開始使用主從複製技術來達到讀寫分離,以提高讀寫性能和讀庫的可擴展性。Mysql的master-slave模式成爲這個時候的網站標配了。

分表分庫
隨着web2.0的繼續高速發展,在Memcached的高速緩存,MySQL的主從複製,讀寫分離的基礎之上,這時MySQL主庫的寫壓力開始出現瓶頸,而數據量的持續猛增,由於MyISAM使用表鎖,在高併發下會出現嚴重的鎖問題,大量的高併發MySQL應用開始使用InnoDB引擎代替MyISAM。同時,開始流行使用分表分庫來緩解寫壓力和數據增長的擴展問題。這個時候,分表分庫成了一個熱門技術,是面試的熱門問題也是業界討論的熱門技術問題。也就在這個時候,MySQL推出了還不太穩定的表分區,這也給技術實力一般的公司帶來了希望。雖然MySQL推出了MySQL Cluster集羣,但是由於在互聯網幾乎沒有成功案例,性能也不能滿足互聯網的要求,只是在高可靠性上提供了非常大的保證。

MySQL的擴展性瓶頸
在互聯網,大部分的MySQL都應該是IO密集型的,事實上,如果你的MySQL是個CPU密集型的話,那麼很可能你的MySQL設計得有性能問題,需要優化了。大數據量高併發環境下的MySQL應用開發越來越複雜,也越來越具有技術挑戰性。分表分庫的規則把握都是需要經驗的。雖然有像淘寶這樣技術實力強大的公司開發了透明的中間件層來屏蔽開發者的複雜性,但是避免不了整個架構的複雜性。分庫分表的子庫到一定階段又面臨擴展問題。還有就是需求的變更,可能又需要一種新的分庫方式。

MySQL數據庫也經常存儲一些大文本字段,導致數據庫表非常的大,在做數據庫恢復的時候就導致非常的慢,不容易快速恢復數據庫。比如1000萬4KB大小的文本就接近40GB的大小,如果能把這些數據從MySQL省去,MySQL將變得非常的小。

關係數據庫很強大,但是它並不能很好的應付所有的應用場景。MySQL的擴展性差(需要複雜的技術來實現),大數據下IO壓力大,表結構更改困難,正是當前使用MySQL的開發人員面臨的問題。

NOSQL的優勢
易擴展
NoSQL數據庫種類繁多,但是一個共同的特點都是去掉關係數據庫的關係型特性。數據之間無關係,這樣就非常容易擴展。也無形之間,在架構的層面上帶來了可擴展的能力。

大數據量,高性能
NoSQL數據庫都具有非常高的讀寫性能,尤其在大數據量下,同樣表現優秀。這得益於它的無關係性,數據庫的結構簡單。一般MySQL使用Query Cache,每次表的更新Cache就失效,是一種大粒度的Cache,在針對web2.0的交互頻繁的應用,Cache性能不高。而NoSQL的Cache是記錄級的,是一種細粒度的Cache,所以NoSQL在這個層面上來說就要性能高很多了。

靈活的數據模型
NoSQL無需事先爲要存儲的數據建立字段,隨時可以存儲自定義的數據格式。而在關係數據庫裏,增刪字段是一件非常麻煩的事情。如果是非常大數據量的表,增加字段簡直就是一個噩夢。這點在大數據量的web2.0時代尤其明顯。

高可用
NoSQL在不太影響性能的情況,就可以方便的實現高可用的架構。比如Cassandra,hbase模型,通過複製模型也能實現高可用。

總結
NoSQL數據庫的出現,彌補了關係數據(比如MySQL)在某些方面的不足,在某些方面能極大的節省開發成本和維護成本。
MySQL和NoSQL都有各自的特點和使用的應用場景,兩者的緊密結合將會給web2.0的數據庫發展帶來新的思路。讓關係數據庫關注在關係上,NoSQL關注在存儲上。

關係數據庫還是NoSQL數據庫
上一篇簡單的說明了爲什麼要使用NoSQL。接下來我們看下如何把NoSQL引入到我們的項目中,我們到底要不要把NoSQL引入到項目中。

在過去,我們只需要學習和使用一種數據庫技術,就能做幾乎所有的數據庫應用開發。因爲成熟穩定的關係數據庫產品並不是很多,而供你選擇的免費版本就更加少了,所以互聯網領域基本上都選擇了免費的MySQL數據庫。在高速發展的WEB2.0時代,我們發現關係數據庫在性能、擴展性、數據的快速備份和恢復、滿足需求的易用性上並不總是能很好的滿足我們的需要,我們越來越趨向於根據業務場景選擇合適的數據庫,以及進行多種數據庫的融合運用。幾年前的一篇文章《One Size Fits All - An Idea Whose Time Has Come and Gone》就已經闡述了這個觀點。

當我們在討論是否要使用NoSQL的時候,你還需要理解NoSQL也是分很多種類的,在NoSQL百花齊放的今天,NoSQL的正確選擇比選擇關係數據庫還具有挑戰性。雖然NoSQL的使用很簡單,但是選擇卻是個麻煩事,這也正是很多人在觀望的一個原因。

NoSQL的分類
NoSQL僅僅是一個概念,NoSQL數據庫根據數據的存儲模型和特點分爲很多種類。
這裏寫圖片描述

以上NoSQL數據庫類型的劃分並不是絕對,只是從存儲模型上來進行的大體劃分。它們之間沒有絕對的分界,也有交差的情況,比如Tokyo Cabinet / Tyrant的Table類型存儲,就可以理解爲是文檔型存儲,Berkeley DB XML數據庫是基於Berkeley DB之上開發的。

NoSQL還是關係數據庫
雖然09年出現了比較激進的文章《關係數據庫已死》,但是我們心裏都清楚,關係數據庫其實還活得好好的,你還不能不用關係數據庫。但是也說明了一個事實,關係數據庫在處理WEB2.0數據的時候,的確已經出現了瓶頸。

那麼我們到底是用NoSQL還是關係數據庫呢?我想我們沒有必要來進行一個絕對的回答。我們需要根據我們的應用場景來決定我們到底用什麼。

如果關係數據庫在你的應用場景中,完全能夠很好的工作,而你又是非常善於使用和維護關係數據庫的,那麼我覺得你完全沒有必要遷移到NoSQL上面,除非你是個喜歡折騰的人。如果你是在金融,電信等以數據爲王的關鍵領域,目前使用的是Oracle數據庫來提供高可靠性的,除非遇到特別大的瓶頸,不然也別貿然嘗試NoSQL。

然而,在WEB2.0的網站中,關係數據庫大部分都出現了瓶頸。在磁盤IO、數據庫可擴展上都花費了開發人員相當多的精力來優化,比如做分表分庫(database sharding)、主從複製、異構複製等等,然而,這些工作需要的技術能力越來越高,也越來越具有挑戰性。如果你正在經歷這些場合,那麼我覺得你應該嘗試一下NoSQL了。

選擇合適的NoSQL
如此多類型的NoSQL,而每種類型的NoSQL又有很多,到底選擇什麼類型的NoSQL來作爲我們的存儲呢?這並不是一個很好回答的問題,影響我們選擇的因素有很多,而選擇也可能有多種,隨着業務場景,需求的變更可能選擇又會變化。我們常常需要根據如下情況考慮:

1.數據結構特點。包括結構化、半結構化、字段是否可能變更、是否有大文本字段、數據字段是否可能變化。

2.寫入特點。包括insert比例、update比例、是否經常更新數據的某一個小字段、原子更新需求。

3.查詢特點。包括查詢的條件、查詢熱點的範圍。比如用戶信息的查詢,可能就是隨機的,而新聞的查詢就是按照時間,越新的越頻繁。

NoSQL和關係數據庫結合
其實NoSQL數據庫僅僅是關係數據庫在某些方面(性能,擴展)的一個彌補,單從功能上講,NoSQL的幾乎所有的功能,在關係數據庫上都能夠滿足,所以選擇NoSQL的原因並不在功能上。

所以,我們一般會把NoSQL和關係數據庫進行結合使用,各取所長,需要使用關係特性的時候我們使用關係數據庫,需要使用NoSQL特性的時候我們使用NoSQL數據庫,各得其所。

舉個簡單的例子吧,比如用戶評論的存儲,評論大概有主鍵id、評論的對象aid、評論內容content、用戶uid等字段。我們能確定的是評論內容content肯定不會在數據庫中用where content=’’查詢,評論內容也是一個大文本字段。那麼我們可以把 主鍵id、評論對象aid、用戶id存儲在數據庫,評論內容存儲在NoSQL,這樣數據庫就節省了存儲content佔用的磁盤空間,從而節省大量IO,對content也更容易做Cache。

//從MySQL中查詢出評論主鍵id列表 commentIds=DB.query(“SELECT id FROM comments where aid=’評論對象id’ LIMIT 0,20”); //根據主鍵id列表,從NoSQL取回評論實體數據 CommentsList=NoSQL.get(commentIds);NoSQL代替MySQL
在某些應用場合,比如一些配置的關係鍵值映射存儲、用戶名和密碼的存儲、Session會話存儲等等,用NoSQL完全可以替代MySQL存儲。不但具有更高的性能,而且開發也更加方便。

NoSQL作爲緩存服務器
MySQL+Memcached的架構中,我們處處都要精心設計我們的緩存,包括過期時間的設計、緩存的實時性設計、緩存內存大小評估、緩存命中率等等。

NoSQL數據庫一般都具有非常高的性能,在大多數場景下面,你不必再考慮在代碼層爲NoSQL構建一層Memcached緩存。NoSQL數據本身在Cache上已經做了相當多的優化工作。

Memcached這類內存緩存服務器緩存的數據大小受限於內存大小,如果用NoSQL來代替Memcached來緩存數據庫的話,就可以不再受限於內存大小。雖然可能有少量的磁盤IO讀寫,可能比Memcached慢一點,但是完全可以用來緩存數據庫的查詢操作。

規避風險
由於NoSQL是一個比較新的東西,特別是我們選擇的NoSQL數據庫還不是非常成熟的產品,所以我們可能會遇到未知的風險。爲了得到NoSQL的好處,又要考慮規避風險,魚與熊掌如何兼得?

現在業內很多公司的做法就是數據的備份。在往NoSQL裏面存儲數據的時候還會往MySQL裏面存儲一份。NoSQL數據庫本身也需要進行備份(冷備和熱備)。或者可以考慮使用兩種NoSQL數據庫,出現問題後可以進行切換(避免出現digg使用Cassandra的悲劇)。

總結
本文只是簡單的從MySQL和NoSQL的角度分析如何選擇,以及進行融合使用。其實在選擇NoSQL的時候,你可能還會碰到關於CAP原則,最終一致性,BASE思想的考慮。因爲使用MySQL架構的時候,你也會碰到上面的問題,所以這裏沒有闡述。

轉載自:http://blog.csdn.net/xlgen157387/article/details/48086607

1.命名規範

1.庫名、表名、字段名必須使用小寫字母,並採用下劃線分割。
a)MySQL有配置參數lower_case_table_names,不可動態更改,Linux系統默認爲 0,即庫表名以實際情況存儲,大小寫敏感。如果是1,以小寫存儲,大小寫不敏感。如果是2,以實際情況存儲,但以小寫比較。
b)如果大小寫混合使用,可能存在abc,Abc,ABC等多個表共存,容易導致混亂。
c)字段名顯示區分大小寫,但實際使⽤用不區分,即不可以建立兩個名字一樣但大小寫不一樣的字段。
d)爲了統一規範, 庫名、表名、字段名使用小寫字母。

2.庫名、表名、字段名禁止超過32個字符。
庫名、表名、字段名支持最多64個字符,但爲了統一規範、易於辨識以及減少傳輸量,禁止超過32個字符。

3.使用INNODB存儲引擎。
INNODB引擎是MySQL5.5版本以後的默認引擘,支持事務、行級鎖,有更好的數據恢復能力、更好的併發性能,同時對多核、大內存、SSD等硬件支持更好,支持數據熱備份等,因此INNODB相比MyISAM有明顯優勢。

4.庫名、表名、字段名禁止使用mysql保留字。
當庫名、表名、字段名等屬性含有保留字時,SQL語句必須用反引號引用屬性名稱,這將使得SQL語句書寫、SHELL腳本中變量的轉義等變得⾮非常複雜。

5.禁止使用分區表。
分區表對分區鍵有嚴格要求;分區表在表變大後,執⾏行DDL、SHARDING、單表恢復等都變得更加困難。因此禁止使用分區表,並建議業務端手動SHARDING。

6.建議使用UNSIGNED存儲非負數值。
同樣的字節數,非負存儲的數值範圍更大。如TINYINT有符號爲 -128-127,無符號爲0-255。

7.建議使用INT UNSIGNED存儲IPV4。
用UNSINGED INT存儲IP地址佔用4字節,CHAR(15)則佔用15字節。另外,計算機處理整數類型比字符串類型快。使用INT UNSIGNED而不是CHAR(15)來存儲IPV4地址,通過MySQL函數inet_ntoa和inet_aton來進行轉化。IPv6地址目前沒有轉化函數,需要使用DECIMAL或兩個BIGINT來存儲。
例如:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">SELECT</span> INET_ATON(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'209.207.224.40'</span>);</span> 3520061480 <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">SELECT</span> INET_NTOA(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3520061480</span>);</span> 209.207.224.40</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
8.強烈建議使用TINYINT來代替ENUM類型。
ENUM類型在需要修改或增加枚舉值時,需要在線DDL,成本較高;ENUM列值如果含有數字類型,可能會引起默認值混淆。

9.使用VARBINARY存儲大小寫敏感的變長字符串或二進制內容。
VARBINARY默認區分大小寫,沒有字符集概念,速度快。

10.INT類型固定佔用4字節存儲
例如INT(4)僅代表顯示字符寬度爲4位,不代表存儲長度。數值類型括號後面的數字只是表示寬度而跟存儲範圍沒有關係,比如INT(3)默認顯示3位,空格補齊,超出時正常顯示,Python、Java客戶端等不具備這個功能。

11.區分使用DATETIME和TIMESTAMP。
存儲年使用YEAR類型。存儲日期使用DATE類型。 存儲時間(精確到秒)建議使用TIMESTAMP類型。
DATETIME和TIMESTAMP都是精確到秒,優先選擇TIMESTAMP,因爲TIMESTAMP只有4個字節,而DATETIME8個字節。同時TIMESTAMP具有自動賦值以及⾃自動更新的特性。注意:在5.5和之前的版本中,如果一個表中有多個timestamp列,那麼最多只能有一列能具有自動更新功能。

如何使用TIMESTAMP的自動賦值屬性?
a)自動初始化,而且自動更新:

<code class="hljs vbnet has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">column1 TIMESTAMP <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">DEFAULT</span> CURRENT_TIMESTAMP <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">ON</span> UPDATECURRENT_TIMESTAMP</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
b)只是自動初始化:

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> column1 TIMESTAMP <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">DEFAULT</span> CURRENT_TIMESTAMP</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
c)自動更新,初始化的值爲0:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> column1 TIMESTAMP DEFAULT 0 ON <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">UPDATE</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">CURRENT_TIMESTAMP</span></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
d)初始化的值爲0:

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">column1 TIMESTAMP <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">DEFAULT</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
12.所有字段均定義爲NOT NULL。
a)對錶的每一行,每個爲NULL的列都需要額外的空間來標識。
b)B樹索引時不會存儲NULL值,所以如果索引字段可以爲NULL,索引效率會下降。
c)建議用0、特殊值或空串代替NULL值。

MySQL使用技巧
1.將大字段、訪問頻率低的字段拆分到單獨的表中存儲,分離冷熱數據。
有利於有效利用緩存,防⽌止讀入無用的冷數據,較少磁盤IO,同時保證熱數據常駐內存提⾼高緩存命中率。

2.禁止在數據庫中存儲明文密碼。
採用加密字符串存儲密碼,並保證密碼不可解密,同時採用隨機字符串加鹽保證密碼安全。

3.表必須有主鍵,推薦使用UNSIGNED自增列作爲主鍵。
表沒有主鍵,INNODB會默認設置隱藏的主鍵列;沒有主鍵的表在定位數據行的時候非常困難,也會降低基於行復制的效率。

4.禁止冗餘索引。
索引是雙刃劍,會增加維護負擔,增⼤大IO壓力。(a,b,c)、(a,b),後者爲冗餘索引。可以利用前綴索引來達到加速目的,減輕維護負擔。

5.禁止重複索引。
primary key a;uniq index a;重複索引增加維護負擔、佔用磁盤空間,同時沒有任何益處。

6.不在低基數列上建立索引,例如“性別”。
大部分場景下,低基數列上建立索引的精確查找,相對於不建立索引的全表掃描沒有任何優勢,而且增大了IO負擔。

7.合理使用覆蓋索引減少IO,避免排序。
覆蓋索引能從索引中獲取需要的所有字段,從⽽而避免回表進行二次查找,節省IO。
INNODB存儲引擎中,secondary index(非主鍵索引,又稱爲輔助索引、二級索引)沒有直接存儲行地址,而是存儲主鍵值。
如果用戶需要查詢secondary index中所不包含的數據列,則需要先通過secondary index查找到主鍵值,然後再通過主鍵查詢到其他數據列,因此需要查詢兩次。覆蓋索引則可以在⼀一個索引中獲取所有需要的數據,因此效率較高。
例如SELECT email,uid FROM user_email WHERE uid=xx,如果uid不是主鍵,適當時候可以將索引添加爲index(uid,email),以獲得性能提升。

8.用IN代替OR。SQL語句中IN包含的值不應過多,應少於1000個。
IN是範圍查找,MySQL內部會對IN的列表值進行排序後查找,比OR效率更高。

9.表字符集使用UTF8,必要時可申請使用UTF8MB4字符集。
a)UTF8字符集存儲漢字佔用3個字節,存儲英文字符佔用一個字節。
b)UTF8統一而且通用,不會出現轉碼出現亂碼風險。
c)如果遇到EMOJ等表情符號的存儲需求,可申請使用UTF8MB4字符集。

10.用UNION ALL代替UNION。
UNION ALL不需要對結果集再進行排序。

11.禁止使用order by rand()。
order by rand()會爲表增加一個僞列,然後用rand()函數爲每一行數據計算出rand()值,然後基於該行排序,這通常都會生成磁盤上的臨時表,因此效率非常低。建議先使用rand()函數獲得隨機的主鍵值,然後通過主鍵
獲取數據。

12.建議使用合理的分頁方式以提高分頁效率。
假如有類似下面分頁語句:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">SELECT</span> * <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">FROM</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">ORDER</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">BY</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">TIME</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">DESC</span> LIMIT <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
這種分頁方式會導致大量的io,因爲MySQL使用的是提前讀取策略。
推薦分頁方式:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">SELECT</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">FROM</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">WHERE</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">TIME</span><last_TIME <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">ORDER</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">BY</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">TIME</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">DESC</span> LIMIT <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">SELECT</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">FROM</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">inner</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">JOIN</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">SELECT</span> id <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">FROM</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">ORDER</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">BY</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">TIME</span> LIMIT <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> t <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">USING</span>(id)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
13.SELECT只獲取必要的字段,禁⽌止使用SELECT *。
減少網絡帶寬消耗;
能有效利用覆蓋索引;
表結構變更對程序基本無影響。

14.SQL中避免出現now()、rand()、sysdate()、current_user()等不確定結果的函數。
語句級複製場景下,引起主從數據不一致;不確定值的函數,產⽣生的SQL語句無法利用QUERY CACHE。

15.採用合適的分庫分表策略。例如千庫十表、十庫百表等。
採用合適的分庫分表策略,有利於業務發展後期快速對數據庫進行水平拆分,同時分庫可以有效利⽤用MySQL
的多線程複製特性。

16.減少與數據庫交互次數,儘量採用批量SQL語句。
使用下面的語句來減少和db的交互次數:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">a)<span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">INSERT</span> ... <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">ON</span> DUPLICATE <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">KEY</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">UPDATE</span> b)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">REPLACE</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">INTO</span> c)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">INSERT</span> IGNORE d)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">INSERT</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">INTO</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">VALUES</span>() </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
17.拆分複雜SQL爲多個小SQL,避免大事務。
簡單的SQL容易使⽤用到MySQL的QUERY CACHE;減少鎖表時間特別是MyISAM;可以使用多核 CPU。

18.對同一個表的多次alter操作必須合併爲一次操作。
mysql對錶的修改絕大部分操作都需要鎖表並重建表,而鎖表則會對線上業務造成影響。爲減少這種影響,必須把對錶的多次alter操作合併爲一次操作。例如,要給表t增加一個字段b,同時給已有的字段aa建立索引,
通常的做法分爲兩步:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">alter</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> t <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">add</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">column</span> b <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">varchar</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
然後增加索引:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">alter</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> t <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">add</span> index idx_aa(aa);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
正確的做法是:

<code class="hljs sql has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">alter</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">table</span> t <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">add</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">column</span> b <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">varchar</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>),<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">add</span> index idx_aa(aa);</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
19.避免使用存儲過程、觸發器、視圖、自定義函數等。
這些高級特性有性能問題,以及未知BUG較多。業務邏輯放到數據庫會造成數據庫的DDL、SCALE OUT、
SHARDING等變得更加困難。

20.禁止有super權限的應用程序賬號存在。
安全第一。super權限會導致read only失效,導致較多詭異問題而且很難追蹤。

21.不要在MySQL數據庫中存放業務邏輯。
數據庫是有狀態的服務,變更復雜而且速度慢,如果把業務邏輯放到數據庫中,將會限制業務的快速發展。建議把業務邏輯提前,放到前端或中間邏輯層,而把數據庫作爲存儲層,實現邏輯與存儲的分離。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章