第二部分NoSQL部分已發布:2020字節跳動數據庫面試題及答案(二)—— NoSQL部分
題目列表
- 數據庫三范式
- 分別說一下范式和反范式的優缺點
- Mysql 數據庫索引。B+ 樹和 B 樹的區別
- 為什么 B+ 樹比 B 樹更適合應用於數據庫索引,除了數據庫索引,還有什么地方用到了(操作系統的文件索引)
- 聚簇索引和非聚簇索引
- 前綴索引和覆蓋索引
- 介紹一下數據庫的事務
- Mysql 有哪些隔離級別
- Mysql 什么情況會造成臟讀、不可重復度、幻讀?如何解決
- Mysql 在可重復讀的隔離級別下會不會有幻讀的情況,為什么?
- Mysql 事務是如何實現的
- Binlog 和 Redo log 的區別是什么,分別是什么用?
- 談一談 MVCC 多版本並發控制
- Innodb 和 MyISAM 的區別是什么
- Innodb 的默認加鎖方式是什么,是怎么實現的
- 如何高效處理大庫 DDL
- Mysql 索引重建
- 對於多列索引,哪些情況下能用到索引,哪些情況用不到索引
- 為什么使用數據庫索引可以提高效率,在什么情況下會用不到數據庫索引?
- 共享鎖和排他鎖的使用場景
- 關系型數據庫和非關系數據庫的優缺點
- Mysql 什么情況會造成慢查,如何查看慢查詢
- 如何處理慢查詢,你一般是怎么處理慢查詢的
- Mysql 中 varchar 和 char 的區別
- 數據庫外鍵的優缺點
- 有沒有使用過數據庫的視圖
- Mysql 中插入數據使用自增 id 好還是使用 uuid,為什么?
- Mysql 有哪些數據類型,使用的時候有沒有什么注意點
- Mysql 集群有哪幾種方式,分別適用於什么場景
- Mysql 主從模式如何保證主從強一致性
- Mysql 集群如何保證主從可用性
- Mysql 讀寫分離有哪些解決辦法
數據庫三范式
- 第一范式: 確保每列的原子性,每列都是不可分割的最小數據單元
- 第二范式: 在第一范式的基礎上,要求每列都和主鍵相關
- 第三范式: 在第二范式的基礎上,要求其他列和主鍵是直接相關,而不是間接相關
分別說一下范式和反范式的優缺點
1.范式化
優點:
- 減少數據冗余
- 表中重復數據較少,更新操作比較快
- 范式化的表通常比反范式化的表小
缺點:
- 在查詢的時候通常需要很多的關聯,降低性能
- 增加了索引優化的難度
2.反范式化
優點:
- 可以減少表的關聯
- 更好的進行索引優化
缺點:
- 數據重復冗余
- 對數據表的修改需要更多的成本
Mysql 數據庫索引。B+ 樹和 B 樹的區別
MySQL數據庫索引和存儲引擎有關,MyISAM和InnoDB只支持BTREE索引。MEMORY和HEAP支持HASH和BTREE索引
B+樹和B樹的區別
- B+樹非葉子節點只存儲關鍵字和指向子節點的指針,而B樹還存儲了數據,在同樣大小的情況下,B+樹可以存儲更多的關鍵字
- B+樹葉子節點存儲了所有關鍵字和數據,並且多個節點用鏈表連接。可以快速支撐范圍查找
- B+樹非葉子節點不存儲數據,所以查詢時間復雜度固定為
O(logN)
,B樹查詢時間復雜度不固定,最好是O(1)
參考文章:B+樹和B樹的區別
為什么 B+ 樹比 B 樹更適合應用於數據庫索引,除了數據庫索引,還有什么地方用到了(操作系統的文件索引)
因為B樹葉子節點和非葉子結點都存儲了數據,這樣就導致了非葉子結點能保存的關鍵字和指針變少,如果要保存大量數據,只能增加樹的高度,導致IO操作變多,查詢性能降低
除數據庫索引,還有操作系統的文件索引用到了B樹。參考文章:操作系統 文件索引結構
聚簇索引和非聚簇索引
- 聚簇索引,又叫主鍵索引,每個表只有一個主鍵索引,葉子節點保存主鍵的值和數據
- 非聚簇索引,又叫輔助索引,葉子節點保存索引字段的值和主鍵的值
前綴索引和覆蓋索引
1.前綴索引
對於列的值較長,比如BLOB、TEXT、VARCHAR
,就必須建立前綴索引,即將值的前一部分作為索引。這樣既可以節約空間,又可以提高查詢效率。但無法使用前綴索引做 ORDER BY
和 GROUP BY
,也無法使用前綴索引做覆蓋掃描。
2.覆蓋索引
select
的數據列從索引中就能獲得,不必再從數據表中讀取。如果一個索引包含了(或覆蓋了)滿足查詢語句中字段與條件的數據就叫 做覆蓋索引。
當發起一個被索引覆蓋的查詢(也叫作索引覆蓋查詢)時,在EXPLAIN
的Extra
列可以看到“Using index”
的信息
參考文章:什么叫做覆蓋索引?
介紹一下數據庫的事務
事務是一個操作序列,這些操作要么全部執行,要么都不執行。
事務具有四大特性:A(原子性)、C(一致性)、I(隔離性)、D(持久性)
Mysql 有哪些隔離級別
Mysql 什么情況會造成臟讀、不可重復讀、幻讀?如何解決
- 臟讀:有兩個事務A和B,A讀取已經被B修改但未提交的字段,此時B回滾,那么A讀取的字段就是臨時且無效的。可以提高隔離級別,改成讀已提交
- 不可重復讀: 有兩個事務A和B,A讀取了一個字段值,然后B更新並且提交事務,A再重新讀取這個字段,就和之前不相等了。可以提高隔離級別,改成可重復讀
- 幻讀: 有兩個事務A和B,A讀取某個范圍內的記錄時,B又在該范圍內插入了新的記錄並提交,當事務A再次讀取該范圍的記錄時,會產生幻行。可以升級隔離級別到串行化,或者使用
MVCC + next-key
鎖機制實現
Mysql 在可重復讀的隔離級別下會不會有幻讀的情況,為什么?
不會。InnoDB
存儲引擎默認隔離級別為RR,通過MVCC + next-key
鎖機制解決了幻讀的問題。
PS:其實嚴格來說,是存在幻讀的。。。可以嘗試一下這個操作,A開啟事務,執行查詢,此時B開啟事務新增一條數據並提交,此時A再查詢,發現沒有幻讀,但是如果A執行一個update操作,再查詢,會發現出現了幻讀。我認為應該是A在執行update操作的時候,新建了一條創建版本號為A事務版本號的記錄,然后標記B事務創建的記錄為待刪除的,查詢的版本號依據是刪除版本號為空或大於當前版本號,並且創建版本號小於等於當前事務版本號,那么這里剛剛A更新的這條數據,顯然也符合查詢的條件,所以也會被查出來。
MVCC版本號原理參考文章:Mysql中MVCC的使用及原理詳解
詳細測試參考文章:MySQL可重復讀級別會不會造成幻讀
Mysql 事務是如何實現的
- 原子性:通過
undo log
實現的。每條數據變更都伴隨一條undo log
日志的生成,當系統發生錯誤或執行回滾根據undo log
做逆向操作 - 持久性:通過
redo log
實現的。redo log
記錄了數據的修改日志。數據持久化到磁盤,先是儲存到緩沖池里,然后緩沖池中的數據定期同步到磁盤中,如果系統宕機,可能會丟失數據,系統重啟后會讀取redo log恢復數據 - 隔離性:mysql數據庫通過
MVCC + next-key
機制實現了隔離性 - 一致性:以上3大特性,保障了事務的一致性
Binlog 和 Redo log 的區別是什么,分別是什么用?
binlog
是二進制文件,記錄了對數據庫執行更改的所有操作,不包括select、show
,因為這兩個操作沒有對數據本身做修改。但是若操作了數據,但是數據沒有發生變化,也會記錄到binlog
。常用來數據恢復,數據備份。redo log
又叫做重做日志文件,記錄了事務的修改,不管事務是否提交都記錄下來。在實例和介質失敗時,InnoDB
存儲引擎會使用redo log
恢復到之前的狀態,保證數據的完整性
談一談 MVCC 多版本並發控制
MVCC是通過在每行記錄后面保存兩個隱藏的列來實現的。這兩個列,一個保存了行的創建時間,一個保存行的過期時間(或刪除時間)。當然存儲的並不是實際的時間值,而是系統版本號(system version number)。每開始一個新的事務,系統版本號都會自動遞增。事務開始時刻的系統版本號會作為事務的版本號,用來和查詢到的每行記錄的版本號進行比較。
SELECT
InnoDB會根據以下兩個條件檢查每行記錄:
- InnoDB只查找版本早於當前事務版本的數據行(也就是,行的系統版本號小於或等於事務的系統版本號),這樣可以確保事務讀取的行,要么是在事務開始前已經存在的,要么是事務自身插入或者修改過的。
- 行的刪除版本要么未定義,要么大於當前事務版本號。這可以確保事務讀取到的行,在事務開始之前未被刪除。
只有符合上述兩個條件的記錄,才能返回作為查詢結果
INSERT
InnoDB為新插入的每一行保存當前系統版本號作為行版本號。
DELETE
InnoDB為刪除的每一行保存當前系統版本號作為行刪除標識。
UPDATE
InnoDB為插入一行新記錄,保存當前系統版本號作為行版本號,同時保存當前系統版本號到原來的行作為行刪除標識。
Innodb 和 MyISAM 的區別是什么
- Innodb 支持事務。MyISAM 不支持
- Innodb 支持外鍵。MyISAM 不支持
- Innodb 主鍵索引的葉子節點是數據文件,輔助索引的葉子節點是主鍵的值。MyISAM 的主鍵索引和輔助索引,葉子節點都是數據文件的指針
- Innodb 不保存表的行數,執行
select count(*) from tb
需要全表掃描。MyISAM 用一個變量保存了整個表的行數,執行上述語句只需要讀取該變量,速度很快 - Innodb 所有的表在磁盤上保存在一個文件中。MyISAM 存儲成三個文件。
- Innodb 需要更多的內存和存儲。MyISAM 可被壓縮,存儲空間較小。
- Innodb 移植方案拷貝文件、備份 binlog,或者用 mysqldump,移植較困難。MyISAM 數據以文件形式存儲,在備份和回復時可以單獨針對表進行操作
- Innodb 支持行鎖、表鎖。MyISAM 支持表鎖
- Innodb 在5.7版本之前不支持全文索引。MyISAM 支持全文索引
Innodb 的默認加鎖方式是什么,是怎么實現的
Innodb默認加鎖方式是行級鎖
通過給索引上的索引項加鎖來實現的
如何高效處理大庫 DDL
DDL是值數據定義語句,即建表,建視圖這種,所以這里的問題,我認為可能是考察建表的時候注意事項。
比如數據字段的定義,遵循從小原則。表的創建,降低耦合。
這道題不是很明白,歡迎留言討論。
Mysql 索引重建
- mysqldump導出然后重新導入,
drop index + recreate index
alter table xxx ENGINE = InnoDB
repaire table xxx
,這種對於InnoDB的無效OPTIMIZE TABLE xxx
對於多列索引,哪些情況下能用到索引,哪些情況用不到索引
like
以%
開頭or
查詢,必須左右字段都是索引,否則索引失效- 聯合索引,遵從最左匹配原則,如果不是使用第一列索引,索引失效
- 數據出現隱形轉換,如
varchar
字段沒加單引號,自動轉為int
類型,會使索引失效 - 索引字段使用
not
、<>
、!=
,索引失效 - 索引字段使用函數,索引無效
為什么使用數據庫索引可以提高效率,在什么情況下會用不到數據庫索引?
默認執行SQL
語句是進行全表掃描,遇到匹配條件的就加入搜索結果合集。如果有索引,就會先去索引表中一次定位到特定值的行數,減少遍歷匹配的行數。索引把無序的數據變成了相對有序的數據結構。
什么情況用不到數據庫索引 見上題回答
共享鎖和排他鎖的使用場景
更新、新增、刪除默認加排它鎖,查詢默認不加鎖
共享鎖,使用語法select * from tb lock in share mode
,自身可以讀,其他事務也可以讀(也可以繼續加共享鎖),但是其他事務無法修改
排它鎖,適用語法select * from tb for update
,自身可以進行增刪改查,其他事務無法進行任何操作
關系型數據庫和非關系數據庫的優缺點
關系型數據庫
優點:
- 二維表格,容易理解
- 操作方便
- 易於維護
- 支持SQL
缺點:
- 讀寫性能較差
- 固定的表結構,不夠靈活
- 應對高並發場景,磁盤I/O存在瓶頸
- 海量數據的讀寫性能差
非關系型數據庫
優點:
- 不需要SQL解析,讀寫性能高
- 可以使用硬盤或者內存作為載體,速度快
- 基於鍵值對,數據沒有耦合性,方便擴展
- 部署簡單
缺點:
- 不支持SQL,增加了學習成本
- 沒有事務
Mysql 什么情況會造成慢查,如何查看慢查詢
響應時間超過閾值會產生慢查詢日志。一般有以下情況會造成查詢慢
- 沒有設置索引,或查詢沒有用到索引
- I/O吞吐量過小
- 內存不足
- 網絡速度慢
- 查詢的數據量過大
- 鎖或者死鎖
- 返回了不必要的行或列
- 查詢語句存在問題,需要優化
慢查詢日志默認是關閉的,如果非必要,不要開啟,會影響性能。
使用SHOW VARIABLES LIKE 'slow_query%';
slow_query_log
,慢查詢開啟關閉狀態
slow_query_log_file
,慢查詢日志存儲位置,用文本編輯器打開存儲位置的文件,查詢慢查詢
如何處理慢查詢,你一般是怎么處理慢查詢的
- 把數據、日志、索引放到不同的I/O設備上,增加讀取速度
- 縱向、橫向分割表,減少表的尺寸
- 升級硬件
- 根據查詢條件,建立索引,索引優化
- 提高網速
- 擴大服務器內存
- 分庫分表
Mysql 中 varchar 和 char 的區別
varchar
會根據存儲的內容改變長度,char
是定長,如果長度不夠,則使用空格補齊
數據庫外鍵的優缺點
優點:
- 能最大限度的保證數據的一致性和完整性
- 增加ER圖的可讀性
缺點:
- 影響數據操作的效率
- 增加開發難度,導致表過多
有沒有使用過數據庫的視圖
使用create view view_name as select * from tb
創建視圖
使用select * from view_name
正常查詢視圖
Mysql 中插入數據使用自增 id 好還是使用 uuid,為什么?
- 單實例或單節點組,不擔心網絡爬蟲獲取數據量,推薦使用自增id,性能更好
- 分布式場景。20個節點下的小規模分布式場景,推薦uuid。20~200個節點的中規模分布式場景,推薦自增id+步長的策略。200以上節點,推薦推特雪花算法的全局自增ID
Mysql 有哪些數據類型,使用的時候有沒有什么注意點
- 整數類型:
BIT
、BOOL
、TINY INT
、SMALL INT
、MEDIUM INT
、INT
、BIG INT
- 浮點數類型:
FLOAT
、DOUBLE
、DECIMAL
- 字符串類型:
CHAR
、VARCHAR
、TINY TEXT
、TEXT
、MEDIUM TEXT
、LONGTEXT
、TINY BLOB
、MEDIUM BLOB
、LONG BLOB
- 日期類型:
Date
、DateTime
、TIMESTAMP
、TIME
、YEAR
使用的時候建議遵循從小原則。
- 使用
char
和vahrchar
的時候,注意char
會去掉字符串末尾的空格 - 使用
text
和blob
的時候,注意定期清理碎片空間,使用OPTIMIZE TABLE
命令 - 浮點數會造成精度丟失,盡量使用定點數
DECIMAL
Mysql 集群有哪幾種方式,分別適用於什么場景
組建MySQL集群的方式:
- LVS + Keepalived + MySQL
- DRBD + Heartbeat + MySQL
- MySQL + Proxy
- MySQL Cluster
- MySQL + MHA
- MySQL + MMM
場景:
- 如果是雙主復制,不需要數據拆分,可以使用MHA或Keepalived或Heartbeat
- 如果是雙主復制,需要數據拆分,采用Cobar
- 如果是雙主復制+Slave,還做了數據拆分,需要讀寫分離,采用Amoeba
Mysql 主從模式如何保證主從強一致性
主從復制原理:master寫數據留下寫入日志,slave根據master留下的日志模仿數據執行過程寫入
所以有兩個步驟可能導致主從復制不一致:
- master日志寫入不成功
- slave根據日志模仿不成功
解決辦法;
-
master上修改配置
-
innodb_flush_log_at_trx_commit = 1 sync_binlog = 1
上述兩個選項的作用是:保證每次事務提交后,都能實時刷新到磁盤中,尤其是確保每次事務對應的binlog都能及時刷新到磁盤中
-
-
slave上修改配置
-
master_info_repository = "TABLE" relay_log_info_repository = "TABLE" relay_log_recovery = 1
上述前兩個選項的作用是:確保在slave上和復制相關的元數據表也采用InnoDB引擎,受到InnoDB事務安全的保護,而后一個選項的作用是開啟relay log自動修復機制,發生crash時,會自動判斷哪些relay log需要重新從master上抓取回來再次應用,以此避免部分數據丟失的可能性。
-
Mysql 集群如何保證主從可用性
使用HA檢測工具。HA工具部署在第三台服務器上,同時連接主從,檢測主從是否存活。如果主庫宕機則及時將從庫升級為主庫,將原來的主庫降級為從庫
Mysql 讀寫分離有哪些解決辦法
- 配置多數據源
- 使用中間件代理