MySQL数据库面试题(2020最新版)
你是否有為快速開發(fā)各種報(bào)表而煩惱?遇到類似如下的問題:
- 表格少的,可以用代碼寫,幾十上百張表格呢,純手工需要用多少時(shí)間?
- 格式復(fù)雜,邏輯復(fù)雜的,做起來更是頭大
- 需求總變來變?nèi)?#xff0c;修改和維護(hù)成本太高
- 圖形自己做不美觀,而且工作量巨大
- 用第三方的相對(duì)簡單,但集成和學(xué)習(xí)成本也不小
從各行業(yè)合作伙伴的實(shí)際使用情況,證明使用下文說的報(bào)表做表格和圖形,可以極大的提升效率,節(jié)省成本,詳情請(qǐng)查看文章:https://thinkwon.blog.csdn.net/article/details/125035932
 文章干貨多多,歡迎一鍵三連,謝謝😊😊
Java面試總結(jié)(2021優(yōu)化版)已發(fā)布在個(gè)人微信公眾號(hào)【技術(shù)人成長之路】,優(yōu)化版首先修正了讀者反饋的部分答案存在的錯(cuò)誤,同時(shí)根據(jù)最新面試總結(jié),刪除了低頻問題,添加了一些常見面試題,對(duì)文章進(jìn)行了精簡優(yōu)化,歡迎大家關(guān)注!😊😊
【技術(shù)人成長之路】,助力技術(shù)人成長!更多精彩文章第一時(shí)間在公眾號(hào)發(fā)布哦!
文章目錄
- 數(shù)據(jù)庫基礎(chǔ)知識(shí)
- 為什么要使用數(shù)據(jù)庫
- 什么是SQL?
- 什么是MySQL?
- 數(shù)據(jù)庫三大范式是什么
- mysql有關(guān)權(quán)限的表都有哪幾個(gè)
- MySQL的binlog有有幾種錄入格式?分別有什么區(qū)別?
 
- 數(shù)據(jù)類型
- mysql有哪些數(shù)據(jù)類型
 
- 引擎
- MySQL存儲(chǔ)引擎MyISAM與InnoDB區(qū)別
- MyISAM索引與InnoDB索引的區(qū)別?
- InnoDB引擎的4大特性
- 存儲(chǔ)引擎選擇
 
- 索引
- 什么是索引?
- 索引有哪些優(yōu)缺點(diǎn)?
- 索引使用場景(重點(diǎn))
- 索引有哪幾種類型?
- 索引的數(shù)據(jù)結(jié)構(gòu)(b樹,hash)
- 索引的基本原理
- 索引算法有哪些?
- 索引設(shè)計(jì)的原則?
- 創(chuàng)建索引的原則(重中之重)
- 創(chuàng)建索引的三種方式,刪除索引
- 創(chuàng)建索引時(shí)需要注意什么?
- 使用索引查詢一定能提高查詢的性能嗎?為什么
- 百萬級(jí)別或以上的數(shù)據(jù)如何刪除
- 前綴索引
- 什么是最左前綴原則?什么是最左匹配原則
- B樹和B+樹的區(qū)別
- 使用B樹的好處
- 使用B+樹的好處
- Hash索引和B+樹所有有什么區(qū)別或者說優(yōu)劣呢?
- 數(shù)據(jù)庫為什么使用B+樹而不是B樹
- B+樹在滿足聚簇索引和覆蓋索引的時(shí)候不需要回表查詢數(shù)據(jù),
- 什么是聚簇索引?何時(shí)使用聚簇索引與非聚簇索引
- 非聚簇索引一定會(huì)回表查詢嗎?
- 聯(lián)合索引是什么?為什么需要注意聯(lián)合索引中的順序?
 
- 事務(wù)
- 什么是數(shù)據(jù)庫事務(wù)?
- 事物的四大特性(ACID)介紹一下?
- 什么是臟讀?幻讀?不可重復(fù)讀?
- 什么是事務(wù)的隔離級(jí)別?MySQL的默認(rèn)隔離級(jí)別是什么?
 
- 鎖
- 對(duì)MySQL的鎖了解嗎
- 隔離級(jí)別與鎖的關(guān)系
- 按照鎖的粒度分?jǐn)?shù)據(jù)庫鎖有哪些?鎖機(jī)制與InnoDB鎖算法
- 從鎖的類別上分MySQL都有哪些鎖呢?像上面那樣子進(jìn)行鎖定豈不是有點(diǎn)阻礙并發(fā)效率了
- MySQL中InnoDB引擎的行鎖是怎么實(shí)現(xiàn)的?
- InnoDB存儲(chǔ)引擎的鎖的算法有三種
- 什么是死鎖?怎么解決?
- 數(shù)據(jù)庫的樂觀鎖和悲觀鎖是什么?怎么實(shí)現(xiàn)的?
 
- 視圖
- 為什么要使用視圖?什么是視圖?
- 視圖有哪些特點(diǎn)?
- 視圖的使用場景有哪些?
- 視圖的優(yōu)點(diǎn)
- 視圖的缺點(diǎn)
- 什么是游標(biāo)?
 
- 存儲(chǔ)過程與函數(shù)
- 什么是存儲(chǔ)過程?有哪些優(yōu)缺點(diǎn)?
 
- 觸發(fā)器
- 什么是觸發(fā)器?觸發(fā)器的使用場景有哪些?
- MySQL中都有哪些觸發(fā)器?
 
- 常用SQL語句
- SQL語句主要分為哪幾類
- 超鍵、候選鍵、主鍵、外鍵分別是什么?
- SQL 約束有哪幾種?
- 六種關(guān)聯(lián)查詢
- 什么是子查詢
- 子查詢的三種情況
- mysql中 in 和 exists 區(qū)別
- varchar與char的區(qū)別
- varchar(50)中50的涵義
- int(20)中20的涵義
- mysql為什么這么設(shè)計(jì)
- mysql中int(10)和char(10)以及varchar(10)的區(qū)別
- FLOAT和DOUBLE的區(qū)別是什么?
- drop、delete與truncate的區(qū)別
- UNION與UNION ALL的區(qū)別?
 
- SQL優(yōu)化
- 如何定位及優(yōu)化SQL語句的性能問題?創(chuàng)建的索引有沒有被使用到?或者說怎么才可以知道這條語句運(yùn)行很慢的原因?
- SQL的生命周期?
- 大表數(shù)據(jù)查詢,怎么優(yōu)化
- 超大分頁怎么處理?
- mysql 分頁
- 慢查詢?nèi)罩?/li>
- 關(guān)心過業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎?統(tǒng)計(jì)過慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過?
- 為什么要盡量設(shè)定一個(gè)主鍵?
- 主鍵使用自增ID還是UUID?
- 字段為什么要求定義為not null?
- 如果要存儲(chǔ)用戶的密碼散列,應(yīng)該使用什么字段進(jìn)行存儲(chǔ)?
- 優(yōu)化查詢過程中的數(shù)據(jù)訪問
- 優(yōu)化長難的查詢語句
- 優(yōu)化特定類型的查詢語句
- 優(yōu)化關(guān)聯(lián)查詢
- 優(yōu)化子查詢
- 優(yōu)化LIMIT分頁
- 優(yōu)化UNION查詢
- 優(yōu)化WHERE子句
 
- 數(shù)據(jù)庫優(yōu)化
- 為什么要優(yōu)化
- 數(shù)據(jù)庫結(jié)構(gòu)優(yōu)化
- MySQL數(shù)據(jù)庫cpu飆升到500%的話他怎么處理?
- 大表怎么優(yōu)化?某個(gè)表有近千萬數(shù)據(jù),CRUD比較慢,如何優(yōu)化?分庫分表了是怎么做的?分表分庫了有什么問題?有用到中間件么?他們的原理知道么?
- 垂直分表
- 適用場景
- 缺點(diǎn)
 
- 水平分表:
- 適用場景
- 水平切分的缺點(diǎn)
 
 
- MySQL的復(fù)制原理以及流程
- 讀寫分離有哪些解決方案?
- 備份計(jì)劃,mysqldump以及xtranbackup的實(shí)現(xiàn)原理
- 數(shù)據(jù)表損壞的修復(fù)方式有哪些?
 
 
Java面試總結(jié)匯總,整理了包括Java基礎(chǔ)知識(shí),集合容器,并發(fā)編程,JVM,常用開源框架Spring,MyBatis,數(shù)據(jù)庫,中間件等,包含了作為一個(gè)Java工程師在面試中需要用到或者可能用到的絕大部分知識(shí)。歡迎大家閱讀,本人見識(shí)有限,寫的博客難免有錯(cuò)誤或者疏忽的地方,還望各位大佬指點(diǎn),在此表示感激不盡。文章持續(xù)更新中…
| 1 | Java基礎(chǔ)知識(shí)面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104390612 | 
| 2 | Java集合容器面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104588551 | 
| 3 | Java異常面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104390689 | 
| 4 | 并發(fā)編程面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104863992 | 
| 5 | JVM面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104390752 | 
| 6 | Spring面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104397516 | 
| 7 | Spring MVC面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104397427 | 
| 8 | Spring Boot面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104397299 | 
| 9 | Spring Cloud面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104397367 | 
| 10 | MyBatis面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/101292950 | 
| 11 | Redis面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/103522351 | 
| 12 | MySQL數(shù)據(jù)庫面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104778621 | 
| 13 | 消息中間件MQ與RabbitMQ面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104588612 | 
| 14 | Dubbo面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104390006 | 
| 15 | Linux面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104588679 | 
| 16 | Tomcat面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104397665 | 
| 17 | ZooKeeper面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104397719 | 
| 18 | Netty面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/104391081 | 
| 19 | 架構(gòu)設(shè)計(jì)&分布式&數(shù)據(jù)結(jié)構(gòu)與算法面試題(2020最新版) | https://thinkwon.blog.csdn.net/article/details/105870730 | 
數(shù)據(jù)庫基礎(chǔ)知識(shí)
為什么要使用數(shù)據(jù)庫
數(shù)據(jù)保存在內(nèi)存
優(yōu)點(diǎn): 存取速度快
缺點(diǎn): 數(shù)據(jù)不能永久保存
數(shù)據(jù)保存在文件
優(yōu)點(diǎn): 數(shù)據(jù)永久保存
缺點(diǎn):1)速度比內(nèi)存操作慢,頻繁的IO操作。2)查詢數(shù)據(jù)不方便
數(shù)據(jù)保存在數(shù)據(jù)庫
1)數(shù)據(jù)永久保存
2)使用SQL語句,查詢方便效率高。
3)管理數(shù)據(jù)方便
什么是SQL?
結(jié)構(gòu)化查詢語言(Structured Query Language)簡稱SQL,是一種數(shù)據(jù)庫查詢語言。
作用:用于存取數(shù)據(jù)、查詢、更新和管理關(guān)系數(shù)據(jù)庫系統(tǒng)。
什么是MySQL?
MySQL是一個(gè)關(guān)系型數(shù)據(jù)庫管理系統(tǒng),由瑞典MySQL AB 公司開發(fā),屬于 Oracle 旗下產(chǎn)品。MySQL 是最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,在 WEB 應(yīng)用方面,MySQL是最好的 RDBMS (Relational Database Management System,關(guān)系數(shù)據(jù)庫管理系統(tǒng)) 應(yīng)用軟件之一。在Java企業(yè)級(jí)開發(fā)中非常常用,因?yàn)?MySQL 是開源免費(fèi)的,并且方便擴(kuò)展。
數(shù)據(jù)庫三大范式是什么
第一范式:每個(gè)列都不可以再拆分。
第二范式:在第一范式的基礎(chǔ)上,非主鍵列完全依賴于主鍵,而不能是依賴于主鍵的一部分。
第三范式:在第二范式的基礎(chǔ)上,非主鍵列只依賴于主鍵,不依賴于其他非主鍵。
在設(shè)計(jì)數(shù)據(jù)庫結(jié)構(gòu)的時(shí)候,要盡量遵守三范式,如果不遵守,必須有足夠的理由。比如性能。事實(shí)上我們經(jīng)常會(huì)為了性能而妥協(xié)數(shù)據(jù)庫的設(shè)計(jì)。
mysql有關(guān)權(quán)限的表都有哪幾個(gè)
MySQL服務(wù)器通過權(quán)限表來控制用戶對(duì)數(shù)據(jù)庫的訪問,權(quán)限表存放在mysql數(shù)據(jù)庫里,由mysql_install_db腳本初始化。這些權(quán)限表分別user,db,table_priv,columns_priv和host。下面分別介紹一下這些表的結(jié)構(gòu)和內(nèi)容:
- user權(quán)限表:記錄允許連接到服務(wù)器的用戶帳號(hào)信息,里面的權(quán)限是全局級(jí)的。
- db權(quán)限表:記錄各個(gè)帳號(hào)在各個(gè)數(shù)據(jù)庫上的操作權(quán)限。
- table_priv權(quán)限表:記錄數(shù)據(jù)表級(jí)的操作權(quán)限。
- columns_priv權(quán)限表:記錄數(shù)據(jù)列級(jí)的操作權(quán)限。
- host權(quán)限表:配合db權(quán)限表對(duì)給定主機(jī)上數(shù)據(jù)庫級(jí)操作權(quán)限作更細(xì)致的控制。這個(gè)權(quán)限表不受GRANT和REVOKE語句的影響。
MySQL的binlog有有幾種錄入格式?分別有什么區(qū)別?
有三種格式,statement,row和mixed。
- statement模式下,每一條會(huì)修改數(shù)據(jù)的sql都會(huì)記錄在binlog中。不需要記錄每一行的變化,減少了binlog日志量,節(jié)約了IO,提高性能。由于sql的執(zhí)行是有上下文的,因此在保存的時(shí)候需要保存相關(guān)的信息,同時(shí)還有一些使用了函數(shù)之類的語句無法被記錄復(fù)制。
- row級(jí)別下,不記錄sql語句上下文相關(guān)信息,僅保存哪條記錄被修改。記錄單元為每一行的改動(dòng),基本是可以全部記下來但是由于很多操作,會(huì)導(dǎo)致大量行的改動(dòng)(比如alter table),因此這種模式的文件保存的信息太多,日志量太大。
- mixed,一種折中的方案,普通操作使用statement記錄,當(dāng)無法使用statement的時(shí)候使用row。
此外,新版的MySQL中對(duì)row級(jí)別也做了一些優(yōu)化,當(dāng)表結(jié)構(gòu)發(fā)生變化的時(shí)候,會(huì)記錄語句而不是逐行記錄。
數(shù)據(jù)類型
mysql有哪些數(shù)據(jù)類型
| 整數(shù)類型 | tinyInt | 很小的整數(shù)(8位二進(jìn)制) | 
| smallint | 小的整數(shù)(16位二進(jìn)制) | |
| mediumint | 中等大小的整數(shù)(24位二進(jìn)制) | |
| int(integer) | 普通大小的整數(shù)(32位二進(jìn)制) | |
| 小數(shù)類型 | float | 單精度浮點(diǎn)數(shù) | 
| double | 雙精度浮點(diǎn)數(shù) | |
| decimal(m,d) | 壓縮嚴(yán)格的定點(diǎn)數(shù) | |
| 日期類型 | year | YYYY 1901~2155 | 
| time | HH:MM:SS -838:59:59~838:59:59 | |
| date | YYYY-MM-DD 1000-01-01~9999-12-3 | |
| datetime | YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00~ 9999-12-31 23:59:59 | |
| timestamp | YYYY-MM-DD HH:MM:SS 19700101 00:00:01 UTC~2038-01-19 03:14:07UTC | |
| 文本、二進(jìn)制類型 | CHAR(M) | M為0~255之間的整數(shù) | 
| VARCHAR(M) | M為0~65535之間的整數(shù) | |
| TINYBLOB | 允許長度0~255字節(jié) | |
| BLOB | 允許長度0~65535字節(jié) | |
| MEDIUMBLOB | 允許長度0~167772150字節(jié) | |
| LONGBLOB | 允許長度0~4294967295字節(jié) | |
| TINYTEXT | 允許長度0~255字節(jié) | |
| TEXT | 允許長度0~65535字節(jié) | |
| MEDIUMTEXT | 允許長度0~167772150字節(jié) | |
| LONGTEXT | 允許長度0~4294967295字節(jié) | |
| VARBINARY(M) | 允許長度0~M個(gè)字節(jié)的變長字節(jié)字符串 | |
| BINARY(M) | 允許長度0~M個(gè)字節(jié)的定長字節(jié)字符串 | 
-  1、整數(shù)類型,包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分別表示1字節(jié)、2字節(jié)、3字節(jié)、4字節(jié)、8字節(jié)整數(shù)。任何整數(shù)類型都可以加上UNSIGNED屬性,表示數(shù)據(jù)是無符號(hào)的,即非負(fù)整數(shù)。 
 長度:整數(shù)類型可以被指定長度,例如:INT(11)表示長度為11的INT類型。長度在大多數(shù)場景是沒有意義的,它不會(huì)限制值的合法范圍,只會(huì)影響顯示字符的個(gè)數(shù),而且需要和UNSIGNED ZEROFILL屬性配合使用才有意義。
 例子,假定類型設(shè)定為INT(5),屬性為UNSIGNED ZEROFILL,如果用戶插入的數(shù)據(jù)為12的話,那么數(shù)據(jù)庫實(shí)際存儲(chǔ)數(shù)據(jù)為00012。
-  2、實(shí)數(shù)類型,包括FLOAT、DOUBLE、DECIMAL。 
 DECIMAL可以用于存儲(chǔ)比BIGINT還大的整型,能存儲(chǔ)精確的小數(shù)。
 而FLOAT和DOUBLE是有取值范圍的,并支持使用標(biāo)準(zhǔn)的浮點(diǎn)進(jìn)行近似計(jì)算。
 計(jì)算時(shí)FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字符串進(jìn)行處理。
-  3、字符串類型,包括VARCHAR、CHAR、TEXT、BLOB 
 VARCHAR用于存儲(chǔ)可變長字符串,它比定長類型更節(jié)省空間。
 VARCHAR使用額外1或2個(gè)字節(jié)存儲(chǔ)字符串長度。列長度小于255字節(jié)時(shí),使用1字節(jié)表示,否則使用2字節(jié)表示。
 VARCHAR存儲(chǔ)的內(nèi)容超出設(shè)置的長度時(shí),內(nèi)容會(huì)被截?cái)唷?br /> CHAR是定長的,根據(jù)定義的字符串長度分配足夠的空間。
 CHAR會(huì)根據(jù)需要使用空格進(jìn)行填充方便比較。
 CHAR適合存儲(chǔ)很短的字符串,或者所有值都接近同一個(gè)長度。
 CHAR存儲(chǔ)的內(nèi)容超出設(shè)置的長度時(shí),內(nèi)容同樣會(huì)被截?cái)唷?/p>使用策略: 
 對(duì)于經(jīng)常變更的數(shù)據(jù)來說,CHAR比VARCHAR更好,因?yàn)镃HAR不容易產(chǎn)生碎片。
 對(duì)于非常短的列,CHAR比VARCHAR在存儲(chǔ)空間上更有效率。
 使用時(shí)要注意只分配需要的空間,更長的列排序時(shí)會(huì)消耗更多內(nèi)存。
 盡量避免使用TEXT/BLOB類型,查詢時(shí)會(huì)使用臨時(shí)表,導(dǎo)致嚴(yán)重的性能開銷。
-  4、枚舉類型(ENUM),把不重復(fù)的數(shù)據(jù)存儲(chǔ)為一個(gè)預(yù)定義的集合。 
 有時(shí)可以使用ENUM代替常用的字符串類型。
 ENUM存儲(chǔ)非常緊湊,會(huì)把列表值壓縮到一個(gè)或兩個(gè)字節(jié)。
 ENUM在內(nèi)部存儲(chǔ)時(shí),其實(shí)存的是整數(shù)。
 盡量避免使用數(shù)字作為ENUM枚舉的常量,因?yàn)槿菀谆靵y。
 排序是按照內(nèi)部存儲(chǔ)的整數(shù)
-  5、日期和時(shí)間類型,盡量使用timestamp,空間效率高于datetime, 
 用整數(shù)保存時(shí)間戳通常不方便處理。
 如果需要存儲(chǔ)微妙,可以使用bigint存儲(chǔ)。
 看到這里,這道真題是不是就比較容易回答了。
引擎
MySQL存儲(chǔ)引擎MyISAM與InnoDB區(qū)別
存儲(chǔ)引擎Storage engine:MySQL中的數(shù)據(jù)、索引以及其他對(duì)象是如何存儲(chǔ)的,是一套文件系統(tǒng)的實(shí)現(xiàn)。
常用的存儲(chǔ)引擎有以下:
- Innodb引擎:Innodb引擎提供了對(duì)數(shù)據(jù)庫ACID事務(wù)的支持。并且還提供了行級(jí)鎖和外鍵的約束。它的設(shè)計(jì)的目標(biāo)就是處理大數(shù)據(jù)容量的數(shù)據(jù)庫系統(tǒng)。
- MyIASM引擎(原本Mysql的默認(rèn)引擎):不提供事務(wù)的支持,也不支持行級(jí)鎖和外鍵。
- MEMORY引擎:所有的數(shù)據(jù)都在內(nèi)存中,數(shù)據(jù)的處理速度快,但是安全性不高。
MyISAM與InnoDB區(qū)別
| 存儲(chǔ)結(jié)構(gòu) | 每張表被存放在三個(gè)文件:frm-表格定義、MYD(MYData)-數(shù)據(jù)文件、MYI(MYIndex)-索引文件 | 所有的表都保存在同一個(gè)數(shù)據(jù)文件中(也可能是多個(gè)文件,或者是獨(dú)立的表空間文件),InnoDB表的大小只受限于操作系統(tǒng)文件的大小,一般為2GB | 
| 存儲(chǔ)空間 | MyISAM可被壓縮,存儲(chǔ)空間較小 | InnoDB的表需要更多的內(nèi)存和存儲(chǔ),它會(huì)在主內(nèi)存中建立其專用的緩沖池用于高速緩沖數(shù)據(jù)和索引 | 
| 可移植性、備份及恢復(fù) | 由于MyISAM的數(shù)據(jù)是以文件的形式存儲(chǔ),所以在跨平臺(tái)的數(shù)據(jù)轉(zhuǎn)移中會(huì)很方便。在備份和恢復(fù)時(shí)可單獨(dú)針對(duì)某個(gè)表進(jìn)行操作 | 免費(fèi)的方案可以是拷貝數(shù)據(jù)文件、備份 binlog,或者用 mysqldump,在數(shù)據(jù)量達(dá)到幾十G的時(shí)候就相對(duì)痛苦了 | 
| 文件格式 | 數(shù)據(jù)和索引是分別存儲(chǔ)的,數(shù)據(jù).MYD,索引.MYI | 數(shù)據(jù)和索引是集中存儲(chǔ)的,.ibd | 
| 記錄存儲(chǔ)順序 | 按記錄插入順序保存 | 按主鍵大小有序插入 | 
| 外鍵 | 不支持 | 支持 | 
| 事務(wù) | 不支持 | 支持 | 
| 鎖支持(鎖是避免資源爭用的一個(gè)機(jī)制,MySQL鎖對(duì)用戶幾乎是透明的) | 表級(jí)鎖定 | 行級(jí)鎖定、表級(jí)鎖定,鎖定力度小并發(fā)能力高 | 
| SELECT | MyISAM更優(yōu) | |
| INSERT、UPDATE、DELETE | InnoDB更優(yōu) | |
| select count(*) | myisam更快,因?yàn)閙yisam內(nèi)部維護(hù)了一個(gè)計(jì)數(shù)器,可以直接調(diào)取。 | |
| 索引的實(shí)現(xiàn)方式 | B+樹索引,myisam 是堆表 | B+樹索引,Innodb 是索引組織表 | 
| 哈希索引 | 不支持 | 支持 | 
| 全文索引 | 支持 | 不支持 | 
MyISAM索引與InnoDB索引的區(qū)別?
- InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
- InnoDB的主鍵索引的葉子節(jié)點(diǎn)存儲(chǔ)著行數(shù)據(jù),因此主鍵索引非常高效。
- MyISAM索引的葉子節(jié)點(diǎn)存儲(chǔ)的是行數(shù)據(jù)地址,需要再尋址一次才能得到數(shù)據(jù)。
- InnoDB非主鍵索引的葉子節(jié)點(diǎn)存儲(chǔ)的是主鍵和其他帶索引的列數(shù)據(jù),因此查詢時(shí)做到覆蓋索引會(huì)非常高效。
InnoDB引擎的4大特性
-  插入緩沖(insert buffer) 
-  二次寫(double write) 
-  自適應(yīng)哈希索引(ahi) 
-  預(yù)讀(read ahead) 
存儲(chǔ)引擎選擇
如果沒有特別的需求,使用默認(rèn)的Innodb即可。
MyISAM:以讀寫插入為主的應(yīng)用程序,比如博客系統(tǒng)、新聞門戶網(wǎng)站。
Innodb:更新(刪除)操作頻率也高,或者要保證數(shù)據(jù)的完整性;并發(fā)量高,支持事務(wù)和外鍵。比如OA自動(dòng)化辦公系統(tǒng)。
索引
什么是索引?
索引是一種特殊的文件(InnoDB數(shù)據(jù)表上的索引是表空間的一個(gè)組成部分),它們包含著對(duì)數(shù)據(jù)表里所有記錄的引用指針。
索引是一種數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)庫索引,是數(shù)據(jù)庫管理系統(tǒng)中一個(gè)排序的數(shù)據(jù)結(jié)構(gòu),以協(xié)助快速查詢、更新數(shù)據(jù)庫表中數(shù)據(jù)。索引的實(shí)現(xiàn)通常使用B樹及其變種B+樹。
更通俗的說,索引就相當(dāng)于目錄。為了方便查找書中的內(nèi)容,通過對(duì)內(nèi)容建立索引形成目錄。索引是一個(gè)文件,它是要占據(jù)物理空間的。
索引有哪些優(yōu)缺點(diǎn)?
索引的優(yōu)點(diǎn)
- 可以大大加快數(shù)據(jù)的檢索速度,這也是創(chuàng)建索引的最主要的原因。
- 通過使用索引,可以在查詢的過程中,使用優(yōu)化隱藏器,提高系統(tǒng)的性能。
索引的缺點(diǎn)
- 時(shí)間方面:創(chuàng)建索引和維護(hù)索引要耗費(fèi)時(shí)間,具體地,當(dāng)對(duì)表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時(shí)候,索引也要?jiǎng)討B(tài)的維護(hù),會(huì)降低增/改/刪的執(zhí)行效率;
- 空間方面:索引需要占物理空間。
索引使用場景(重點(diǎn))
where
上圖中,根據(jù)id查詢記錄,因?yàn)閕d字段僅建立了主鍵索引,因此此SQL執(zhí)行可選的索引只有主鍵索引,如果有多個(gè),最終會(huì)選一個(gè)較優(yōu)的作為檢索的依據(jù)。
-- 增加一個(gè)沒有建立索引的字段 alter table innodb1 add sex char(1); -- 按sex檢索時(shí)可選的索引為null EXPLAIN SELECT * from innodb1 where sex='男';可以嘗試在一個(gè)字段未建立索引時(shí),根據(jù)該字段查詢的效率,然后對(duì)該字段建立索引(alter table 表名 add index(字段名)),同樣的SQL執(zhí)行的效率,你會(huì)發(fā)現(xiàn)查詢效率會(huì)有明顯的提升(數(shù)據(jù)量越大越明顯)。
order by
當(dāng)我們使用order by將查詢結(jié)果按照某個(gè)字段排序時(shí),如果該字段沒有建立索引,那么執(zhí)行計(jì)劃會(huì)將查詢出的所有數(shù)據(jù)使用外部排序(將數(shù)據(jù)從硬盤分批讀取到內(nèi)存使用內(nèi)部排序,最后合并排序結(jié)果),這個(gè)操作是很影響性能的,因?yàn)樾枰獙⒉樵兩婕暗降乃袛?shù)據(jù)從磁盤中讀到內(nèi)存(如果單條數(shù)據(jù)過大或者數(shù)據(jù)量過多都會(huì)降低效率),更無論讀到內(nèi)存之后的排序了。
但是如果我們對(duì)該字段建立索引alter table 表名 add index(字段名),那么由于索引本身是有序的,因此直接按照索引的順序和映射關(guān)系逐條取出數(shù)據(jù)即可。而且如果分頁的,那么只用取出索引表某個(gè)范圍內(nèi)的索引對(duì)應(yīng)的數(shù)據(jù),而不用像上述那取出所有數(shù)據(jù)進(jìn)行排序再返回某個(gè)范圍內(nèi)的數(shù)據(jù)。(從磁盤取數(shù)據(jù)是最影響性能的)
join
對(duì)join語句匹配關(guān)系(on)涉及的字段建立索引能夠提高效率
索引覆蓋
如果要查詢的字段都建立過索引,那么引擎會(huì)直接在索引表中查詢而不會(huì)訪問原始數(shù)據(jù)(否則只要有一個(gè)字段沒有建立索引就會(huì)做全表掃描),這叫索引覆蓋。因此我們需要盡可能的在select后只寫必要的查詢字段,以增加索引覆蓋的幾率。
這里值得注意的是不要想著為每個(gè)字段建立索引,因?yàn)閮?yōu)先使用索引的優(yōu)勢就在于其體積小。
索引有哪幾種類型?
主鍵索引: 數(shù)據(jù)列不允許重復(fù),不允許為NULL,一個(gè)表只能有一個(gè)主鍵。
唯一索引: 數(shù)據(jù)列不允許重復(fù),允許為NULL值,一個(gè)表允許多個(gè)列創(chuàng)建唯一索引。
-  可以通過 ALTER TABLE table_name ADD UNIQUE (column); 創(chuàng)建唯一索引 
-  可以通過 ALTER TABLE table_name ADD UNIQUE (column1,column2); 創(chuàng)建唯一組合索引 
普通索引: 基本的索引類型,沒有唯一性的限制,允許為NULL值。
-  可以通過ALTER TABLE table_name ADD INDEX index_name (column);創(chuàng)建普通索引 
-  可以通過ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);創(chuàng)建組合索引 
全文索引: 是目前搜索引擎使用的一種關(guān)鍵技術(shù)。
- 可以通過ALTER TABLE table_name ADD FULLTEXT (column);創(chuàng)建全文索引
索引的數(shù)據(jù)結(jié)構(gòu)(b樹,hash)
索引的數(shù)據(jù)結(jié)構(gòu)和具體存儲(chǔ)引擎的實(shí)現(xiàn)有關(guān),在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經(jīng)常使用的InnoDB存儲(chǔ)引擎的默認(rèn)索引實(shí)現(xiàn)為:B+樹索引。對(duì)于哈希索引來說,底層的數(shù)據(jù)結(jié)構(gòu)就是哈希表,因此在絕大多數(shù)需求為單條記錄查詢的時(shí)候,可以選擇哈希索引,查詢性能最快;其余大部分場景,建議選擇BTree索引。
1)B樹索引
mysql通過存儲(chǔ)引擎取數(shù)據(jù),基本上90%的人用的就是InnoDB了,按照實(shí)現(xiàn)方式分,InnoDB的索引類型目前只有兩種:BTREE(B樹)索引和HASH索引。B樹索引是Mysql數(shù)據(jù)庫中使用最頻繁的索引類型,基本所有存儲(chǔ)引擎都支持BTree索引。通常我們說的索引不出意外指的就是(B樹)索引(實(shí)際是用B+樹實(shí)現(xiàn)的,因?yàn)樵诓榭幢硭饕龝r(shí),mysql一律打印BTREE,所以簡稱為B樹索引)
查詢方式:
主鍵索引區(qū):PI(關(guān)聯(lián)保存的時(shí)數(shù)據(jù)的地址)按主鍵查詢,
普通索引區(qū):si(關(guān)聯(lián)的id的地址,然后再到達(dá)上面的地址)。所以按主鍵查詢,速度最快
B+tree性質(zhì):
1.)n棵子tree的節(jié)點(diǎn)包含n個(gè)關(guān)鍵字,不用來保存數(shù)據(jù)而是保存數(shù)據(jù)的索引。
2.)所有的葉子結(jié)點(diǎn)中包含了全部關(guān)鍵字的信息,及指向含這些關(guān)鍵字記錄的指針,且葉子結(jié)點(diǎn)本身依關(guān)鍵字的大小自小而大順序鏈接。
3.)所有的非終端結(jié)點(diǎn)可以看成是索引部分,結(jié)點(diǎn)中僅含其子樹中的最大(或最小)關(guān)鍵字。
4.)B+ 樹中,數(shù)據(jù)對(duì)象的插入和刪除僅在葉節(jié)點(diǎn)上進(jìn)行。
5.)B+樹有2個(gè)頭指針,一個(gè)是樹的根節(jié)點(diǎn),一個(gè)是最小關(guān)鍵碼的葉節(jié)點(diǎn)。
2)哈希索引
簡要說下,類似于數(shù)據(jù)結(jié)構(gòu)中簡單實(shí)現(xiàn)的HASH表(散列表)一樣,當(dāng)我們?cè)趍ysql中用哈希索引時(shí),主要就是通過Hash算法(常見的Hash算法有直接定址法、平方取中法、折疊法、除數(shù)取余法、隨機(jī)數(shù)法),將數(shù)據(jù)庫字段數(shù)據(jù)轉(zhuǎn)換成定長的Hash值,與這條數(shù)據(jù)的行指針一并存入Hash表的對(duì)應(yīng)位置;如果發(fā)生Hash碰撞(兩個(gè)不同關(guān)鍵字的Hash值相同),則在對(duì)應(yīng)Hash鍵下以鏈表形式存儲(chǔ)。當(dāng)然這只是簡略模擬圖。
索引的基本原理
索引用來快速地尋找那些具有特定值的記錄。如果沒有索引,一般來說執(zhí)行查詢時(shí)遍歷整張表。
索引的原理很簡單,就是把無序的數(shù)據(jù)變成有序的查詢
把創(chuàng)建了索引的列的內(nèi)容進(jìn)行排序
對(duì)排序結(jié)果生成倒排表
在倒排表內(nèi)容上拼上數(shù)據(jù)地址鏈
在查詢的時(shí)候,先拿到倒排表內(nèi)容,再取出數(shù)據(jù)地址鏈,從而拿到具體數(shù)據(jù)
索引算法有哪些?
索引算法有 BTree算法和Hash算法
BTree算法
BTree是最常用的mysql數(shù)據(jù)庫索引算法,也是mysql默認(rèn)的算法。因?yàn)樗粌H可以被用在=,>,>=,<,<=和between這些比較操作符上,而且還可以用于like操作符,只要它的查詢條件是一個(gè)不以通配符開頭的常量, 例如:
-- 只要它的查詢條件是一個(gè)不以通配符開頭的常量 select * from user where name like 'jack%'; -- 如果一通配符開頭,或者沒有使用常量,則不會(huì)使用索引,例如: select * from user where name like '%jack';Hash算法
Hash Hash索引只能用于對(duì)等比較,例如=,<=>(相當(dāng)于=)操作符。由于是一次定位數(shù)據(jù),不像BTree索引需要從根節(jié)點(diǎn)到枝節(jié)點(diǎn),最后才能訪問到頁節(jié)點(diǎn)這樣多次IO訪問,所以檢索效率遠(yuǎn)高于BTree索引。
索引設(shè)計(jì)的原則?
創(chuàng)建索引的原則(重中之重)
索引雖好,但也不是無限制的使用,最好符合一下幾個(gè)原則
1) 最左前綴匹配原則,組合索引非常重要的原則,mysql會(huì)一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整。
2)較頻繁作為查詢條件的字段才去創(chuàng)建索引
3)更新頻繁字段不適合創(chuàng)建索引
4)若是不能有效區(qū)分?jǐn)?shù)據(jù)的列不適合做索引列(如性別,男女未知,最多也就三種,區(qū)分度實(shí)在太低)
5)盡量的擴(kuò)展索引,不要新建索引。比如表中已經(jīng)有a的索引,現(xiàn)在要加(a,b)的索引,那么只需要修改原來的索引即可。
6)定義有外鍵的數(shù)據(jù)列一定要建立索引。
7)對(duì)于那些查詢中很少涉及的列,重復(fù)值比較多的列不要建立索引。
8)對(duì)于定義為text、image和bit的數(shù)據(jù)類型的列不要建立索引。
創(chuàng)建索引的三種方式,刪除索引
第一種方式:在執(zhí)行CREATE TABLE時(shí)創(chuàng)建索引
CREATE TABLE user_index2 (id INT auto_increment PRIMARY KEY,first_name VARCHAR (16),last_name VARCHAR (16),id_card VARCHAR (18),information text,KEY name (first_name, last_name),FULLTEXT KEY (information),UNIQUE KEY (id_card) );第二種方式:使用ALTER TABLE命令去增加索引
ALTER TABLE table_name ADD INDEX index_name (column_list);ALTER TABLE用來創(chuàng)建普通索引、UNIQUE索引或PRIMARY KEY索引。
其中table_name是要增加索引的表名,column_list指出對(duì)哪些列進(jìn)行索引,多列時(shí)各列之間用逗號(hào)分隔。
索引名index_name可自己命名,缺省時(shí),MySQL將根據(jù)第一個(gè)索引列賦一個(gè)名稱。另外,ALTER TABLE允許在單個(gè)語句中更改多個(gè)表,因此可以在同時(shí)創(chuàng)建多個(gè)索引。
第三種方式:使用CREATE INDEX命令創(chuàng)建
CREATE INDEX index_name ON table_name (column_list);CREATE INDEX可對(duì)表增加普通索引或UNIQUE索引。(但是,不能創(chuàng)建PRIMARY KEY索引)
刪除索引
根據(jù)索引名刪除普通索引、唯一索引、全文索引:alter table 表名 drop KEY 索引名
alter table user_index drop KEY name; alter table user_index drop KEY id_card; alter table user_index drop KEY information;刪除主鍵索引:alter table 表名 drop primary key(因?yàn)橹麈I只有一個(gè))。這里值得注意的是,如果主鍵自增長,那么不能直接執(zhí)行此操作(自增長依賴于主鍵索引):
需要取消自增長再行刪除:
alter table user_index -- 重新定義字段 MODIFY id int, drop PRIMARY KEY但通常不會(huì)刪除主鍵,因?yàn)樵O(shè)計(jì)主鍵一定與業(yè)務(wù)邏輯無關(guān)。
創(chuàng)建索引時(shí)需要注意什么?
- 非空字段:應(yīng)該指定列為NOT NULL,除非你想存儲(chǔ)NULL。在mysql中,含有空值的列很難進(jìn)行查詢優(yōu)化,因?yàn)樗鼈兪沟盟饕⑺饕慕y(tǒng)計(jì)信息以及比較運(yùn)算更加復(fù)雜。你應(yīng)該用0、一個(gè)特殊的值或者一個(gè)空串代替空值;
- 取值離散大的字段:(變量各個(gè)取值之間的差異程度)的列放到聯(lián)合索引的前面,可以通過count()函數(shù)查看字段的差異值,返回值越大說明字段的唯一值越多字段的離散程度高;
- 索引字段越小越好:數(shù)據(jù)庫的數(shù)據(jù)存儲(chǔ)以頁為單位一頁存儲(chǔ)的數(shù)據(jù)越多一次IO操作獲取的數(shù)據(jù)越大效率越高。
使用索引查詢一定能提高查詢的性能嗎?為什么
通常,通過索引查詢數(shù)據(jù)比全表掃描要快。但是我們也必須注意到它的代價(jià)。
- 索引需要空間來存儲(chǔ),也需要定期維護(hù), 每當(dāng)有記錄在表中增減或索引列被修改時(shí),索引本身也會(huì)被修改。 這意味著每條記錄的INSERT,DELETE,UPDATE將為此多付出4,5 次的磁盤I/O。 因?yàn)樗饕枰~外的存儲(chǔ)空間和處理,那些不必要的索引反而會(huì)使查詢反應(yīng)時(shí)間變慢。使用索引查詢不一定能提高查詢性能,索引范圍查詢(INDEX RANGE SCAN)適用于兩種情況:
- 基于一個(gè)范圍的檢索,一般查詢返回結(jié)果集小于表中記錄數(shù)的30%
- 基于非唯一性索引的檢索
百萬級(jí)別或以上的數(shù)據(jù)如何刪除
關(guān)于索引:由于索引需要額外的維護(hù)成本,因?yàn)樗饕募菃为?dú)存在的文件,所以當(dāng)我們對(duì)數(shù)據(jù)的增加,修改,刪除,都會(huì)產(chǎn)生額外的對(duì)索引文件的操作,這些操作需要消耗額外的IO,會(huì)降低增/改/刪的執(zhí)行效率。所以,在我們刪除數(shù)據(jù)庫百萬級(jí)別數(shù)據(jù)的時(shí)候,查詢MySQL官方手冊(cè)得知?jiǎng)h除數(shù)據(jù)的速度和創(chuàng)建的索引數(shù)量是成正比的。
前綴索引
語法:index(field(10)),使用字段值的前10個(gè)字符建立索引,默認(rèn)是使用字段的全部內(nèi)容建立索引。
前提:前綴的標(biāo)識(shí)度高。比如密碼就適合建立前綴索引,因?yàn)槊艽a幾乎各不相同。
實(shí)操的難度:在于前綴截取的長度。
我們可以利用select count(*)/count(distinct left(password,prefixLen));,通過從調(diào)整prefixLen的值(從1自增)查看不同前綴長度的一個(gè)平均匹配度,接近1時(shí)就可以了(表示一個(gè)密碼的前prefixLen個(gè)字符幾乎能確定唯一一條記錄)
什么是最左前綴原則?什么是最左匹配原則
- 顧名思義,就是最左優(yōu)先,在創(chuàng)建多列索引時(shí),要根據(jù)業(yè)務(wù)需求,where子句中使用最頻繁的一列放在最左邊。
- 最左前綴匹配原則,非常重要的原則,mysql會(huì)一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整。
- =和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優(yōu)化器會(huì)幫你優(yōu)化成索引可以識(shí)別的形式
B樹和B+樹的區(qū)別
-  在B樹中,你可以將鍵和值存放在內(nèi)部節(jié)點(diǎn)和葉子節(jié)點(diǎn);但在B+樹中,內(nèi)部節(jié)點(diǎn)都是鍵,沒有值,葉子節(jié)點(diǎn)同時(shí)存放鍵和值。 
-  B+樹的葉子節(jié)點(diǎn)有一條鏈相連,而B樹的葉子節(jié)點(diǎn)各自獨(dú)立。 
使用B樹的好處
B樹可以在內(nèi)部節(jié)點(diǎn)同時(shí)存儲(chǔ)鍵和值,因此,把頻繁訪問的數(shù)據(jù)放在靠近根節(jié)點(diǎn)的地方將會(huì)大大提高熱點(diǎn)數(shù)據(jù)的查詢效率。這種特性使得B樹在特定數(shù)據(jù)重復(fù)多次查詢的場景中更加高效。
使用B+樹的好處
由于B+樹的內(nèi)部節(jié)點(diǎn)只存放鍵,不存放值,因此,一次讀取,可以在內(nèi)存頁中獲取更多的鍵,有利于更快地縮小查找范圍。 B+樹的葉節(jié)點(diǎn)由一條鏈相連,因此,當(dāng)需要進(jìn)行一次全數(shù)據(jù)遍歷的時(shí)候,B+樹只需要使用O(logN)時(shí)間找到最小的一個(gè)節(jié)點(diǎn),然后通過鏈進(jìn)行O(N)的順序遍歷即可。而B樹則需要對(duì)樹的每一層進(jìn)行遍歷,這會(huì)需要更多的內(nèi)存置換次數(shù),因此也就需要花費(fèi)更多的時(shí)間
Hash索引和B+樹所有有什么區(qū)別或者說優(yōu)劣呢?
首先要知道Hash索引和B+樹索引的底層實(shí)現(xiàn)原理:
hash索引底層就是hash表,進(jìn)行查找時(shí),調(diào)用一次hash函數(shù)就可以獲取到相應(yīng)的鍵值,之后進(jìn)行回表查詢獲得實(shí)際數(shù)據(jù)。B+樹底層實(shí)現(xiàn)是多路平衡查找樹。對(duì)于每一次的查詢都是從根節(jié)點(diǎn)出發(fā),查找到葉子節(jié)點(diǎn)方可以獲得所查鍵值,然后根據(jù)查詢判斷是否需要回表查詢數(shù)據(jù)。
那么可以看出他們有以下的不同:
- hash索引進(jìn)行等值查詢更快(一般情況下),但是卻無法進(jìn)行范圍查詢。
因?yàn)樵趆ash索引中經(jīng)過hash函數(shù)建立索引之后,索引的順序與原順序無法保持一致,不能支持范圍查詢。而B+樹的的所有節(jié)點(diǎn)皆遵循(左節(jié)點(diǎn)小于父節(jié)點(diǎn),右節(jié)點(diǎn)大于父節(jié)點(diǎn),多叉樹也類似),天然支持范圍。
- hash索引不支持使用索引進(jìn)行排序,原理同上。
- hash索引不支持模糊查詢以及多列索引的最左前綴匹配。原理也是因?yàn)閔ash函數(shù)的不可預(yù)測。AAAA和AAAAB的索引沒有相關(guān)性。
- hash索引任何時(shí)候都避免不了回表查詢數(shù)據(jù),而B+樹在符合某些條件(聚簇索引,覆蓋索引等)的時(shí)候可以只通過索引完成查詢。
- hash索引雖然在等值查詢上較快,但是不穩(wěn)定。性能不可預(yù)測,當(dāng)某個(gè)鍵值存在大量重復(fù)的時(shí)候,發(fā)生hash碰撞,此時(shí)效率可能極差。而B+樹的查詢效率比較穩(wěn)定,對(duì)于所有的查詢都是從根節(jié)點(diǎn)到葉子節(jié)點(diǎn),且樹的高度較低。
因此,在大多數(shù)情況下,直接選擇B+樹索引可以獲得穩(wěn)定且較好的查詢速度。而不需要使用hash索引。
數(shù)據(jù)庫為什么使用B+樹而不是B樹
- B樹只適合隨機(jī)檢索,而B+樹同時(shí)支持隨機(jī)檢索和順序檢索;
- B+樹空間利用率更高,可減少I/O次數(shù),磁盤讀寫代價(jià)更低。一般來說,索引本身也很大,不可能全部存儲(chǔ)在內(nèi)存中,因此索引往往以索引文件的形式存儲(chǔ)的磁盤上。這樣的話,索引查找過程中就要產(chǎn)生磁盤I/O消耗。B+樹的內(nèi)部結(jié)點(diǎn)并沒有指向關(guān)鍵字具體信息的指針,只是作為索引使用,其內(nèi)部結(jié)點(diǎn)比B樹小,盤塊能容納的結(jié)點(diǎn)中關(guān)鍵字?jǐn)?shù)量更多,一次性讀入內(nèi)存中可以查找的關(guān)鍵字也就越多,相對(duì)的,IO讀寫次數(shù)也就降低了。而IO讀寫次數(shù)是影響索引檢索效率的最大因素;
- B+樹的查詢效率更加穩(wěn)定。B樹搜索有可能會(huì)在非葉子結(jié)點(diǎn)結(jié)束,越靠近根節(jié)點(diǎn)的記錄查找時(shí)間越短,只要找到關(guān)鍵字即可確定記錄的存在,其性能等價(jià)于在關(guān)鍵字全集內(nèi)做一次二分查找。而在B+樹中,順序檢索比較明顯,隨機(jī)檢索時(shí),任何關(guān)鍵字的查找都必須走一條從根節(jié)點(diǎn)到葉節(jié)點(diǎn)的路,所有關(guān)鍵字的查找路徑長度相同,導(dǎo)致每一個(gè)關(guān)鍵字的查詢效率相當(dāng)。
- B-樹在提高了磁盤IO性能的同時(shí)并沒有解決元素遍歷的效率低下的問題。B+樹的葉子節(jié)點(diǎn)使用指針順序連接在一起,只要遍歷葉子節(jié)點(diǎn)就可以實(shí)現(xiàn)整棵樹的遍歷。而且在數(shù)據(jù)庫中基于范圍的查詢是非常頻繁的,而B樹不支持這樣的操作。
- 增刪文件(節(jié)點(diǎn))時(shí),效率更高。因?yàn)锽+樹的葉子節(jié)點(diǎn)包含所有關(guān)鍵字,并以有序的鏈表結(jié)構(gòu)存儲(chǔ),這樣可很好提高增刪效率。
B+樹在滿足聚簇索引和覆蓋索引的時(shí)候不需要回表查詢數(shù)據(jù),
在B+樹的索引中,葉子節(jié)點(diǎn)可能存儲(chǔ)了當(dāng)前的key值,也可能存儲(chǔ)了當(dāng)前的key值以及整行的數(shù)據(jù),這就是聚簇索引和非聚簇索引。 在InnoDB中,只有主鍵索引是聚簇索引,如果沒有主鍵,則挑選一個(gè)唯一鍵建立聚簇索引。如果沒有唯一鍵,則隱式的生成一個(gè)鍵來建立聚簇索引。
當(dāng)查詢使用聚簇索引時(shí),在對(duì)應(yīng)的葉子節(jié)點(diǎn),可以獲取到整行數(shù)據(jù),因此不用再次進(jìn)行回表查詢。
什么是聚簇索引?何時(shí)使用聚簇索引與非聚簇索引
- 聚簇索引:將數(shù)據(jù)存儲(chǔ)與索引放到了一塊,找到索引也就找到了數(shù)據(jù)
- 非聚簇索引:將數(shù)據(jù)存儲(chǔ)于索引分開結(jié)構(gòu),索引結(jié)構(gòu)的葉子節(jié)點(diǎn)指向了數(shù)據(jù)的對(duì)應(yīng)行,myisam通過key_buffer把索引先緩存到內(nèi)存中,當(dāng)需要訪問數(shù)據(jù)時(shí)(通過索引訪問數(shù)據(jù)),在內(nèi)存中直接搜索索引,然后通過索引找到磁盤相應(yīng)數(shù)據(jù),這也就是為什么索引不在key buffer命中時(shí),速度慢的原因
澄清一個(gè)概念:innodb中,在聚簇索引之上創(chuàng)建的索引稱之為輔助索引,輔助索引訪問數(shù)據(jù)總是需要二次查找,非聚簇索引都是輔助索引,像復(fù)合索引、前綴索引、唯一索引,輔助索引葉子節(jié)點(diǎn)存儲(chǔ)的不再是行的物理位置,而是主鍵值
何時(shí)使用聚簇索引與非聚簇索引
非聚簇索引一定會(huì)回表查詢嗎?
不一定,這涉及到查詢語句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再進(jìn)行回表查詢。
舉個(gè)簡單的例子,假設(shè)我們?cè)趩T工表的年齡上建立了索引,那么當(dāng)進(jìn)行select age from employee where age < 20的查詢時(shí),在索引的葉子節(jié)點(diǎn)上,已經(jīng)包含了age信息,不會(huì)再次進(jìn)行回表查詢。
聯(lián)合索引是什么?為什么需要注意聯(lián)合索引中的順序?
MySQL可以使用多個(gè)字段同時(shí)建立一個(gè)索引,叫做聯(lián)合索引。在聯(lián)合索引中,如果想要命中索引,需要按照建立索引時(shí)的字段順序挨個(gè)使用,否則無法命中索引。
具體原因?yàn)?
MySQL使用索引時(shí)需要索引有序,假設(shè)現(xiàn)在建立了"name,age,school"的聯(lián)合索引,那么索引的排序?yàn)? 先按照name排序,如果name相同,則按照age排序,如果age的值也相等,則按照school進(jìn)行排序。
當(dāng)進(jìn)行查詢時(shí),此時(shí)索引僅僅按照name嚴(yán)格有序,因此必須首先使用name字段進(jìn)行等值查詢,之后對(duì)于匹配到的列而言,其按照age字段嚴(yán)格有序,此時(shí)可以使用age字段用做索引查找,以此類推。因此在建立聯(lián)合索引的時(shí)候應(yīng)該注意索引列的順序,一般情況下,將查詢需求頻繁或者字段選擇性高的列放在前面。此外可以根據(jù)特例的查詢或者表結(jié)構(gòu)進(jìn)行單獨(dú)的調(diào)整。
事務(wù)
什么是數(shù)據(jù)庫事務(wù)?
事務(wù)是一個(gè)不可分割的數(shù)據(jù)庫操作序列,也是數(shù)據(jù)庫并發(fā)控制的基本單位,其執(zhí)行的結(jié)果必須使數(shù)據(jù)庫從一種一致性狀態(tài)變到另一種一致性狀態(tài)。事務(wù)是邏輯上的一組操作,要么都執(zhí)行,要么都不執(zhí)行。
事務(wù)最經(jīng)典也經(jīng)常被拿出來說例子就是轉(zhuǎn)賬了。
假如小明要給小紅轉(zhuǎn)賬1000元,這個(gè)轉(zhuǎn)賬會(huì)涉及到兩個(gè)關(guān)鍵操作就是:將小明的余額減少1000元,將小紅的余額增加1000元。萬一在這兩個(gè)操作之間突然出現(xiàn)錯(cuò)誤比如銀行系統(tǒng)崩潰,導(dǎo)致小明余額減少而小紅的余額沒有增加,這樣就不對(duì)了。事務(wù)就是保證這兩個(gè)關(guān)鍵操作要么都成功,要么都要失敗。
事物的四大特性(ACID)介紹一下?
關(guān)系性數(shù)據(jù)庫需要遵循ACID規(guī)則,具體內(nèi)容如下:
什么是臟讀?幻讀?不可重復(fù)讀?
- 臟讀(Drity Read):某個(gè)事務(wù)已更新一份數(shù)據(jù),另一個(gè)事務(wù)在此時(shí)讀取了同一份數(shù)據(jù),由于某些原因,前一個(gè)RollBack了操作,則后一個(gè)事務(wù)所讀取的數(shù)據(jù)就會(huì)是不正確的。
- 不可重復(fù)讀(Non-repeatable read):在一個(gè)事務(wù)的兩次查詢之中數(shù)據(jù)不一致,這可能是兩次查詢過程中間插入了一個(gè)事務(wù)更新的原有的數(shù)據(jù)。
- 幻讀(Phantom Read):在一個(gè)事務(wù)的兩次查詢中數(shù)據(jù)筆數(shù)不一致,例如有一個(gè)事務(wù)查詢了幾列(Row)數(shù)據(jù),而另一個(gè)事務(wù)卻在此時(shí)插入了新的幾列數(shù)據(jù),先前的事務(wù)在接下來的查詢中,就會(huì)發(fā)現(xiàn)有幾列數(shù)據(jù)是它先前所沒有的。
什么是事務(wù)的隔離級(jí)別?MySQL的默認(rèn)隔離級(jí)別是什么?
為了達(dá)到事務(wù)的四大特性,數(shù)據(jù)庫定義了4種不同的事務(wù)隔離級(jí)別,由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個(gè)級(jí)別可以逐個(gè)解決臟讀、不可重復(fù)讀、幻讀這幾類問題。
| READ-UNCOMMITTED | √ | √ | √ | 
| READ-COMMITTED | × | √ | √ | 
| REPEATABLE-READ | × | × | √ | 
| SERIALIZABLE | × | × | × | 
SQL 標(biāo)準(zhǔn)定義了四個(gè)隔離級(jí)別:
- READ-UNCOMMITTED(讀取未提交): 最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、幻讀或不可重復(fù)讀。
- READ-COMMITTED(讀取已提交): 允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生。
- REPEATABLE-READ(可重復(fù)讀): 對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生。
- SERIALIZABLE(可串行化): 最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別。所有的事務(wù)依次逐個(gè)執(zhí)行,這樣事務(wù)之間就完全不可能產(chǎn)生干擾,也就是說,該級(jí)別可以防止臟讀、不可重復(fù)讀以及幻讀。
這里需要注意的是:Mysql 默認(rèn)采用的 REPEATABLE_READ隔離級(jí)別 Oracle 默認(rèn)采用的 READ_COMMITTED隔離級(jí)別
事務(wù)隔離機(jī)制的實(shí)現(xiàn)基于鎖機(jī)制和并發(fā)調(diào)度。其中并發(fā)調(diào)度使用的是MVVC(多版本并發(fā)控制),通過保存修改的舊版本信息來支持并發(fā)一致性讀和回滾等特性。
因?yàn)楦綦x級(jí)別越低,事務(wù)請(qǐng)求的鎖越少,所以大部分?jǐn)?shù)據(jù)庫系統(tǒng)的隔離級(jí)別都是READ-COMMITTED(讀取提交內(nèi)容):,但是你要知道的是InnoDB 存儲(chǔ)引擎默認(rèn)使用 **REPEATABLE-READ(可重讀)**并不會(huì)有任何性能損失。
InnoDB 存儲(chǔ)引擎在 分布式事務(wù) 的情況下一般會(huì)用到**SERIALIZABLE(可串行化)**隔離級(jí)別。
鎖
對(duì)MySQL的鎖了解嗎
當(dāng)數(shù)據(jù)庫有并發(fā)事務(wù)的時(shí)候,可能會(huì)產(chǎn)生數(shù)據(jù)的不一致,這時(shí)候需要一些機(jī)制來保證訪問的次序,鎖機(jī)制就是這樣的一個(gè)機(jī)制。
就像酒店的房間,如果大家隨意進(jìn)出,就會(huì)出現(xiàn)多人搶奪同一個(gè)房間的情況,而在房間上裝上鎖,申請(qǐng)到鑰匙的人才可以入住并且將房間鎖起來,其他人只有等他使用完畢才可以再次使用。
隔離級(jí)別與鎖的關(guān)系
在Read Uncommitted級(jí)別下,讀取數(shù)據(jù)不需要加共享鎖,這樣就不會(huì)跟被修改的數(shù)據(jù)上的排他鎖沖突
在Read Committed級(jí)別下,讀操作需要加共享鎖,但是在語句執(zhí)行完以后釋放共享鎖;
在Repeatable Read級(jí)別下,讀操作需要加共享鎖,但是在事務(wù)提交之前并不釋放共享鎖,也就是必須等待事務(wù)執(zhí)行完畢以后才釋放共享鎖。
SERIALIZABLE 是限制性最強(qiáng)的隔離級(jí)別,因?yàn)樵摷?jí)別鎖定整個(gè)范圍的鍵,并一直持有鎖,直到事務(wù)完成。
按照鎖的粒度分?jǐn)?shù)據(jù)庫鎖有哪些?鎖機(jī)制與InnoDB鎖算法
在關(guān)系型數(shù)據(jù)庫中,可以按照鎖的粒度把數(shù)據(jù)庫鎖分為行級(jí)鎖(INNODB引擎)、表級(jí)鎖(MYISAM引擎)和頁級(jí)鎖(BDB引擎 )。
MyISAM和InnoDB存儲(chǔ)引擎使用的鎖:
- MyISAM采用表級(jí)鎖(table-level locking)。
- InnoDB支持行級(jí)鎖(row-level locking)和表級(jí)鎖,默認(rèn)為行級(jí)鎖
行級(jí)鎖,表級(jí)鎖和頁級(jí)鎖對(duì)比
行級(jí)鎖 行級(jí)鎖是Mysql中鎖定粒度最細(xì)的一種鎖,表示只針對(duì)當(dāng)前操作的行進(jìn)行加鎖。行級(jí)鎖能大大減少數(shù)據(jù)庫操作的沖突。其加鎖粒度最小,但加鎖的開銷也最大。行級(jí)鎖分為共享鎖 和 排他鎖。
特點(diǎn):開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
表級(jí)鎖 表級(jí)鎖是MySQL中鎖定粒度最大的一種鎖,表示對(duì)當(dāng)前操作的整張表加鎖,它實(shí)現(xiàn)簡單,資源消耗較少,被大部分MySQL引擎支持。最常使用的MYISAM與INNODB都支持表級(jí)鎖定。表級(jí)鎖定分為表共享讀鎖(共享鎖)與表獨(dú)占寫鎖(排他鎖)。
特點(diǎn):開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)出鎖沖突的概率最高,并發(fā)度最低。
頁級(jí)鎖 頁級(jí)鎖是MySQL中鎖定粒度介于行級(jí)鎖和表級(jí)鎖中間的一種鎖。表級(jí)鎖速度快,但沖突多,行級(jí)沖突少,但速度慢。所以取了折衷的頁級(jí),一次鎖定相鄰的一組記錄。
特點(diǎn):開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般
從鎖的類別上分MySQL都有哪些鎖呢?像上面那樣子進(jìn)行鎖定豈不是有點(diǎn)阻礙并發(fā)效率了
從鎖的類別上來講,有共享鎖和排他鎖。
共享鎖: 又叫做讀鎖。 當(dāng)用戶要進(jìn)行數(shù)據(jù)的讀取時(shí),對(duì)數(shù)據(jù)加上共享鎖。共享鎖可以同時(shí)加上多個(gè)。
排他鎖: 又叫做寫鎖。 當(dāng)用戶要進(jìn)行數(shù)據(jù)的寫入時(shí),對(duì)數(shù)據(jù)加上排他鎖。排他鎖只可以加一個(gè),他和其他的排他鎖,共享鎖都相斥。
用上面的例子來說就是用戶的行為有兩種,一種是來看房,多個(gè)用戶一起看房是可以接受的。 一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以。
鎖的粒度取決于具體的存儲(chǔ)引擎,InnoDB實(shí)現(xiàn)了行級(jí)鎖,頁級(jí)鎖,表級(jí)鎖。
他們的加鎖開銷從大到小,并發(fā)能力也是從大到小。
MySQL中InnoDB引擎的行鎖是怎么實(shí)現(xiàn)的?
答:InnoDB是基于索引來完成行鎖
例: select * from tab_with_index where id = 1 for update;
for update 可以根據(jù)條件來完成行鎖鎖定,并且 id 是有索引鍵的列,如果 id 不是索引鍵那么InnoDB將完成表鎖,并發(fā)將無從談起
InnoDB存儲(chǔ)引擎的鎖的算法有三種
- Record lock:單個(gè)行記錄上的鎖
- Gap lock:間隙鎖,鎖定一個(gè)范圍,不包括記錄本身
- Next-key lock:record+gap 鎖定一個(gè)范圍,包含記錄本身
相關(guān)知識(shí)點(diǎn):
什么是死鎖?怎么解決?
死鎖是指兩個(gè)或多個(gè)事務(wù)在同一資源上相互占用,并請(qǐng)求鎖定對(duì)方的資源,從而導(dǎo)致惡性循環(huán)的現(xiàn)象。
常見的解決死鎖的方法
1、如果不同程序會(huì)并發(fā)存取多個(gè)表,盡量約定以相同的順序訪問表,可以大大降低死鎖機(jī)會(huì)。
2、在同一個(gè)事務(wù)中,盡可能做到一次鎖定所需要的所有資源,減少死鎖產(chǎn)生概率;
3、對(duì)于非常容易產(chǎn)生死鎖的業(yè)務(wù)部分,可以嘗試使用升級(jí)鎖定顆粒度,通過表級(jí)鎖定來減少死鎖產(chǎn)生的概率;
如果業(yè)務(wù)處理不好可以用分布式事務(wù)鎖或者使用樂觀鎖
數(shù)據(jù)庫的樂觀鎖和悲觀鎖是什么?怎么實(shí)現(xiàn)的?
數(shù)據(jù)庫管理系統(tǒng)(DBMS)中的并發(fā)控制的任務(wù)是確保在多個(gè)事務(wù)同時(shí)存取數(shù)據(jù)庫中同一數(shù)據(jù)時(shí)不破壞事務(wù)的隔離性和統(tǒng)一性以及數(shù)據(jù)庫的統(tǒng)一性。樂觀并發(fā)控制(樂觀鎖)和悲觀并發(fā)控制(悲觀鎖)是并發(fā)控制主要采用的技術(shù)手段。
悲觀鎖:假定會(huì)發(fā)生并發(fā)沖突,屏蔽一切可能違反數(shù)據(jù)完整性的操作。在查詢完數(shù)據(jù)的時(shí)候就把事務(wù)鎖起來,直到提交事務(wù)。實(shí)現(xiàn)方式:使用數(shù)據(jù)庫中的鎖機(jī)制
樂觀鎖:假設(shè)不會(huì)發(fā)生并發(fā)沖突,只在提交操作時(shí)檢查是否違反數(shù)據(jù)完整性。在修改數(shù)據(jù)的時(shí)候把事務(wù)鎖起來,通過version的方式來進(jìn)行鎖定。實(shí)現(xiàn)方式:樂一般會(huì)使用版本號(hào)機(jī)制或CAS算法實(shí)現(xiàn)。
兩種鎖的使用場景
從上面對(duì)兩種鎖的介紹,我們知道兩種鎖各有優(yōu)缺點(diǎn),不可認(rèn)為一種好于另一種,像樂觀鎖適用于寫比較少的情況下(多讀場景),即沖突真的很少發(fā)生的時(shí)候,這樣可以省去了鎖的開銷,加大了系統(tǒng)的整個(gè)吞吐量。
但如果是多寫的情況,一般會(huì)經(jīng)常產(chǎn)生沖突,這就會(huì)導(dǎo)致上層應(yīng)用會(huì)不斷的進(jìn)行retry,這樣反倒是降低了性能,所以一般多寫的場景下用悲觀鎖就比較合適。
視圖
為什么要使用視圖?什么是視圖?
為了提高復(fù)雜SQL語句的復(fù)用性和表操作的安全性,MySQL數(shù)據(jù)庫管理系統(tǒng)提供了視圖特性。所謂視圖,本質(zhì)上是一種虛擬表,在物理上是不存在的,其內(nèi)容與真實(shí)的表相似,包含一系列帶有名稱的列和行數(shù)據(jù)。但是,視圖并不在數(shù)據(jù)庫中以儲(chǔ)存的數(shù)據(jù)值形式存在。行和列數(shù)據(jù)來自定義視圖的查詢所引用基本表,并且在具體引用視圖時(shí)動(dòng)態(tài)生成。
視圖使開發(fā)者只關(guān)心感興趣的某些特定數(shù)據(jù)和所負(fù)責(zé)的特定任務(wù),只能看到視圖中所定義的數(shù)據(jù),而不是視圖所引用表中的數(shù)據(jù),從而提高了數(shù)據(jù)庫中數(shù)據(jù)的安全性。
視圖有哪些特點(diǎn)?
視圖的特點(diǎn)如下:
-  視圖的列可以來自不同的表,是表的抽象和在邏輯意義上建立的新關(guān)系。 
-  視圖是由基本表(實(shí)表)產(chǎn)生的表(虛表)。 
-  視圖的建立和刪除不影響基本表。 
-  對(duì)視圖內(nèi)容的更新(添加,刪除和修改)直接影響基本表。 
-  當(dāng)視圖來自多個(gè)基本表時(shí),不允許添加和刪除數(shù)據(jù)。 
視圖的操作包括創(chuàng)建視圖,查看視圖,刪除視圖和修改視圖。
視圖的使用場景有哪些?
視圖根本用途:簡化sql查詢,提高開發(fā)效率。如果說還有另外一個(gè)用途那就是兼容老的表結(jié)構(gòu)。
下面是視圖的常見使用場景:
-  重用SQL語句; 
-  簡化復(fù)雜的SQL操作。在編寫查詢后,可以方便的重用它而不必知道它的基本查詢細(xì)節(jié); 
-  使用表的組成部分而不是整個(gè)表; 
-  保護(hù)數(shù)據(jù)。可以給用戶授予表的特定部分的訪問權(quán)限而不是整個(gè)表的訪問權(quán)限; 
-  更改數(shù)據(jù)格式和表示。視圖可返回與底層表的表示和格式不同的數(shù)據(jù)。 
視圖的優(yōu)點(diǎn)
視圖的缺點(diǎn)
性能。數(shù)據(jù)庫必須把視圖的查詢轉(zhuǎn)化成對(duì)基本表的查詢,如果這個(gè)視圖是由一個(gè)復(fù)雜的多表查詢所定義,那么,即使是視圖的一個(gè)簡單查詢,數(shù)據(jù)庫也把它變成一個(gè)復(fù)雜的結(jié)合體,需要花費(fèi)一定的時(shí)間。
修改限制。當(dāng)用戶試圖修改視圖的某些行時(shí),數(shù)據(jù)庫必須把它轉(zhuǎn)化為對(duì)基本表的某些行的修改。事實(shí)上,當(dāng)從視圖中插入或者刪除時(shí),情況也是這樣。對(duì)于簡單視圖來說,這是很方便的,但是,對(duì)于比較復(fù)雜的視圖,可能是不可修改的
這些視圖有如下特征:1.有UNIQUE等集合操作符的視圖。2.有GROUP BY子句的視圖。3.有諸如AVG\SUM\MAX等聚合函數(shù)的視圖。 4.使用DISTINCT關(guān)鍵字的視圖。5.連接表的視圖(其中有些例外)
什么是游標(biāo)?
游標(biāo)是系統(tǒng)為用戶開設(shè)的一個(gè)數(shù)據(jù)緩沖區(qū),存放SQL語句的執(zhí)行結(jié)果,每個(gè)游標(biāo)區(qū)都有一個(gè)名字。用戶可以通過游標(biāo)逐一獲取記錄并賦給主變量,交由主語言進(jìn)一步處理。
存儲(chǔ)過程與函數(shù)
什么是存儲(chǔ)過程?有哪些優(yōu)缺點(diǎn)?
存儲(chǔ)過程是一個(gè)預(yù)編譯的SQL語句,優(yōu)點(diǎn)是允許模塊化的設(shè)計(jì),就是說只需要?jiǎng)?chuàng)建一次,以后在該程序中就可以調(diào)用多次。如果某次操作需要執(zhí)行多次SQL,使用存儲(chǔ)過程比單純SQL語句執(zhí)行要快。
優(yōu)點(diǎn)
1)存儲(chǔ)過程是預(yù)編譯過的,執(zhí)行效率高。
2)存儲(chǔ)過程的代碼直接存放于數(shù)據(jù)庫中,通過存儲(chǔ)過程名直接調(diào)用,減少網(wǎng)絡(luò)通訊。
3)安全性高,執(zhí)行存儲(chǔ)過程需要有一定權(quán)限的用戶。
4)存儲(chǔ)過程可以重復(fù)使用,減少數(shù)據(jù)庫開發(fā)人員的工作量。
缺點(diǎn)
1)調(diào)試麻煩,但是用 PL/SQL Developer 調(diào)試很方便!彌補(bǔ)這個(gè)缺點(diǎn)。
2)移植問題,數(shù)據(jù)庫端代碼當(dāng)然是與數(shù)據(jù)庫相關(guān)的。但是如果是做工程型項(xiàng)目,基本不存在移植問題。
3)重新編譯問題,因?yàn)楹蠖舜a是運(yùn)行前編譯的,如果帶有引用關(guān)系的對(duì)象發(fā)生改變時(shí),受影響的存儲(chǔ)過程、包將需要重新編譯(不過也可以設(shè)置成運(yùn)行時(shí)刻自動(dòng)編譯)。
4)如果在一個(gè)程序系統(tǒng)中大量的使用存儲(chǔ)過程,到程序交付使用的時(shí)候隨著用戶需求的增加會(huì)導(dǎo)致數(shù)據(jù)結(jié)構(gòu)的變化,接著就是系統(tǒng)的相關(guān)問題了,最后如果用戶想維護(hù)該系統(tǒng)可以說是很難很難、而且代價(jià)是空前的,維護(hù)起來更麻煩。
觸發(fā)器
什么是觸發(fā)器?觸發(fā)器的使用場景有哪些?
觸發(fā)器是用戶定義在關(guān)系表上的一類由事件驅(qū)動(dòng)的特殊的存儲(chǔ)過程。觸發(fā)器是指一段代碼,當(dāng)觸發(fā)某個(gè)事件時(shí),自動(dòng)執(zhí)行這些代碼。
使用場景
- 可以通過數(shù)據(jù)庫中的相關(guān)表實(shí)現(xiàn)級(jí)聯(lián)更改。
- 實(shí)時(shí)監(jiān)控某張表中的某個(gè)字段的更改而需要做出相應(yīng)的處理。
- 例如可以生成某些業(yè)務(wù)的編號(hào)。
- 注意不要濫用,否則會(huì)造成數(shù)據(jù)庫及應(yīng)用程序的維護(hù)困難。
- 大家需要牢記以上基礎(chǔ)知識(shí)點(diǎn),重點(diǎn)是理解數(shù)據(jù)類型CHAR和VARCHAR的差異,表存儲(chǔ)引擎InnoDB和MyISAM的區(qū)別。
MySQL中都有哪些觸發(fā)器?
在MySQL數(shù)據(jù)庫中有如下六種觸發(fā)器:
- Before Insert
- After Insert
- Before Update
- After Update
- Before Delete
- After Delete
常用SQL語句
SQL語句主要分為哪幾類
數(shù)據(jù)定義語言DDL(Data Ddefinition Language)CREATE,DROP,ALTER
主要為以上操作 即對(duì)邏輯結(jié)構(gòu)等有操作的,其中包括表結(jié)構(gòu),視圖和索引。
數(shù)據(jù)查詢語言DQL(Data Query Language)SELECT
這個(gè)較為好理解 即查詢操作,以select關(guān)鍵字。各種簡單查詢,連接查詢等 都屬于DQL。
數(shù)據(jù)操縱語言DML(Data Manipulation Language)INSERT,UPDATE,DELETE
主要為以上操作 即對(duì)數(shù)據(jù)進(jìn)行操作的,對(duì)應(yīng)上面所說的查詢操作 DQL與DML共同構(gòu)建了多數(shù)初級(jí)程序員常用的增刪改查操作。而查詢是較為特殊的一種 被劃分到DQL中。
數(shù)據(jù)控制功能DCL(Data Control Language)GRANT,REVOKE,COMMIT,ROLLBACK
主要為以上操作 即對(duì)數(shù)據(jù)庫安全性完整性等有操作的,可以簡單的理解為權(quán)限控制等。
超鍵、候選鍵、主鍵、外鍵分別是什么?
- 超鍵:在關(guān)系中能唯一標(biāo)識(shí)元組的屬性集稱為關(guān)系模式的超鍵。一個(gè)屬性可以為作為一個(gè)超鍵,多個(gè)屬性組合在一起也可以作為一個(gè)超鍵。超鍵包含候選鍵和主鍵。
- 候選鍵:是最小超鍵,即沒有冗余元素的超鍵。
- 主鍵:數(shù)據(jù)庫表中對(duì)儲(chǔ)存數(shù)據(jù)對(duì)象予以唯一和完整標(biāo)識(shí)的數(shù)據(jù)列或?qū)傩缘慕M合。一個(gè)數(shù)據(jù)列只能有一個(gè)主鍵,且主鍵的取值不能缺失,即不能為空值(Null)。
- 外鍵:在一個(gè)表中存在的另一個(gè)表的主鍵稱此表的外鍵。
SQL 約束有哪幾種?
SQL 約束有哪幾種?
- NOT NULL: 用于控制字段的內(nèi)容一定不能為空(NULL)。
- UNIQUE: 控件字段內(nèi)容不能重復(fù),一個(gè)表允許有多個(gè) Unique 約束。
- PRIMARY KEY: 也是用于控件字段內(nèi)容不能重復(fù),但它在一個(gè)表只允許出現(xiàn)一個(gè)。
- FOREIGN KEY: 用于預(yù)防破壞表之間連接的動(dòng)作,也能防止非法數(shù)據(jù)插入外鍵列,因?yàn)樗仨毷撬赶虻哪莻€(gè)表中的值之一。
- CHECK: 用于控制字段的值范圍。
六種關(guān)聯(lián)查詢
- 交叉連接(CROSS JOIN)
- 內(nèi)連接(INNER JOIN)
- 外連接(LEFT JOIN/RIGHT JOIN)
- 聯(lián)合查詢(UNION與UNION ALL)
- 全連接(FULL JOIN)
- 交叉連接(CROSS JOIN)
內(nèi)連接分為三類
- 等值連接:ON A.id=B.id
- 不等值連接:ON A.id > B.id
- 自連接:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid
外連接(LEFT JOIN/RIGHT JOIN)
- 左外連接:LEFT OUTER JOIN, 以左表為主,先查詢出左表,按照ON后的關(guān)聯(lián)條件匹配右表,沒有匹配到的用NULL填充,可以簡寫成LEFT JOIN
- 右外連接:RIGHT OUTER JOIN, 以右表為主,先查詢出右表,按照ON后的關(guān)聯(lián)條件匹配左表,沒有匹配到的用NULL填充,可以簡寫成RIGHT JOIN
聯(lián)合查詢(UNION與UNION ALL)
SELECT * FROM A UNION SELECT * FROM B UNION ...- 就是把多個(gè)結(jié)果集集中在一起,UNION前的結(jié)果為基準(zhǔn),需要注意的是聯(lián)合查詢的列數(shù)要相等,相同的記錄行會(huì)合并
- 如果使用UNION ALL,不會(huì)合并重復(fù)的記錄行
- 效率 UNION 高于 UNION ALL
全連接(FULL JOIN)
- MySQL不支持全連接
- 可以使用LEFT JOIN 和UNION和RIGHT JOIN聯(lián)合使用
表連接面試題
有2張表,1張R、1張S,R表有ABC三列,S表有CD兩列,表中各有三條記錄。
R表
| a1 | b1 | c1 | 
| a2 | b2 | c2 | 
| a3 | b3 | c3 | 
S表
| c1 | d1 | 
| c2 | d2 | 
| c4 | d3 | 
select r.*,s.* from r,s
| a1 | b1 | c1 | c1 | d1 | 
| a2 | b2 | c2 | c1 | d1 | 
| a3 | b3 | c3 | c1 | d1 | 
| a1 | b1 | c1 | c2 | d2 | 
| a2 | b2 | c2 | c2 | d2 | 
| a3 | b3 | c3 | c2 | d2 | 
| a1 | b1 | c1 | c4 | d3 | 
| a2 | b2 | c2 | c4 | d3 | 
| a3 | b3 | c3 | c4 | d3 | 
內(nèi)連接結(jié)果:
select r.*,s.* from r inner join s on r.c=s.c
| a1 | b1 | c1 | c1 | d1 | 
| a2 | b2 | c2 | c2 | d2 | 
左連接結(jié)果:
select r.*,s.* from r left join s on r.c=s.c
| a1 | b1 | c1 | c1 | d1 | 
| a2 | b2 | c2 | c2 | d2 | 
| a3 | b3 | c3 | 
右連接結(jié)果:
select r.*,s.* from r right join s on r.c=s.c
| A | B | C | C | D | 
| a1 | b1 | c1 | c1 | d1 | 
| a2 | b2 | c2 | c2 | d2 | 
| c4 | d3 | 
全表連接的結(jié)果(MySql不支持,Oracle支持):
select r.*,s.* from r full join s on r.c=s.c
| a1 | b1 | c1 | c1 | d1 | 
| a2 | b2 | c2 | c2 | d2 | 
| a3 | b3 | c3 | ||
| c4 | d3 | 
什么是子查詢
條件:一條SQL語句的查詢結(jié)果做為另一條查詢語句的條件或查詢結(jié)果
嵌套:多條SQL語句嵌套使用,內(nèi)部的SQL查詢語句稱為子查詢。
子查詢的三種情況
mysql中 in 和 exists 區(qū)別
mysql中的in語句是把外表和內(nèi)表作hash 連接,而exists語句是對(duì)外表作loop循環(huán),每次loop循環(huán)再對(duì)內(nèi)表進(jìn)行查詢。一直大家都認(rèn)為exists比in語句的效率要高,這種說法其實(shí)是不準(zhǔn)確的。這個(gè)是要區(qū)分環(huán)境的。
varchar與char的區(qū)別
char的特點(diǎn)
-  char表示定長字符串,長度是固定的; 
-  如果插入數(shù)據(jù)的長度小于char的固定長度時(shí),則用空格填充; 
-  因?yàn)殚L度固定,所以存取速度要比varchar快很多,甚至能快50%,但正因?yàn)槠溟L度固定,所以會(huì)占據(jù)多余的空間,是空間換時(shí)間的做法; 
-  對(duì)于char來說,最多能存放的字符個(gè)數(shù)為255,和編碼無關(guān) 
varchar的特點(diǎn)
-  varchar表示可變長字符串,長度是可變的; 
-  插入的數(shù)據(jù)是多長,就按照多長來存儲(chǔ); 
-  varchar在存取方面與char相反,它存取慢,因?yàn)殚L度不固定,但正因如此,不占據(jù)多余的空間,是時(shí)間換空間的做法; 
-  對(duì)于varchar來說,最多能存放的字符個(gè)數(shù)為65532 
總之,結(jié)合性能角度(char更快)和節(jié)省磁盤空間角度(varchar更小),具體情況還需具體來設(shè)計(jì)數(shù)據(jù)庫才是妥當(dāng)?shù)淖龇ā?/p>
varchar(50)中50的涵義
最多存放50個(gè)字符,varchar(50)和(200)存儲(chǔ)hello所占空間一樣,但后者在排序時(shí)會(huì)消耗更多內(nèi)存,因?yàn)閛rder by col采用fixed_length計(jì)算col長度(memory引擎也一樣)。在早期 MySQL 版本中, 50 代表字節(jié)數(shù),現(xiàn)在代表字符數(shù)。
int(20)中20的涵義
是指顯示字符的長度。20表示最大顯示寬度為20,但仍占4字節(jié)存儲(chǔ),存儲(chǔ)范圍不變;
不影響內(nèi)部存儲(chǔ),只是影響帶 zerofill 定義的 int 時(shí),前面補(bǔ)多少個(gè) 0,易于報(bào)表展示
mysql為什么這么設(shè)計(jì)
對(duì)大多數(shù)應(yīng)用沒有意義,只是規(guī)定一些工具用來顯示字符的個(gè)數(shù);int(1)和int(20)存儲(chǔ)和計(jì)算均一樣;
mysql中int(10)和char(10)以及varchar(10)的區(qū)別
-  int(10)的10表示顯示的數(shù)據(jù)的長度,不是存儲(chǔ)數(shù)據(jù)的大小;chart(10)和varchar(10)的10表示存儲(chǔ)數(shù)據(jù)的大小,即表示存儲(chǔ)多少個(gè)字符。 int(10) 10位的數(shù)據(jù)長度 9999999999,占32個(gè)字節(jié),int型4位 
 char(10) 10位固定字符串,不足補(bǔ)空格 最多10個(gè)字符
 varchar(10) 10位可變字符串,不足補(bǔ)空格 最多10個(gè)字符
-  char(10)表示存儲(chǔ)定長的10個(gè)字符,不足10個(gè)就用空格補(bǔ)齊,占用更多的存儲(chǔ)空間 
-  varchar(10)表示存儲(chǔ)10個(gè)變長的字符,存儲(chǔ)多少個(gè)就是多少個(gè),空格也按一個(gè)字符存儲(chǔ),這一點(diǎn)是和char(10)的空格不同的,char(10)的空格表示占位不算一個(gè)字符 
FLOAT和DOUBLE的區(qū)別是什么?
- FLOAT類型數(shù)據(jù)可以存儲(chǔ)至多8位十進(jìn)制數(shù),并在內(nèi)存中占4字節(jié)。
- DOUBLE類型數(shù)據(jù)可以存儲(chǔ)至多18位十進(jìn)制數(shù),并在內(nèi)存中占8字節(jié)。
drop、delete與truncate的區(qū)別
三者都表示刪除,但是三者有一些差別:
| 類型 | 屬于DML | 屬于DDL | 屬于DDL | 
| 回滾 | 可回滾 | 不可回滾 | 不可回滾 | 
| 刪除內(nèi)容 | 表結(jié)構(gòu)還在,刪除表的全部或者一部分?jǐn)?shù)據(jù)行 | 表結(jié)構(gòu)還在,刪除表中的所有數(shù)據(jù) | 從數(shù)據(jù)庫中刪除表,所有的數(shù)據(jù)行,索引和權(quán)限也會(huì)被刪除 | 
| 刪除速度 | 刪除速度慢,需要逐行刪除 | 刪除速度快 | 刪除速度最快 | 
因此,在不再需要一張表的時(shí)候,用drop;在想刪除部分?jǐn)?shù)據(jù)行時(shí)候,用delete;在保留表而刪除所有數(shù)據(jù)的時(shí)候用truncate。
UNION與UNION ALL的區(qū)別?
- 如果使用UNION ALL,不會(huì)合并重復(fù)的記錄行
- 效率 UNION 高于 UNION ALL
SQL優(yōu)化
如何定位及優(yōu)化SQL語句的性能問題?創(chuàng)建的索引有沒有被使用到?或者說怎么才可以知道這條語句運(yùn)行很慢的原因?
對(duì)于低性能的SQL語句的定位,最重要也是最有效的方法就是使用執(zhí)行計(jì)劃,MySQL提供了explain命令來查看語句的執(zhí)行計(jì)劃。 我們知道,不管是哪種數(shù)據(jù)庫,或者是哪種數(shù)據(jù)庫引擎,在對(duì)一條SQL語句進(jìn)行執(zhí)行的過程中都會(huì)做很多相關(guān)的優(yōu)化,對(duì)于查詢語句,最重要的優(yōu)化方式就是使用索引。 而執(zhí)行計(jì)劃,就是顯示數(shù)據(jù)庫引擎對(duì)于SQL語句的執(zhí)行的詳細(xì)情況,其中包含了是否使用索引,使用什么索引,使用的索引的相關(guān)信息等。
執(zhí)行計(jì)劃包含的信息 id 有一組數(shù)字組成。表示一個(gè)查詢中各個(gè)子查詢的執(zhí)行順序;
- id相同執(zhí)行順序由上至下。
- id不同,id值越大優(yōu)先級(jí)越高,越先被執(zhí)行。
- id為null時(shí)表示一個(gè)結(jié)果集,不需要使用它查詢,常出現(xiàn)在包含union等查詢語句中。
select_type 每個(gè)子查詢的查詢類型,一些常見的查詢類型。
| 1 | SIMPLE | 不包含任何子查詢或union等查詢 | 
| 2 | PRIMARY | 包含子查詢最外層查詢就顯示為 PRIMARY | 
| 3 | SUBQUERY | 在select或 where字句中包含的查詢 | 
| 4 | DERIVED | from字句中包含的查詢 | 
| 5 | UNION | 出現(xiàn)在union后的查詢語句中 | 
| 6 | UNION RESULT | 從UNION中獲取結(jié)果集,例如上文的第三個(gè)例子 | 
table 查詢的數(shù)據(jù)表,當(dāng)從衍生表中查數(shù)據(jù)時(shí)會(huì)顯示 x 表示對(duì)應(yīng)的執(zhí)行計(jì)劃id partitions 表分區(qū)、表創(chuàng)建的時(shí)候可以指定通過那個(gè)列進(jìn)行表分區(qū)。 舉個(gè)例子:
create table tmp (id int unsigned not null AUTO_INCREMENT,name varchar(255),PRIMARY KEY (id) ) engine = innodb partition by key (id) partitions 5;type(非常重要,可以看到有沒有走索引) 訪問類型
- ALL 掃描全表數(shù)據(jù)
- index 遍歷索引
- range 索引范圍查找
- index_subquery 在子查詢中使用 ref
- unique_subquery 在子查詢中使用 eq_ref
- ref_or_null 對(duì)Null進(jìn)行索引的優(yōu)化的 ref
- fulltext 使用全文索引
- ref 使用非唯一索引查找數(shù)據(jù)
- eq_ref 在join查詢中使用PRIMARY KEYorUNIQUE NOT NULL索引關(guān)聯(lián)。
possible_keys 可能使用的索引,注意不一定會(huì)使用。查詢涉及到的字段上若存在索引,則該索引將被列出來。當(dāng)該列為 NULL時(shí)就要考慮當(dāng)前的SQL是否需要優(yōu)化了。
key 顯示MySQL在查詢中實(shí)際使用的索引,若沒有使用索引,顯示為NULL。
TIPS:查詢中若使用了覆蓋索引(覆蓋索引:索引的數(shù)據(jù)覆蓋了需要查詢的所有數(shù)據(jù)),則該索引僅出現(xiàn)在key列表中
key_length 索引長度
ref 表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值
rows 返回估算的結(jié)果集數(shù)目,并不是一個(gè)準(zhǔn)確的值。
extra 的信息非常豐富,常見的有:
SQL的生命周期?
應(yīng)用服務(wù)器與數(shù)據(jù)庫服務(wù)器建立一個(gè)連接
數(shù)據(jù)庫進(jìn)程拿到請(qǐng)求sql
解析并生成執(zhí)行計(jì)劃,執(zhí)行
讀取數(shù)據(jù)到內(nèi)存并進(jìn)行邏輯處理
通過步驟一的連接,發(fā)送結(jié)果到客戶端
關(guān)掉連接,釋放資源
大表數(shù)據(jù)查詢,怎么優(yōu)化
超大分頁怎么處理?
超大的分頁一般從兩個(gè)方向上來解決.
- 數(shù)據(jù)庫層面,這也是我們主要集中關(guān)注的(雖然收效沒那么大),類似于select * from table where age > 20 limit 1000000,10這種查詢其實(shí)也是有可以優(yōu)化的余地的. 這條語句需要load1000000數(shù)據(jù)然后基本上全部丟棄,只取10條當(dāng)然比較慢. 當(dāng)時(shí)我們可以修改為select * from table where id in (select id from table where age > 20 limit 1000000,10).這樣雖然也load了一百萬的數(shù)據(jù),但是由于索引覆蓋,要查詢的所有字段都在索引中,所以速度會(huì)很快. 同時(shí)如果ID連續(xù)的好,我們還可以select * from table where id > 1000000 limit 10,效率也是不錯(cuò)的,優(yōu)化的可能性有許多種,但是核心思想都一樣,就是減少load的數(shù)據(jù).
- 從需求的角度減少這種請(qǐng)求…主要是不做類似的需求(直接跳轉(zhuǎn)到幾百萬頁之后的具體某一頁.只允許逐頁查看或者按照給定的路線走,這樣可預(yù)測,可緩存)以及防止ID泄漏且連續(xù)被人惡意攻擊.
解決超大分頁,其實(shí)主要是靠緩存,可預(yù)測性的提前查到內(nèi)容,緩存至redis等k-V數(shù)據(jù)庫中,直接返回即可.
在阿里巴巴《Java開發(fā)手冊(cè)》中,對(duì)超大分頁的解決辦法是類似于上面提到的第一種.
【推薦】利用延遲關(guān)聯(lián)或者子查詢優(yōu)化超多分頁場景。 說明:MySQL并不是跳過offset行,而是取offset+N行,然后返回放棄前offset行,返回N行,那當(dāng)offset特別大的時(shí)候,效率就非常的低下,要么控制返回的總頁數(shù),要么對(duì)超過特定閾值的頁數(shù)進(jìn)行SQL改寫。 正例:先快速定位需要獲取的id段,然后再關(guān)聯(lián): SELECT a.* FROM 表1 a, (select id from 表1 where 條件 LIMIT 100000,20 ) b where a.id=b.idmysql 分頁
LIMIT 子句可以被用于強(qiáng)制 SELECT 語句返回指定的記錄數(shù)。LIMIT 接受一個(gè)或兩個(gè)數(shù)字參數(shù)。參數(shù)必須是一個(gè)整數(shù)常量。如果給定兩個(gè)參數(shù),第一個(gè)參數(shù)指定第一個(gè)返回記錄行的偏移量,第二個(gè)參數(shù)指定返回記錄行的最大數(shù)目。初始記錄行的偏移量是 0(而不是 1)
mysql> SELECT * FROM table LIMIT 5,10; // 檢索記錄行 6-15為了檢索從某一個(gè)偏移量到記錄集的結(jié)束所有的記錄行,可以指定第二個(gè)參數(shù)為 -1:
mysql> SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.如果只給定一個(gè)參數(shù),它表示返回最大的記錄行數(shù)目:
mysql> SELECT * FROM table LIMIT 5; //檢索前 5 個(gè)記錄行換句話說,LIMIT n 等價(jià)于 LIMIT 0,n。
慢查詢?nèi)罩?/h3>
用于記錄執(zhí)行時(shí)間超過某個(gè)臨界值的SQL日志,用于快速定位慢查詢,為我們的優(yōu)化做參考。
開啟慢查詢?nèi)罩?/p>
配置項(xiàng):slow_query_log
可以使用show variables like ‘slov_query_log’查看是否開啟,如果狀態(tài)值為OFF,可以使用set GLOBAL slow_query_log = on來開啟,它會(huì)在datadir下產(chǎn)生一個(gè)xxx-slow.log的文件。
設(shè)置臨界時(shí)間
配置項(xiàng):long_query_time
查看:show VARIABLES like 'long_query_time',單位秒
設(shè)置:set long_query_time=0.5
實(shí)操時(shí)應(yīng)該從長時(shí)間設(shè)置到短的時(shí)間,即將最慢的SQL優(yōu)化掉
查看日志,一旦SQL超過了我們?cè)O(shè)置的臨界時(shí)間就會(huì)被記錄到xxx-slow.log中
關(guān)心過業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎?統(tǒng)計(jì)過慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過?
在業(yè)務(wù)系統(tǒng)中,除了使用主鍵進(jìn)行的查詢,其他的我都會(huì)在測試庫上測試其耗時(shí),慢查詢的統(tǒng)計(jì)主要由運(yùn)維在做,會(huì)定期將業(yè)務(wù)中的慢查詢反饋給我們。
慢查詢的優(yōu)化首先要搞明白慢的原因是什么? 是查詢條件沒有命中索引?是load了不需要的數(shù)據(jù)列?還是數(shù)據(jù)量太大?
所以優(yōu)化也是針對(duì)這三個(gè)方向來的,
- 首先分析語句,看看是否load了額外的數(shù)據(jù),可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結(jié)果中并不需要的列,對(duì)語句進(jìn)行分析以及重寫。
- 分析語句的執(zhí)行計(jì)劃,然后獲得其使用索引的情況,之后修改語句或者修改索引,使得語句可以盡可能的命中索引。
- 如果對(duì)語句的優(yōu)化已經(jīng)無法進(jìn)行,可以考慮表中的數(shù)據(jù)量是否太大,如果是的話可以進(jìn)行橫向或者縱向的分表。
為什么要盡量設(shè)定一個(gè)主鍵?
主鍵是數(shù)據(jù)庫確保數(shù)據(jù)行在整張表唯一性的保障,即使業(yè)務(wù)上本張表沒有主鍵,也建議添加一個(gè)自增長的ID列作為主鍵。設(shè)定了主鍵之后,在后續(xù)的刪改查的時(shí)候可能更加快速以及確保操作數(shù)據(jù)范圍安全。
主鍵使用自增ID還是UUID?
推薦使用自增ID,不要使用UUID。
因?yàn)樵贗nnoDB存儲(chǔ)引擎中,主鍵索引是作為聚簇索引存在的,也就是說,主鍵索引的B+樹葉子節(jié)點(diǎn)上存儲(chǔ)了主鍵索引以及全部的數(shù)據(jù)(按照順序),如果主鍵索引是自增ID,那么只需要不斷向后排列即可,如果是UUID,由于到來的ID與原來的大小不確定,會(huì)造成非常多的數(shù)據(jù)插入,數(shù)據(jù)移動(dòng),然后導(dǎo)致產(chǎn)生很多的內(nèi)存碎片,進(jìn)而造成插入性能的下降。
總之,在數(shù)據(jù)量大一些的情況下,用自增主鍵性能會(huì)好一些。
關(guān)于主鍵是聚簇索引,如果沒有主鍵,InnoDB會(huì)選擇一個(gè)唯一鍵來作為聚簇索引,如果沒有唯一鍵,會(huì)生成一個(gè)隱式的主鍵。
字段為什么要求定義為not null?
null值會(huì)占用更多的字節(jié),且會(huì)在程序中造成很多與預(yù)期不符的情況。
如果要存儲(chǔ)用戶的密碼散列,應(yīng)該使用什么字段進(jìn)行存儲(chǔ)?
密碼散列,鹽,用戶身份證號(hào)等固定長度的字符串應(yīng)該使用char而不是varchar來存儲(chǔ),這樣可以節(jié)省空間且提高檢索效率。
優(yōu)化查詢過程中的數(shù)據(jù)訪問
- 訪問數(shù)據(jù)太多導(dǎo)致查詢性能下降
- 確定應(yīng)用程序是否在檢索大量超過需要的數(shù)據(jù),可能是太多行或列
- 確認(rèn)MySQL服務(wù)器是否在分析大量不必要的數(shù)據(jù)行
- 避免犯如下SQL語句錯(cuò)誤
- 查詢不需要的數(shù)據(jù)。解決辦法:使用limit解決
- 多表關(guān)聯(lián)返回全部列。解決辦法:指定列名
- 總是返回全部列。解決辦法:避免使用SELECT *
- 重復(fù)查詢相同的數(shù)據(jù)。解決辦法:可以緩存數(shù)據(jù),下次直接讀取緩存
- 是否在掃描額外的記錄。解決辦法:
- 使用explain進(jìn)行分析,如果發(fā)現(xiàn)查詢需要掃描大量的數(shù)據(jù),但只返回少數(shù)的行,可以通過如下技巧去優(yōu)化:
- 使用索引覆蓋掃描,把所有的列都放到索引中,這樣存儲(chǔ)引擎不需要回表獲取對(duì)應(yīng)行就可以返回結(jié)果。
- 改變數(shù)據(jù)庫和表的結(jié)構(gòu),修改數(shù)據(jù)表范式
- 重寫SQL語句,讓優(yōu)化器可以以更優(yōu)的方式執(zhí)行查詢。
優(yōu)化長難的查詢語句
- 一個(gè)復(fù)雜查詢還是多個(gè)簡單查詢
- MySQL內(nèi)部每秒能掃描內(nèi)存中上百萬行數(shù)據(jù),相比之下,響應(yīng)數(shù)據(jù)給客戶端就要慢得多
- 使用盡可能小的查詢是好的,但是有時(shí)將一個(gè)大的查詢分解為多個(gè)小的查詢是很有必要的。
- 切分查詢
- 將一個(gè)大的查詢分為多個(gè)小的相同的查詢
- 一次性刪除1000萬的數(shù)據(jù)要比一次刪除1萬,暫停一會(huì)的方案更加損耗服務(wù)器開銷。
- 分解關(guān)聯(lián)查詢,讓緩存的效率更高。
- 執(zhí)行單個(gè)查詢可以減少鎖的競爭。
- 在應(yīng)用層做關(guān)聯(lián)更容易對(duì)數(shù)據(jù)庫進(jìn)行拆分。
- 查詢效率會(huì)有大幅提升。
- 較少冗余記錄的查詢。
優(yōu)化特定類型的查詢語句
- count(*)會(huì)忽略所有的列,直接統(tǒng)計(jì)所有列數(shù),不要使用count(列名)
- MyISAM中,沒有任何where條件的count(*)非常快。
- 當(dāng)有where條件時(shí),MyISAM的count統(tǒng)計(jì)不一定比其它引擎快。
- 可以使用explain查詢近似值,用近似值替代count(*)
- 增加匯總表
- 使用緩存
優(yōu)化關(guān)聯(lián)查詢
- 確定ON或者USING子句中是否有索引。
- 確保GROUP BY和ORDER BY只有一個(gè)表中的列,這樣MySQL才有可能使用索引。
優(yōu)化子查詢
- 用關(guān)聯(lián)查詢替代
- 優(yōu)化GROUP BY和DISTINCT
- 這兩種查詢據(jù)可以使用索引來優(yōu)化,是最有效的優(yōu)化方法
- 關(guān)聯(lián)查詢中,使用標(biāo)識(shí)列分組的效率更高
- 如果不需要ORDER BY,進(jìn)行GROUP BY時(shí)加ORDER BY NULL,MySQL不會(huì)再進(jìn)行文件排序。
- WITH ROLLUP超級(jí)聚合,可以挪到應(yīng)用程序處理
優(yōu)化LIMIT分頁
- LIMIT偏移量大的時(shí)候,查詢效率較低
- 可以記錄上次查詢的最大ID,下次查詢時(shí)直接根據(jù)該ID來查詢
優(yōu)化UNION查詢
- UNION ALL的效率高于UNION
優(yōu)化WHERE子句
解題方法
對(duì)于此類考題,先說明如何定位低效SQL語句,然后根據(jù)SQL語句可能低效的原因做排查,先從索引著手,如果索引沒有問題,考慮以上幾個(gè)方面,數(shù)據(jù)訪問的問題,長難查詢句的問題還是一些特定類型優(yōu)化的問題,逐一回答。
SQL語句優(yōu)化的一些方法?
- 1.對(duì)查詢進(jìn)行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。
- 2.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
- 3.應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則引擎將放棄使用索引而進(jìn)行全表掃描。
- 4.應(yīng)盡量避免在 where 子句中使用or 來連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
- 5.in 和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描,如:
- 6.下面的查詢也將導(dǎo)致全表掃描:select id from t where name like ‘%李%’若要提高效率,可以考慮全文檢索。
- 7.如果在 where 子句中使用參數(shù),也會(huì)導(dǎo)致全表掃描。因?yàn)镾QL只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問計(jì)劃的選擇推遲到運(yùn)行時(shí);它必須在編譯時(shí)進(jìn)行選擇。然 而,如果在編譯時(shí)建立訪問計(jì)劃,變量的值還是未知的,因而無法作為索引選擇的輸入項(xiàng)。如下面語句將進(jìn)行全表掃描:
- 8.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
- 9.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
- 10.不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無法正確使用索引。
數(shù)據(jù)庫優(yōu)化
為什么要優(yōu)化
- 系統(tǒng)的吞吐量瓶頸往往出現(xiàn)在數(shù)據(jù)庫的訪問速度上
- 隨著應(yīng)用程序的運(yùn)行,數(shù)據(jù)庫的中的數(shù)據(jù)會(huì)越來越多,處理時(shí)間會(huì)相應(yīng)變慢
- 數(shù)據(jù)是存放在磁盤上的,讀寫速度無法和內(nèi)存相比
優(yōu)化原則:減少系統(tǒng)瓶頸,減少資源占用,增加系統(tǒng)的反應(yīng)速度。
數(shù)據(jù)庫結(jié)構(gòu)優(yōu)化
一個(gè)好的數(shù)據(jù)庫設(shè)計(jì)方案對(duì)于數(shù)據(jù)庫的性能往往會(huì)起到事半功倍的效果。
需要考慮數(shù)據(jù)冗余、查詢和更新的速度、字段的數(shù)據(jù)類型是否合理等多方面的內(nèi)容。
將字段很多的表分解成多個(gè)表
對(duì)于字段較多的表,如果有些字段的使用頻率很低,可以將這些字段分離出來形成新表。
因?yàn)楫?dāng)一個(gè)表的數(shù)據(jù)量很大時(shí),會(huì)由于使用頻率低的字段的存在而變慢。
增加中間表
對(duì)于需要經(jīng)常聯(lián)合查詢的表,可以建立中間表以提高查詢效率。
通過建立中間表,將需要通過聯(lián)合查詢的數(shù)據(jù)插入到中間表中,然后將原來的聯(lián)合查詢改為對(duì)中間表的查詢。
增加冗余字段
設(shè)計(jì)數(shù)據(jù)表時(shí)應(yīng)盡量遵循范式理論的規(guī)約,盡可能的減少冗余字段,讓數(shù)據(jù)庫設(shè)計(jì)看起來精致、優(yōu)雅。但是,合理的加入冗余字段可以提高查詢速度。
表的規(guī)范化程度越高,表和表之間的關(guān)系越多,需要連接查詢的情況也就越多,性能也就越差。
注意:
冗余字段的值在一個(gè)表中修改了,就要想辦法在其他表中更新,否則就會(huì)導(dǎo)致數(shù)據(jù)不一致的問題。
MySQL數(shù)據(jù)庫cpu飆升到500%的話他怎么處理?
當(dāng) cpu 飆升到 500%時(shí),先用操作系統(tǒng)命令 top 命令觀察是不是 mysqld 占用導(dǎo)致的,如果不是,找出占用高的進(jìn)程,并進(jìn)行相關(guān)處理。
如果是 mysqld 造成的, show processlist,看看里面跑的 session 情況,是不是有消耗資源的 sql 在運(yùn)行。找出消耗高的 sql,看看執(zhí)行計(jì)劃是否準(zhǔn)確, index 是否缺失,或者實(shí)在是數(shù)據(jù)量太大造成。
一般來說,肯定要 kill 掉這些線程(同時(shí)觀察 cpu 使用率是否下降),等進(jìn)行相應(yīng)的調(diào)整(比如說加索引、改 sql、改內(nèi)存參數(shù))之后,再重新跑這些 SQL。
也有可能是每個(gè) sql 消耗資源并不多,但是突然之間,有大量的 session 連進(jìn)來導(dǎo)致 cpu 飆升,這種情況就需要跟應(yīng)用一起來分析為何連接數(shù)會(huì)激增,再做出相應(yīng)的調(diào)整,比如說限制連接數(shù)等
大表怎么優(yōu)化?某個(gè)表有近千萬數(shù)據(jù),CRUD比較慢,如何優(yōu)化?分庫分表了是怎么做的?分表分庫了有什么問題?有用到中間件么?他們的原理知道么?
當(dāng)MySQL單表記錄數(shù)過大時(shí),數(shù)據(jù)庫的CRUD性能會(huì)明顯下降,一些常見的優(yōu)化措施如下:
還有就是通過分庫分表的方式進(jìn)行優(yōu)化,主要有垂直分表和水平分表
垂直分區(qū):
根據(jù)數(shù)據(jù)庫里面數(shù)據(jù)表的相關(guān)性進(jìn)行拆分。 例如,用戶表中既有用戶的登錄信息又有用戶的基本信息,可以將用戶表拆分成兩個(gè)單獨(dú)的表,甚至放到單獨(dú)的庫做分庫。
簡單來說垂直拆分是指數(shù)據(jù)表列的拆分,把一張列比較多的表拆分為多張表。 如下圖所示,這樣來說大家應(yīng)該就更容易理解了。
垂直拆分的優(yōu)點(diǎn): 可以使得行數(shù)據(jù)變小,在查詢時(shí)減少讀取的Block數(shù),減少I/O次數(shù)。此外,垂直分區(qū)可以簡化表的結(jié)構(gòu),易于維護(hù)。
垂直拆分的缺點(diǎn): 主鍵會(huì)出現(xiàn)冗余,需要管理冗余列,并會(huì)引起Join操作,可以通過在應(yīng)用層進(jìn)行Join來解決。此外,垂直分區(qū)會(huì)讓事務(wù)變得更加復(fù)雜;
垂直分表
把主鍵和一些列放在一個(gè)表,然后把主鍵和另外的列放在另一個(gè)表中
適用場景
- 1、如果一個(gè)表中某些列常用,另外一些列不常用
- 2、可以使數(shù)據(jù)行變小,一個(gè)數(shù)據(jù)頁能存儲(chǔ)更多數(shù)據(jù),查詢時(shí)減少I/O次數(shù)
缺點(diǎn)
- 有些分表的策略基于應(yīng)用層的邏輯算法,一旦邏輯算法改變,整個(gè)分表邏輯都會(huì)改變,擴(kuò)展性較差
- 對(duì)于應(yīng)用層來說,邏輯算法增加開發(fā)成本
- 管理冗余列,查詢所有數(shù)據(jù)需要join操作
水平分區(qū):
保持?jǐn)?shù)據(jù)表結(jié)構(gòu)不變,通過某種策略存儲(chǔ)數(shù)據(jù)分片。這樣每一片數(shù)據(jù)分散到不同的表或者庫中,達(dá)到了分布式的目的。 水平拆分可以支撐非常大的數(shù)據(jù)量。
水平拆分是指數(shù)據(jù)表行的拆分,表的行數(shù)超過200萬行時(shí),就會(huì)變慢,這時(shí)可以把一張的表的數(shù)據(jù)拆成多張表來存放。舉個(gè)例子:我們可以將用戶信息表拆分成多個(gè)用戶信息表,這樣就可以避免單一表數(shù)據(jù)量過大對(duì)性能造成影響。
水品拆分可以支持非常大的數(shù)據(jù)量。需要注意的一點(diǎn)是:分表僅僅是解決了單一表數(shù)據(jù)過大的問題,但由于表的數(shù)據(jù)還是在同一臺(tái)機(jī)器上,其實(shí)對(duì)于提升MySQL并發(fā)能力沒有什么意義,所以 水平拆分最好分庫 。
水平拆分能夠 支持非常大的數(shù)據(jù)量存儲(chǔ),應(yīng)用端改造也少,但 分片事務(wù)難以解決 ,跨界點(diǎn)Join性能較差,邏輯復(fù)雜。
《Java工程師修煉之道》的作者推薦 盡量不要對(duì)數(shù)據(jù)進(jìn)行分片,因?yàn)椴鸱謺?huì)帶來邏輯、部署、運(yùn)維的各種復(fù)雜度 ,一般的數(shù)據(jù)表在優(yōu)化得當(dāng)?shù)那闆r下支撐千萬以下的數(shù)據(jù)量是沒有太大問題的。如果實(shí)在要分片,盡量選擇客戶端分片架構(gòu),這樣可以減少一次和中間件的網(wǎng)絡(luò)I/O。
水平分表:
表很大,分割后可以降低在查詢時(shí)需要讀的數(shù)據(jù)和索引的頁數(shù),同時(shí)也降低了索引的層數(shù),提高查詢次數(shù)
適用場景
- 1、表中的數(shù)據(jù)本身就有獨(dú)立性,例如表中分表記錄各個(gè)地區(qū)的數(shù)據(jù)或者不同時(shí)期的數(shù)據(jù),特別是有些數(shù)據(jù)常用,有些不常用。
- 2、需要把數(shù)據(jù)存放在多個(gè)介質(zhì)上。
水平切分的缺點(diǎn)
- 1、給應(yīng)用增加復(fù)雜度,通常查詢時(shí)需要多個(gè)表名,查詢所有數(shù)據(jù)都需UNION操作
- 2、在許多數(shù)據(jù)庫應(yīng)用中,這種復(fù)雜度會(huì)超過它帶來的優(yōu)點(diǎn),查詢時(shí)會(huì)增加讀一個(gè)索引層的磁盤次數(shù)
下面補(bǔ)充一下數(shù)據(jù)庫分片的兩種常見方案:
- 客戶端代理: 分片邏輯在應(yīng)用端,封裝在jar包中,通過修改或者封裝JDBC層來實(shí)現(xiàn)。 當(dāng)當(dāng)網(wǎng)的 Sharding-JDBC 、阿里的TDDL是兩種比較常用的實(shí)現(xiàn)。
- 中間件代理: 在應(yīng)用和數(shù)據(jù)中間加了一個(gè)代理層。分片邏輯統(tǒng)一維護(hù)在中間件服務(wù)中。 我們現(xiàn)在談的 Mycat 、360的Atlas、網(wǎng)易的DDB等等都是這種架構(gòu)的實(shí)現(xiàn)。
分庫分表后面臨的問題
-  事務(wù)支持 分庫分表后,就成了分布式事務(wù)了。如果依賴數(shù)據(jù)庫本身的分布式事務(wù)管理功能去執(zhí)行事務(wù),將付出高昂的性能代價(jià); 如果由應(yīng)用程序去協(xié)助控制,形成程序邏輯上的事務(wù),又會(huì)造成編程方面的負(fù)擔(dān)。 
-  跨庫join 只要是進(jìn)行切分,跨節(jié)點(diǎn)Join的問題是不可避免的。但是良好的設(shè)計(jì)和切分卻可以減少此類情況的發(fā)生。解決這一問題的普遍做法是分兩次查詢實(shí)現(xiàn)。在第一次查詢的結(jié)果集中找出關(guān)聯(lián)數(shù)據(jù)的id,根據(jù)這些id發(fā)起第二次請(qǐng)求得到關(guān)聯(lián)數(shù)據(jù)。 分庫分表方案產(chǎn)品 
-  跨節(jié)點(diǎn)的count,order by,group by以及聚合函數(shù)問題 這些是一類問題,因?yàn)樗鼈兌夹枰谌繑?shù)據(jù)集合進(jìn)行計(jì)算。多數(shù)的代理都不會(huì)自動(dòng)處理合并工作。解決方案:與解決跨節(jié)點(diǎn)join問題的類似,分別在各個(gè)節(jié)點(diǎn)上得到結(jié)果后在應(yīng)用程序端進(jìn)行合并。和join不同的是每個(gè)結(jié)點(diǎn)的查詢可以并行執(zhí)行,因此很多時(shí)候它的速度要比單一大表快很多。但如果結(jié)果集很大,對(duì)應(yīng)用程序內(nèi)存的消耗是一個(gè)問題。 
-  數(shù)據(jù)遷移,容量規(guī)劃,擴(kuò)容等問題 來自淘寶綜合業(yè)務(wù)平臺(tái)團(tuán)隊(duì),它利用對(duì)2的倍數(shù)取余具有向前兼容的特性(如對(duì)4取余得1的數(shù)對(duì)2取余也是1)來分配數(shù)據(jù),避免了行級(jí)別的數(shù)據(jù)遷移,但是依然需要進(jìn)行表級(jí)別的遷移,同時(shí)對(duì)擴(kuò)容規(guī)模和分表數(shù)量都有限制。總得來說,這些方案都不是十分的理想,多多少少都存在一些缺點(diǎn),這也從一個(gè)側(cè)面反映出了Sharding擴(kuò)容的難度。 
-  ID問題 
-  一旦數(shù)據(jù)庫被切分到多個(gè)物理結(jié)點(diǎn)上,我們將不能再依賴數(shù)據(jù)庫自身的主鍵生成機(jī)制。一方面,某個(gè)分區(qū)數(shù)據(jù)庫自生成的ID無法保證在全局上是唯一的;另一方面,應(yīng)用程序在插入數(shù)據(jù)之前需要先獲得ID,以便進(jìn)行SQL路由. 一些常見的主鍵生成策略 
UUID 使用UUID作主鍵是最簡單的方案,但是缺點(diǎn)也是非常明顯的。由于UUID非常的長,除占用大量存儲(chǔ)空間外,最主要的問題是在索引上,在建立索引和基于索引進(jìn)行查詢時(shí)都存在性能問題。 Twitter的分布式自增ID算法Snowflake 在分布式系統(tǒng)中,需要生成全局UID的場合還是比較多的,twitter的snowflake解決了這種需求,實(shí)現(xiàn)也還是很簡單的,除去配置信息,核心代碼就是毫秒級(jí)時(shí)間41位 機(jī)器ID 10位 毫秒內(nèi)序列12位。
-  跨分片的排序分頁 般來講,分頁時(shí)需要按照指定字段進(jìn)行排序。當(dāng)排序字段就是分片字段的時(shí)候,我們通過分片規(guī)則可以比較容易定位到指定的分片,而當(dāng)排序字段非分片字段的時(shí)候,情況就會(huì)變得比較復(fù)雜了。為了最終結(jié)果的準(zhǔn)確性,我們需要在不同的分片節(jié)點(diǎn)中將數(shù)據(jù)進(jìn)行排序并返回,并將不同分片返回的結(jié)果集進(jìn)行匯總和再次排序,最后再返回給用戶。如下圖所示: 
MySQL的復(fù)制原理以及流程
主從復(fù)制:將主數(shù)據(jù)庫中的DDL和DML操作通過二進(jìn)制日志(BINLOG)傳輸?shù)綇臄?shù)據(jù)庫上,然后將這些日志重新執(zhí)行(重做);從而使得從數(shù)據(jù)庫的數(shù)據(jù)與主數(shù)據(jù)庫保持一致。
主從復(fù)制的作用
MySQL主從復(fù)制解決的問題
- 數(shù)據(jù)分布:隨意開始或停止復(fù)制,并在不同地理位置分布數(shù)據(jù)備份
- 負(fù)載均衡:降低單個(gè)服務(wù)器的壓力
- 高可用和故障切換:幫助應(yīng)用程序避免單點(diǎn)失敗
- 升級(jí)測試:可以用更高版本的MySQL作為從庫
MySQL主從復(fù)制工作原理
- 在主庫上把數(shù)據(jù)更高記錄到二進(jìn)制日志
- 從庫將主庫的日志復(fù)制到自己的中繼日志
- 從庫讀取中繼日志的事件,將其重放到從庫數(shù)據(jù)中
基本原理流程,3個(gè)線程以及之間的關(guān)聯(lián)
主:binlog線程——記錄下所有改變了數(shù)據(jù)庫數(shù)據(jù)的語句,放進(jìn)master上的binlog中;
從:io線程——在使用start slave 之后,負(fù)責(zé)從master上拉取 binlog 內(nèi)容,放進(jìn)自己的relay log中;
從:sql執(zhí)行線程——執(zhí)行relay log中的語句;
復(fù)制過程
Binary log:主數(shù)據(jù)庫的二進(jìn)制日志
Relay log:從服務(wù)器的中繼日志
第一步:master在每個(gè)事務(wù)更新數(shù)據(jù)完成之前,將該操作記錄串行地寫入到binlog文件中。
第二步:salve開啟一個(gè)I/O Thread,該線程在master打開一個(gè)普通連接,主要工作是binlog dump process。如果讀取的進(jìn)度已經(jīng)跟上了master,就進(jìn)入睡眠狀態(tài)并等待master產(chǎn)生新的事件。I/O線程最終的目的是將這些事件寫入到中繼日志中。
第三步:SQL Thread會(huì)讀取中繼日志,并順序執(zhí)行該日志中的SQL事件,從而與主數(shù)據(jù)庫中的數(shù)據(jù)保持一致。
讀寫分離有哪些解決方案?
讀寫分離是依賴于主從復(fù)制,而主從復(fù)制又是為讀寫分離服務(wù)的。因?yàn)橹鲝膹?fù)制要求slave不能寫只能讀(如果對(duì)slave執(zhí)行寫操作,那么show slave status將會(huì)呈現(xiàn)Slave_SQL_Running=NO,此時(shí)你需要按照前面提到的手動(dòng)同步一下slave)。
方案一
使用mysql-proxy代理
優(yōu)點(diǎn):直接實(shí)現(xiàn)讀寫分離和負(fù)載均衡,不用修改代碼,master和slave用一樣的帳號(hào),mysql官方不建議實(shí)際生產(chǎn)中使用
缺點(diǎn):降低性能, 不支持事務(wù)
方案二
使用AbstractRoutingDataSource+aop+annotation在dao層決定數(shù)據(jù)源。
 如果采用了mybatis, 可以將讀寫分離放在ORM層,比如mybatis可以通過mybatis plugin攔截sql語句,所有的insert/update/delete都訪問master庫,所有的select 都訪問salve庫,這樣對(duì)于dao層都是透明。 plugin實(shí)現(xiàn)時(shí)可以通過注解或者分析語句是讀寫方法來選定主從庫。不過這樣依然有一個(gè)問題, 也就是不支持事務(wù), 所以我們還需要重寫一下DataSourceTransactionManager, 將read-only的事務(wù)扔進(jìn)讀庫, 其余的有讀有寫的扔進(jìn)寫庫。
方案三
使用AbstractRoutingDataSource+aop+annotation在service層決定數(shù)據(jù)源,可以支持事務(wù).
缺點(diǎn):類內(nèi)部方法通過this.xx()方式相互調(diào)用時(shí),aop不會(huì)進(jìn)行攔截,需進(jìn)行特殊處理。
備份計(jì)劃,mysqldump以及xtranbackup的實(shí)現(xiàn)原理
(1)備份計(jì)劃
視庫的大小來定,一般來說 100G 內(nèi)的庫,可以考慮使用 mysqldump 來做,因?yàn)?mysqldump更加輕巧靈活,備份時(shí)間選在業(yè)務(wù)低峰期,可以每天進(jìn)行都進(jìn)行全量備份(mysqldump 備份出來的文件比較小,壓縮之后更小)。
100G 以上的庫,可以考慮用 xtranbackup 來做,備份速度明顯要比 mysqldump 要快。一般是選擇一周一個(gè)全備,其余每天進(jìn)行增量備份,備份時(shí)間為業(yè)務(wù)低峰期。
(2)備份恢復(fù)時(shí)間
物理備份恢復(fù)快,邏輯備份恢復(fù)慢
這里跟機(jī)器,尤其是硬盤的速率有關(guān)系,以下列舉幾個(gè)僅供參考
20G的2分鐘(mysqldump)
80G的30分鐘(mysqldump)
111G的30分鐘(mysqldump)
288G的3小時(shí)(xtra)
3T的4小時(shí)(xtra)
邏輯導(dǎo)入時(shí)間一般是備份時(shí)間的5倍以上
(3)備份恢復(fù)失敗如何處理
首先在恢復(fù)之前就應(yīng)該做足準(zhǔn)備工作,避免恢復(fù)的時(shí)候出錯(cuò)。比如說備份之后的有效性檢查、權(quán)限檢查、空間檢查等。如果萬一報(bào)錯(cuò),再根據(jù)報(bào)錯(cuò)的提示來進(jìn)行相應(yīng)的調(diào)整。
(4)mysqldump和xtrabackup實(shí)現(xiàn)原理
mysqldump
mysqldump 屬于邏輯備份。加入–single-transaction 選項(xiàng)可以進(jìn)行一致性備份。后臺(tái)進(jìn)程會(huì)先設(shè)置 session 的事務(wù)隔離級(jí)別為 RR(SET SESSION TRANSACTION ISOLATION LEVELREPEATABLE READ),之后顯式開啟一個(gè)事務(wù)(START TRANSACTION /*!40100 WITH CONSISTENTSNAPSHOT */),這樣就保證了該事務(wù)里讀到的數(shù)據(jù)都是事務(wù)事務(wù)時(shí)候的快照。之后再把表的數(shù)據(jù)讀取出來。如果加上–master-data=1 的話,在剛開始的時(shí)候還會(huì)加一個(gè)數(shù)據(jù)庫的讀鎖(FLUSH TABLES WITH READ LOCK),等開啟事務(wù)后,再記錄下數(shù)據(jù)庫此時(shí) binlog 的位置(showmaster status),馬上解鎖,再讀取表的數(shù)據(jù)。等所有的數(shù)據(jù)都已經(jīng)導(dǎo)完,就可以結(jié)束事務(wù)
Xtrabackup:
xtrabackup 屬于物理備份,直接拷貝表空間文件,同時(shí)不斷掃描產(chǎn)生的 redo 日志并保存下來。最后完成 innodb 的備份后,會(huì)做一個(gè) flush engine logs 的操作(老版本在有 bug,在5.6 上不做此操作會(huì)丟數(shù)據(jù)),確保所有的 redo log 都已經(jīng)落盤(涉及到事務(wù)的兩階段提交
概念,因?yàn)?xtrabackup 并不拷貝 binlog,所以必須保證所有的 redo log 都落盤,否則可能會(huì)丟最后一組提交事務(wù)的數(shù)據(jù))。這個(gè)時(shí)間點(diǎn)就是 innodb 完成備份的時(shí)間點(diǎn),數(shù)據(jù)文件雖然不是一致性的,但是有這段時(shí)間的 redo 就可以讓數(shù)據(jù)文件達(dá)到一致性(恢復(fù)的時(shí)候做的事
情)。然后還需要 flush tables with read lock,把 myisam 等其他引擎的表給備份出來,備份完后解鎖。這樣就做到了完美的熱備。
數(shù)據(jù)表損壞的修復(fù)方式有哪些?
使用 myisamchk 來修復(fù),具體步驟:
- 1)修復(fù)前將mysql服務(wù)停止。
- 2)打開命令行方式,然后進(jìn)入到mysql的/bin目錄。
- 3)執(zhí)行myisamchk –recover 數(shù)據(jù)庫所在路徑/*.MYI
使用repair table 或者 OPTIMIZE table命令來修復(fù),REPAIR TABLE table_name 修復(fù)表 OPTIMIZE TABLE table_name 優(yōu)化表 REPAIR TABLE 用于修復(fù)被破壞的表。 OPTIMIZE TABLE 用于回收閑置的數(shù)據(jù)庫空間,當(dāng)表上的數(shù)據(jù)行被刪除時(shí),所占據(jù)的磁盤空間并沒有立即被回收,使用了OPTIMIZE TABLE命令后這些空間將被回收,并且對(duì)磁盤上的數(shù)據(jù)行進(jìn)行重排(注意:是磁盤上,而非數(shù)據(jù)庫)
總結(jié)
以上是生活随笔為你收集整理的MySQL数据库面试题(2020最新版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        