後端數據庫攻略

(一)MySQL基礎考點

1.事務的原理 特性及併發控制

什麼是事務(Transaction)?

事務是數據庫併發控制的基本單位
事務能夠看做是一些列SQL語句的集合
事務必需要麼所有執行成功,要麼所有執行失敗(回滾)
事務使用常見的場景:銀行轉帳操做

事務的ACID特性

原子性(Atomicity):一個事務中全部操做所有完成或失敗
一致性(Consistency):事務開始和結束以後數據完整性沒有被破壞
隔離性(Isolation):容許多個事務同時對數據庫修改和讀寫
持久性(Durability):事務結束以後,修改是永久的不會被丟失

事務併發控制

可能產生哪些問題?
幻讀:一個事務第二次查出現第一次沒有的結果
非重複讀:一個事務重複讀兩次獲得不一樣的結果
髒讀:一個事務讀取到另外一個事務沒有提交的修改
丟失修改:併發寫入形成其中一些修改丟失
解決併發異常,定義4種事務隔離級別
讀未提交:別的事務能夠讀取到未提交改變
讀已提交:只能讀取已經提交的數據
可重複讀:同一個事務前後查詢結果同樣(Mysql innoDB默認實現可重複讀級別)
串行化: 事務徹底串行化執行,隔離級別最高,效率最低
如何解決高併發場景下的插入重複(寫入數據庫會出現重複問題)
使用數據庫的惟一索引
使用隊列異步寫入
使用redis等實現分佈式鎖
樂觀鎖和悲觀鎖
悲觀鎖:先獲取鎖再進行操做。一鎖二查三更新 select for update
樂觀鎖:先修改,更近的時候發現數據已經變了就回滾(check and set)
使用須要根據響應速度、衝突頻率、重試代價來判斷使用哪種

2.常見字段的含義及區別

文本型

CHAR
VARCHAR
TINYTEXT
TEXT

數值型

TINYINT
SMALLINT
INT
SIGINT
FLOAT
DOUBLE

日期和時間

DATE
DATETIME
TIMESTAMP (4個字節,但接受的時間1970-2038年之間)

3.常見數據庫引擎之間的區別(InnoDB VS MyISAM)

MyISAM不支持事務,InnoDB支持事務
MyISAM不支持外鍵,InnoDB支持外鍵
MyISAM只支持表鎖,InnoDB支持行鎖和表鎖
MyISAM支持全文索引,InnoDB不支持

(二)Mysql索引原理及優化常見考題

1. 索引的原理、類型、結構

什麼是索引?

數據表種一個或者多個列進行排序的數據結構
索引可以大幅提高索引速度
建立、更新索引自己也會消耗空間和時間

什麼是B-Tree?(查找結構進化史)

多路平衡查找樹

B+Tree

Mysql實際使用的B+Tree做爲索引的數據結構

2. 建立索引的注意事項,使用原理

常見索引類型

普通索引  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數據文件就是索引文件,主鍵索引就是彙集索引

3.如何排查和消除慢查詢

慢查詢一般是缺乏索引,索引不合理或者業務代碼實現致使

排查

slow_query_log_file開啓而且查詢慢查詢日誌
經過explain命令排查索引問題
調整數據修改索引;業務代碼層限制不合理訪問(好比一次獲取太多數據--實現分頁; 數據類型不匹配致使全文掃描)

(三)SQL語句編寫常考題

1.經常使用鏈接爲重點

內鏈接(INNER JOIN):兩個表都存在匹配時,纔會返回匹配行
外鏈接(LEFT/RIGHT JOIN): 返回一個表的行,即便另外一個沒有匹配
全鏈接(FULL JOIN):只要某一個表存在匹配就返回

(四)非關係型數據庫Redis

1. 緩存(內存緩存)的使用場景

爲何要使用緩存?

緩解關係數據(常見的Mysql)併發訪問的壓力: 熱點數據
減小響應時間:內存IO速度比磁盤快
提高吞吐量: Redis等內存數據庫單機就能夠支持很大併發

Redis和Memcached主要區別?

數據存儲類型:redis支持string/List/hash/set/sort set;memcached只支持文本型/二進制類型
網絡IO模型:redis單進程模式;memcached多線程、非阻塞IO模式
持久化支持:redis支持兩種RDB,DOF; memcached不支持

2. Redis經常使用數據類型和使用場景?

數據類型

String(字符串):用來實現簡單的KV鍵值對存儲,好比計數器
List(鏈表): 實現雙向鏈表,好比用戶的關注,粉絲列表
Hash(哈希表):用來存儲彼此相關信息的鍵值對
Set(集合): 存儲不重複元素,好比用戶的關注者
Sorted set(有序集合): 實時信息排行榜python

支持兩種方式實現持久化

快照方式:把樹快照放在磁盤二進制文件中,dump.rdb
AOF: 每個寫命令追加到appendonly.aof中
能夠修改經過Redis配置實現

什麼redis事務?

將多個請求打包,一次性,按序執行多個命令的機制
經過 MULTI, EXEC,WATCH等命令實現事務功能

如何實現分佈式鎖?

使用setnx實現加鎖,能夠同時經過expire添加超時時間
鎖的value值可使用一個隨機的uuid或者特定的命名
釋放鎖的時候,經過uuid判斷是不是該鎖,是則執行delete釋放鎖

3. 緩存使用的坑

使用緩存的模式?

Cache Aside:  同時更新緩存和數據庫
Read/Write Through: 先更新緩存,緩存負責同步更新數據庫
Write Behind Caching: 先更新緩存,緩存按期異步更新數據庫

如何解決緩存穿透問題?

緣由:因爲大量緩存查不到就去數據庫取,數據庫也沒有要查的數據
解決:對於沒有查到返回None的數據也緩存; 插入數據的時候刪除相應緩存,或者設置較短的超時時間

如何解決緩存擊穿問題?

緣由:某些很是熱點的數據key過時,大量請求達到後端數據庫
解決:
    分佈式鎖-獲取鎖的線程從數據庫拉數據更新緩存,其餘線程等待
    異步後臺更新-後臺任務針對過時key自動刷新

如何解決緩存雪崩問題?

緣由:緩存不可用或大量緩存key同時失效,大量請求直接達到數據庫
解決:
    多級緩存--不一樣級別的key設置不一樣的超時時間
    隨機超時--key的超時時間隨機設置,防止同時超時
    架構層--提高系統可用性,監控、報警完善

(五)Mysql與Redis練習題

1. Mysql思考題

爲何Mysql數據庫主鍵使用自增的整數比較好?uuid能夠嗎?

在最佳實踐中,auto_increment字段長度比uuid小,從性能及可讀性都比uuid要好

若是是分佈式系統下咱們怎麼生成數據庫的自增id呢?

在auto_increment的基礎上,設置step增加步長;好比:Master1 生成的是 1,4,7,10,
    Master2生成的是2,5,8,11 Master3生成的是 3,6,9,12。
    這樣就能夠有效生成集羣中的惟一ID,也能夠大大下降ID生成數據庫操做的負載。

2. Redis應用-分佈式鎖

編寫一個簡單的分佈式鎖,要求支持超時時間參數
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()
相關文章
相關標籤/搜索