NoSQL(NoSQL = Not Only SQL ),意即「不只僅是SQL」,是一項全新的數據庫革命性運動,泛指非關係型的數據庫。隨着互聯網web2.0網站的興起,傳統的關係數據庫在應付web2.0網站,特別是超大規模和高併發的SNS類型的web2.0純動態網站已經顯得力不從心,暴露了不少難以克服的問題,而非關係型的數據庫則因爲其自己的特色獲得了很是迅速的發展。NoSQL數據庫的產生就是爲了解決大規模數據集合多重數據種類帶來的挑戰,尤爲是大數據應用難題。web
NoSQL四個大分類:redis
鍵值(Key-Value)存儲數據庫:這一類數據庫主要會使用到一個哈希表,這個表中有一個特定的鍵和一個指針指向特定的數據。Key/value模型對於IT系統來講的優點在於簡單、易部署。可是若是DBA只對部分值進行查詢或更新的時候,Key/value就顯得效率低下了。舉例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB。算法
列存儲數據庫:這部分數據庫一般是用來應對分佈式存儲的海量數據。鍵仍然存在,可是它們的特色是指向了多個列。這些列是由列家族來安排的。如:Cassandra, HBase, Riak.shell
文檔型數據庫:文檔型數據庫的靈感是來自於Lotus Notes辦公軟件的,並且它同第一種鍵值存儲相相似。該類型的數據模型是版本化的文檔,半結構化的文檔以特定的格式存儲,好比JSON。文檔型數據庫可 以看做是鍵值數據庫的升級版,容許之間嵌套鍵值。並且文檔型數據庫比鍵值數據庫的查詢效率更高。如:CouchDB, MongoDb. 國內也有文檔型數據庫SequoiaDB,已經開源。數據庫
圖形(Graph)數據庫:圖形結構的數據庫同其餘行列以及剛性結構的SQL數據庫不一樣,它是使用靈活的圖形模型,而且可以擴展到多個服務器上。NoSQL數據庫沒有標準的查詢語言(SQL),所以進行數據庫查詢須要制定數據模型。許多NoSQL數據庫都有REST式的數據接口或者查詢API。如:Neo4J, InfoGrid, Infinite Graph.緩存
NoSQL數據庫使用場景:服務器
一、數據模型比較簡單;網絡
二、須要靈活性更強的IT系統;數據結構
三、對數據庫性能要求較高;架構
四、不須要高度的數據一致性;
五、對於給定key,比較容易映射覆雜值的環境。
鍵值(key-value) | Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB | 內容緩存,主要用於處理大量數據的高訪問負載,也用於一些日誌系統等等。 | Key 指向 Value 的鍵值對,一般用hash table來實現 | 查找速度快 | 數據無結構化,一般只被看成字符串或者二進制數據 |
列存儲數據庫 | Cassandra, HBase, Riak | 分佈式的文件系統 | 以列簇式存儲,將同一列數據存在一塊兒 | 查找速度快,可擴展性強,更容易進行分佈式擴展 | 功能相對侷限 |
文檔型數據庫 | CouchDB, MongoDb | Web應用(與Key-Value相似,Value是結構化的,不一樣的是數據庫可以瞭解Value的內容) | Key-Value對應的鍵值對,Value爲結構化數據 | 數據結構要求不嚴格,表結構可變,不須要像關係型數據庫同樣須要預先定義表結構 | 查詢性能不高,並且缺少統一的查詢語法。 |
圖形(Graph)數據庫 | Neo4J, InfoGrid, Infinite Graph | 社交網絡,推薦系統等。專一於構建關係圖譜 | 圖結構 | 利用圖結構相關算法。好比最短路徑尋址,N度關係查找等 | 不少時候須要對整個圖作計算才能得出須要的信息,並且這種結構不太好作分佈式的集羣方案 |
對於NoSQL並無一個明確的範圍和定義,可是他們都廣泛存在下面一些共同特徵:
(1)不須要預約義模式:不須要事先定義數據模式,預約義表結構。數據中的每條記錄均可能有不一樣的屬性和格式。當插入數據時,並不須要預先定義它們的模式。
(2)無共享架構:相對於將全部數據存儲的存儲區域網絡中的全共享架構。NoSQL每每將數據劃分後存儲在各個本地服務器上。由於從本地磁盤讀取數據的性能每每好於經過網絡傳輸讀取數據的性能,從而提升了系統的性能。
(3)彈性可擴展:能夠在系統運行的時候,動態增長或者刪除結點。不須要停機維護,數據能夠自動遷移。
(4)分區:相對於將數據存放於同一個節點,NoSQL數據庫須要將數據進行分區,將記錄分散在多個節點上面。而且一般分區的同時還要作複製。這樣既提升了並行性能,又能保證沒有單點失效的問題。
(5)異步複製:和RAID存儲系統不一樣的是,NoSQL中的複製,每每是基於日誌的異步複製。這樣,數據就能夠儘快地寫入一個節點,而不會被網絡傳輸引發遲延。缺點是並不老是能保證一致性,這樣的方式在出現故障的時候,可能會丟失少許的數據。
(6)BASE:相對於事務嚴格的ACID特性,NoSQL數據庫保證的是BASE特性。BASE是最終一致性和軟事務。
(7)NoSQL數據庫並無一個統一的架構,兩種NoSQL數據庫之間的不一樣,甚至遠遠超過兩種關係型數據庫的不一樣。能夠說,NoSQL各有所長,成功的NoSQL必然特別適用於某些場合或者某些應用,在這些場合中會遠遠賽過關係型數據庫和其餘的NoSQL。
Redis
Redis是一個key-value存儲系統。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,redis支持各類不一樣方式的排序。與memcached同樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步。
Redis 是一個高性能的key-value數據庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合能夠對關係數據庫起到很好的補充做用。它提供了Python,Ruby,Erlang,PHP客戶端,使用很方便,Redis支持主從同步。數據能夠從主服務器向任意數量的從服務器上同步,從服務器能夠是關聯其餘從服務器的主服務器。這使得Redis可執行單層樹複製。從盤能夠有意無心的對數據進行寫操做。因爲徹底實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。
#Redis經常使用shell
[root@localhost ~]# redis-cli # 進入redis cli窗口
127.0.0.1:6379> set name fgf # 設置值
OK
127.0.0.1:6379> set age 02
OK
127.0.0.1:6379> keys * # 當前全部key
1) "age"
2) "name"
127.0.0.1:6379> set sex m ex 2 # 設置值,只存活2秒
OK
127.0.0.1:6379> get sex # 獲取值
"m"
127.0.0.1:6379> flushdb # 清空當前db下的全部鍵值
OK
127.0.0.1:6379> flushall # 清空全部db下的鍵值
OK
1)操做模式
redis-py提供兩個類Redis和StrictRedis用於實現Redis的命令,StrictRedis用於實現大部分官方的命令,並使用官方的語法和命令,Redis是StrictRedis的子類,用於向後兼容舊版本的redis-py。
import redis
r = redis.Redis(host='127.0.0.1', port=6379)
r.set('foo', 'Bar') #添加
print (r.get('foo')) #獲取
2)鏈接池
redis-py使用connection pool來管理對一個redis server的全部鏈接,避免每次創建、釋放鏈接的開銷。默認,每一個Redis實例都會維護一個本身的鏈接池。能夠直接創建一個鏈接池,而後做爲參數Redis,這樣就能夠實現多個Redis實例共享一個鏈接池。
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
r = redis.Redis(connection_pool=pool)
r.set('foo', 'Bar') #添加
print r.get('foo') #獲取
3)管道
redis-py默認在執行每次請求都會建立(鏈接池申請鏈接)和斷開(歸還鏈接池)一次鏈接操做,若是想要在一次請求中指定多個命令,則可使用pipline實現一次請求指定多個命令,而且默認狀況下一次pipline 是原子性操做。
import redis
pool = redis.ConnectionPool(host='192.168.0.110', port=6379)
r = redis.Redis(connection_pool=pool)
pipe = r.pipeline(transaction=True)
r.set('name', 'zhangsan')
r.set('name', 'lisi')
pipe.execute()
一、字符串操做
redis中的String在在內存中按照一個name對應一個value來存儲
#在Redis中設置值,默認不存在則建立,存在則修改r.('name', 'zhangsan')'''參數:
set(name, value, ex=None, px=None, nx=False, xx=False)
ex,過時時間(秒)
px,過時時間(毫秒)
nx,若是設置爲True,則只有name不存在時,當前set操做才執行,同setnx(name, value)
xx,若是設置爲True,則只有name存在時,當前set操做才執行'''
#設置過時時間(秒)
setex(name, value, time)
#設置過時時間(豪秒)
psetex(name, time_ms, value)
#批量設置值
r.mset(name1='zhangsan', name2='lisi')
#或
r.mget({"name1":'zhangsan', "name2":'lisi'})
#批量獲取
print(r.mget("name1","name2"))
#或
li=["name1","name2"]
print(r.mget(li))
#設置新值,打印原值
print(r.getset("name1","wangwu")) #輸出:zhangsan
print(r.get("name1")) #輸出:wangwu
#根據字節獲取子序列
r.set("name","zhangsan")
print(r.getrange("name",0,3)) #輸出:zhan
#修改字符串內容,從指定字符串索引開始向後替換,若是新值太長時,則向後添加
r.set("name","zhangsan")
r.setrange("name",1,"z")
print(r.get("name")) #輸出:zzangsan
r.setrange("name",6,"zzzzzzz")
print(r.get("name")) #輸出:zzangszzzzzzz
二、List操做
redis中的List在在內存中按照一個name對應一個List來存儲
# 在name對應的list中添加元素,每一個新的元素都添加到列表的最左邊
r.lpush("list_name",2)
r.lpush("list_name",3,4,5) #保存在列表中的順序爲5,4,3,2
#同lpush,但每一個新的元素都添加到列表的最右邊
rpush(name,values)
#在name對應的list中添加元素,只有name已經存在時,值添加到列表的最左邊
lpushx(name,value)
#在name對應的list中添加元素,只有name已經存在時,值添加到列表的最右邊
rpushx(name,value)
# name對應的list元素的個數
print(r.llen("list_name"))
# 在name對應的列表的某一個值前或後插入一個新值
r.linsert("list_name","BEFORE","2","SS") #在列表內找到第一個元素2,在它前面插入SS
'''參數:
name: redis的name
where: BEFORE(前)或AFTER(後)
refvalue: 列表內的值
value: 要插入的數據'''
#對list中的某一個索引位置從新賦值
r.lset("list_name",0,"bbb")
#刪除name對應的list中的指定值
r.lrem("list_name","SS",num=0)
''' 參數:
name: redis的name
value: 要刪除的值
num: num=0 刪除列表中全部的指定值;
num=2 從前到後,刪除2個;
num=-2 從後向前,刪除2個'''
#移除列表的左側第一個元素,返回值則是第一個元素
print(r.lpop("list_name"))
#根據索引獲取列表內元素
print(r.lindex("list_name",1))
#分片獲取元素
print(r.lrange("list_name",0,-1))
#移除列表內沒有在該索引以內的值
r.ltrim("list_name",0,2)
三、Set操做
#給name對應的集合中添加元素
r.sadd("set_name","aa")
r.sadd("set_name","aa","bb")
# 獲取多個name對應集合的並集
r.sadd("set_name","aa","bb")
r.sadd("set_name1","bb","cc")
r.sadd("set_name2","bb","cc","dd")
print(r.sinter("set_name","set_name1","set_name2")) #輸出:{bb}
#獲取name對應的集合的全部成員
smembers(name)
#獲取name對應的集合中的元素個數
r.scard("set_name")
# 在name對應的有序集合中添加元素
r.zadd("zset_name", "a1", 6, "a2", 2,"a3",5)
#或r.zadd('zset_name1', b1=10, b2=5)
#獲取有序集合中分數在[min,max]之間的個數
print(r.zcount("zset_name",1,5))
#自增有序集合內value對應的分數
r.zincrby("zset_name","a1",amount=2) #自增zset_name對應的有序集合裏a1對應的分數
其餘經常使用操做:
delete(*names) #根據name刪除redis中的任意數據類型
exists(name) #檢測redis的name是否存在
keys(pattern='*') #根據* ?等通配符匹配獲取redis的name
expire(name ,time) # 爲某個name設置超時時間
rename(src, dst) # 重命名
move(name, db)) # 將redis的某個值移動到指定的db下
randomkey() #隨機獲取一個redis的name(不刪除)
type(name) # 獲取name對應值的類型