事務是數據庫併發控制的基本單位 事務能夠看做是一些列SQL語句的集合 事務必需要麼所有執行成功,要麼所有執行失敗(回滾) 事務使用常見的場景:銀行轉帳操做
原子性(Atomicity):一個事務中全部操做所有完成或失敗 一致性(Consistency):事務開始和結束以後數據完整性沒有被破壞 隔離性(Isolation):容許多個事務同時對數據庫修改和讀寫 持久性(Durability):事務結束以後,修改是永久的不會被丟失
幻讀:一個事務第二次查出現第一次沒有的結果 非重複讀:一個事務重複讀兩次獲得不一樣的結果 髒讀:一個事務讀取到另外一個事務沒有提交的修改 丟失修改:併發寫入形成其中一些修改丟失
讀未提交:別的事務能夠讀取到未提交改變 讀已提交:只能讀取已經提交的數據 可重複讀:同一個事務前後查詢結果同樣(Mysql innoDB默認實現可重複讀級別) 串行化: 事務徹底串行化執行,隔離級別最高,效率最低
使用數據庫的惟一索引 使用隊列異步寫入 使用redis等實現分佈式鎖
悲觀鎖:先獲取鎖再進行操做。一鎖二查三更新 select for update 樂觀鎖:先修改,更近的時候發現數據已經變了就回滾(check and set) 使用須要根據響應速度、衝突頻率、重試代價來判斷使用哪種
CHAR VARCHAR TINYTEXT TEXT
TINYINT SMALLINT INT SIGINT FLOAT DOUBLE
DATE DATETIME TIMESTAMP (4個字節,但接受的時間1970-2038年之間)
MyISAM不支持事務,InnoDB支持事務 MyISAM不支持外鍵,InnoDB支持外鍵 MyISAM只支持表鎖,InnoDB支持行鎖和表鎖 MyISAM支持全文索引,InnoDB不支持
數據表種一個或者多個列進行排序的數據結構 索引可以大幅提高索引速度 建立、更新索引自己也會消耗空間和時間
多路平衡查找樹
Mysql實際使用的B+Tree做爲索引的數據結構
普通索引 CREATE INDEX 惟一索引,索引列的值必須惟一 CREATE UNIQUE INDEX 多列索引(聯合索引) 主鍵索引 一個表只能有一個 PRIMARY KEY 全文索引 InnoDB不支持(通常採用專門的全文索引數據庫實現)
常常用做查詢條件的字段(WHERE條件) 常常用做錶鏈接的字段 常常出如今order by, group by以後的字段
非空字段NOT NULL, Mysql很難對空值作查詢優化 區分度高,離散度大,做爲索引的字段值儘可能不要有大量相同值 索引的長度不要太大(比較消耗時間--索引做爲B+Tree的key值存在,字符串key太長比較耗時)
記憶口訣:模型匹配、類型隱轉、最左匹配 以%開頭的LIKE語句,模糊搜索 出現隱式轉換(python這種動態語言查詢中須要注意) 沒有知足最左前綴原理(針對聯合索引)
是指B+Tree葉節點存的是指針仍是數據記錄 MyISAM索引和數據分離,使用的是非彙集索引(存的是數據指針) InnoDB數據文件就是索引文件,主鍵索引就是彙集索引
slow_query_log_file開啓而且查詢慢查詢日誌 經過explain命令排查索引問題 調整數據修改索引;業務代碼層限制不合理訪問(好比一次獲取太多數據--實現分頁; 數據類型不匹配致使全文掃描)
內鏈接(INNER JOIN):兩個表都存在匹配時,纔會返回匹配行 外鏈接(LEFT/RIGHT JOIN): 返回一個表的行,即便另外一個沒有匹配 全鏈接(FULL JOIN):只要某一個表存在匹配就返回
緩解關係數據(常見的Mysql)併發訪問的壓力: 熱點數據 減小響應時間:內存IO速度比磁盤快 提高吞吐量: Redis等內存數據庫單機就能夠支持很大併發
數據存儲類型:redis支持string/List/hash/set/sort set;memcached只支持文本型/二進制類型 網絡IO模型:redis單進程模式;memcached多線程、非阻塞IO模式 持久化支持:redis支持兩種RDB,DOF; memcached不支持
String(字符串):用來實現簡單的KV鍵值對存儲,好比計數器
List(鏈表): 實現雙向鏈表,好比用戶的關注,粉絲列表
Hash(哈希表):用來存儲彼此相關信息的鍵值對
Set(集合): 存儲不重複元素,好比用戶的關注者
Sorted set(有序集合): 實時信息排行榜python
快照方式:把樹快照放在磁盤二進制文件中,dump.rdb AOF: 每個寫命令追加到appendonly.aof中 能夠修改經過Redis配置實現
將多個請求打包,一次性,按序執行多個命令的機制 經過 MULTI, EXEC,WATCH等命令實現事務功能
使用setnx實現加鎖,能夠同時經過expire添加超時時間 鎖的value值可使用一個隨機的uuid或者特定的命名 釋放鎖的時候,經過uuid判斷是不是該鎖,是則執行delete釋放鎖
Cache Aside: 同時更新緩存和數據庫 Read/Write Through: 先更新緩存,緩存負責同步更新數據庫 Write Behind Caching: 先更新緩存,緩存按期異步更新數據庫
緣由:因爲大量緩存查不到就去數據庫取,數據庫也沒有要查的數據 解決:對於沒有查到返回None的數據也緩存; 插入數據的時候刪除相應緩存,或者設置較短的超時時間
緣由:某些很是熱點的數據key過時,大量請求達到後端數據庫 解決: 分佈式鎖-獲取鎖的線程從數據庫拉數據更新緩存,其餘線程等待 異步後臺更新-後臺任務針對過時key自動刷新
緣由:緩存不可用或大量緩存key同時失效,大量請求直接達到數據庫 解決: 多級緩存--不一樣級別的key設置不一樣的超時時間 隨機超時--key的超時時間隨機設置,防止同時超時 架構層--提高系統可用性,監控、報警完善
在最佳實踐中,auto_increment字段長度比uuid小,從性能及可讀性都比uuid要好
在auto_increment的基礎上,設置step增加步長;好比:Master1 生成的是 1,4,7,10, Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。 這樣就能夠有效生成集羣中的惟一ID,也能夠大大下降ID生成數據庫操做的負載。
編寫一個簡單的分佈式鎖,要求支持超時時間參數
import time import redis class RedisLock(object): def __init__(self, key, timeout): self.rdcon = redis.Redis(host='', port=6379, password="", db=1) self._lock = 0 self.timeout = timeout self.lock_key = "%s_dynamic_test" % key @staticmethod def get_lock(cls): while cls._lock != 1: timestamp = time.time() + self.timeout + 1 cls._lock = cls.rdcon.setnx(cls.lock_key, timestamp) # 注意下方括號的範圍 if cls._lock == 1 or (time.time() > cls.rdcon.get(cls.lock_key) and time.time() > cls.rdcon.getset(cls.lock_key, timestamp)): print "get lock" break else: time.sleep(0.3) @staticmethod def release(cls): if time.time() < cls.rdcon.get(cls.lock_key): print("release lock") cls.rdcon.delete(cls.lock_key) def deco(cls): def _deco(func): def __deco(*args, **kwargs): print("before %s called [%s]."%(func.__name__, cls)) cls.get_lock(cls, timeout) try: return func(*args, **kwargs) finally: cls.release(cls) return __deco return _deco @deco(RedisLock("key")) def myfunc(): # do_something time.sleep(20) if __name__ == "__main__": myfunc()