python面试题库——3数据库和缓存
-  第三部分 數(shù)據(jù)庫和緩存(46題)
-  列舉常見的關(guān)系型數(shù)據(jù)庫和非關(guān)系型都有那些?
?
關(guān)系型數(shù)據(jù)庫:
?
Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL
?
非關(guān)系型數(shù)據(jù)庫:
?
NoSql、Cloudant、MongoDb、redis、HBase
?
兩種數(shù)據(jù)庫之間的區(qū)別:
?
關(guān)系型數(shù)據(jù)庫
?
  關(guān)系型數(shù)據(jù)庫的特性
?
1、關(guān)系型數(shù)據(jù)庫,是指采用了關(guān)系模型來組織數(shù)據(jù)的數(shù)據(jù)庫;
?
2、關(guān)系型數(shù)據(jù)庫的最大特點就是事務(wù)的一致性;
?
3、簡單來說,關(guān)系模型指的就是二維表格模型,而一個關(guān)系型數(shù)據(jù)庫就是由二維表及其之間的聯(lián)系所組成的一個數(shù)據(jù)組織。
?
關(guān)系型數(shù)據(jù)庫的優(yōu)點
?
  1、容易理解:二維表結(jié)構(gòu)是非常貼近邏輯世界一個概念,關(guān)系模型相對網(wǎng)狀、層次等其他模型來說更容易理解;
  2、使用方便:通用的SQL語言使得操作關(guān)系型數(shù)據(jù)庫非常方便;
  3、易于維護:豐富的完整性(實體完整性、參照完整性和用戶定義的完整性)大大減低了數(shù)據(jù)冗余和數(shù)據(jù)不一致的概率;
  4、支持SQL,可用于復(fù)雜的查詢。
?
關(guān)系型數(shù)據(jù)庫的缺點
?
  1、為了維護一致性所付出的巨大代價就是其讀寫性能比較差;
  2、固定的表結(jié)構(gòu);
  3、高并發(fā)讀寫需求;
  4、海量數(shù)據(jù)的高效率讀寫;
?
非關(guān)系型數(shù)據(jù)庫
?
  非關(guān)系型數(shù)據(jù)庫的特性
?
  1、使用鍵值對存儲數(shù)據(jù);
  2、分布式;
  3、一般不支持ACID特性;
  4、非關(guān)系型數(shù)據(jù)庫嚴(yán)格上不是一種數(shù)據(jù)庫,應(yīng)該是一種數(shù)據(jù)結(jié)構(gòu)化存儲方法的集合。
?
  非關(guān)系型數(shù)據(jù)庫的優(yōu)點
?
  1、無需經(jīng)過sql層的解析,讀寫性能很高;
  2、基于鍵值對,數(shù)據(jù)沒有耦合性,容易擴展;
  3、存儲數(shù)據(jù)的格式:nosql的存儲格式是key,value形式、文檔形式、圖片形式等等,文檔形式、圖片形式等等,而關(guān)系型數(shù)據(jù)庫則只支持基礎(chǔ)類型。
?
非關(guān)系型數(shù)據(jù)庫的缺點
?
  ?1、不提供sql支持,學(xué)習(xí)和使用成本較高;
  ?2、無事務(wù)處理,附加功能bi和報表等支持也不好;
?
-  MySQL常見數(shù)據(jù)庫引擎及比較?
?
MySQL存儲引擎簡介
?
MySQL支持?jǐn)?shù)個存儲引擎作為對不同表的類型的處理器。MySQL存儲引擎包括處理事務(wù)安全表的引擎和處理非事務(wù)安全表的引擎:
?
?
?
MyISAM管理非事務(wù)表。它提供高速存儲和檢索,以及全文搜索能力。MyISAM在所有MySQL配置里被支持,它是默認(rèn)的存儲引擎,除非你配置MySQL默認(rèn)使用另外一個引擎。
?
?
?
MEMORY存儲引擎提供“內(nèi)存中”表。MERGE存儲引擎允許集合將被處理同樣的MyISAM表作為一個單獨的表。就像MyISAM一樣,MEMORY和MERGE存儲引擎處理非事務(wù)表,這兩個引擎也都被默認(rèn)包含在MySQL中。
?
?
?
注:MEMORY存儲引擎正式地被確定為HEAP引擎。
?
?
?
InnoDB和BDB存儲引擎提供事務(wù)安全表。BDB被包含在為支持它的操作系統(tǒng)發(fā)布的MySQL-Max二進制分發(fā)版里。InnoDB也默認(rèn)被包括在所 有MySQL 5.1二進制分發(fā)版里,你可以按照喜好通過配置MySQL來允許或禁止任一引擎。
EXAMPLE存儲引擎是一個“存根”引擎,它不做什么。你可以用這個引擎創(chuàng)建表,但沒有數(shù)據(jù)被存儲于其中或從其中檢索。這個引擎的目的是服務(wù),在 MySQL源代碼中的一個例子,它演示說明如何開始編寫新存儲引擎。同樣,它的主要興趣是對開發(fā)者。
?
?
?
NDB Cluster是被MySQL Cluster用來實現(xiàn)分割到多臺計算機上的表的存儲引擎。它在MySQL-Max 5.1二進制分發(fā)版里提供。這個存儲引擎當(dāng)前只被Linux,?Solaris, 和Mac OS X?支持。在未來的MySQL分發(fā)版中,我們想要添加其它平臺對這個引擎的支持,包括Windows。
?
?
?
ARCHIVE存儲引擎被用來無索引地,非常小地覆蓋存儲的大量數(shù)據(jù)。
?
CSV存儲引擎把數(shù)據(jù)以逗號分隔的格式存儲在文本文件中。
?
?
?
BLACKHOLE存儲引擎接受但不存儲數(shù)據(jù),并且檢索總是返回一個空集。
?
?
?
FEDERATED存儲引擎把數(shù)據(jù)存在遠程數(shù)據(jù)庫中。在MySQL 5.1中,它只和MySQL一起工作,使用MySQL C Client API。在未來的分發(fā)版中,我們想要讓它使用其它驅(qū)動器或客戶端連接方法連接到另外的數(shù)據(jù)源。
?
?
?
如何選擇最適合你的存儲引擎呢?
?
?
?
MyISAM:默認(rèn)的MySQL插件式存儲引擎,它是在Web、數(shù)據(jù)倉儲和其他應(yīng)用環(huán)境下最常使用的存儲引擎之一。注意,通過更改STORAGE_ENGINE配置變量,能夠方便地更改MySQL服務(wù)器的默認(rèn)存儲引擎。
?
?
?
InnoDB:用于事務(wù)處理應(yīng)用程序,具有眾多特性,包括ACID事務(wù)支持。(提供行級鎖)
?
?
?
BDB:可替代InnoDB的事務(wù)引擎,支持COMMIT、ROLLBACK和其他事務(wù)特性。
?
?
?
Memory:將所有數(shù)據(jù)保存在RAM中,在需要快速查找引用和其他類似數(shù)據(jù)的環(huán)境下,可提供極快的訪問。
?
?
?
Merge:允許MySQL DBA或開發(fā)人員將一系列等同的MyISAM表以邏輯方式組合在一起,并作為1個對象引用它們。對于諸如數(shù)據(jù)倉儲等VLDB環(huán)境十分適合。
?
?
?
Archive:為大量很少引用的歷史、歸檔、或安全審計信息的存儲和檢索提供了完美的解決方案。
?
?
?
Federated:能夠?qū)⒍鄠€分離的MySQL服務(wù)器鏈接起來,從多個物理服務(wù)器創(chuàng)建一個邏輯數(shù)據(jù)庫。十分適合于分布式環(huán)境或數(shù)據(jù)集市環(huán)境。
?
?
?
Cluster/NDB:MySQL的簇式數(shù)據(jù)庫引擎,尤其適合于具有高性能查找要求的應(yīng)用程序,這類查找需求還要求具有最高的正常工作時間和可用性。
?
?
?
Other:其他存儲引擎包括CSV(引用由逗號隔開的用作數(shù)據(jù)庫表的文件),Blackhole(用于臨時禁止對數(shù)據(jù)庫的應(yīng)用程序輸入),以及Example引擎(可為快速創(chuàng)建定制的插件式存儲引擎提供幫助)。
?
?
?
MySQL存儲引擎比較
?
MyISAM
?
?
?
  ?MyISAM是MySQL的默認(rèn)存儲引擎。MyISAM不支持事務(wù)、也不支持外鍵,但其訪問(讀)速度快,對事務(wù)完整性沒有要求。?
  MyISAM除了提供ISAM里所沒有的索引和字段管理的大量功能,MyISAM還使用一種表格鎖定的機制,來優(yōu)化多個并發(fā)的讀寫操作,其代價是你需要經(jīng)常運行OPTIMIZE TABLE命令,來恢復(fù)被更新機制所浪費的空間。MyISAM還有一些有用的擴展,例如用來修復(fù)數(shù)據(jù)庫文件的MyISAMCHK工具和用來恢復(fù)浪費空間的MyISAMPACK工具。MYISAM強調(diào)了快速讀取操作,這可能就是為什么MySQL受到了WEB開發(fā)如此青睞的主要原因:在WEB開發(fā)中你所進行的大量數(shù)據(jù)操作都是讀取操作。所以,大多數(shù)虛擬主機提供商和INTERNET平臺提供商只允許使用MYISAM格式。MyISAM格式的一個重要缺陷就是不能在表損壞后恢復(fù)數(shù)據(jù)。
  InnoDB存儲引擎提供了具有提交、回滾和崩潰恢復(fù)能力的事務(wù)安全。但是比起MyISAM存儲引擎,InnoDB寫的處理效率差一些并且會占用更多的磁盤空間以保留數(shù)據(jù)和索引。
?
?
?
MEMORY/HEAP
?
?
?
  MEMORY(又叫HEAP)存儲引擎使用存在內(nèi)存中的內(nèi)容來創(chuàng)建表。每個MEMORY表只實際對應(yīng)一個磁盤文件。MEMORY類型的表訪問非常得快,因為它的數(shù)據(jù)是放在內(nèi)存中的,并且默認(rèn)使用HASH索引。但是一旦服務(wù)關(guān)閉,表中的數(shù)據(jù)就會丟失掉。?HEAP允許只駐留在內(nèi)存里的臨時表格。駐留在內(nèi)存里讓HEAP要比ISAM和MYISAM都快,但是它所管理的數(shù)據(jù)是不穩(wěn)定的,而且如果在關(guān)機之前沒有進行保存,那么所有的數(shù)據(jù)都會丟失。在數(shù)據(jù)行被刪除的時候,HEAP也不會浪費大量的空間。HEAP表格在你需要使用SELECT表達式來選擇和操控數(shù)據(jù)的時候非常有用。
  MEMORY主要用于那些內(nèi)容變化不頻繁的代碼表,或者作為統(tǒng)計操作的中間結(jié)果表,便于高效地堆中間結(jié)果進行分析并得到最終的統(tǒng)計結(jié)果。
?
?
?
MERGE
?
?
?
  MERGE存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結(jié)構(gòu)完全相同。MERGE表本身沒有數(shù)據(jù),對MERGE類型的表進行查詢、更新、刪除的操作,就是對內(nèi)部的MyISAM表進行的。?MERGE用于將一系列等同的MyISAM表以邏輯方式組合在一起,并作為一個對象引用它。MERGE表的優(yōu)點在于可以突破對單個MyISAM表大小的限制,通過將不同的表分布在多個磁盤上,可以有效的改善MERGE表的訪問效率。
  MyISAM與InnoDB的區(qū)別
  InnoDB和MyISAM是許多人在使用MySQL時最常用的兩個表類型,這兩個表類型各有優(yōu)劣,視具體應(yīng)用而定。基本的差別為:MyISAM類型不支持事務(wù)處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調(diào)的是性能,其執(zhí)行數(shù)度比InnoDB類型更快,但是不提供事務(wù)支持,而InnoDB提供事務(wù)支持已經(jīng)外部鍵等高級數(shù)據(jù)庫功能。
  MyISAM表還支持3中不同的存儲格式:??靜態(tài)表?、?動態(tài)表?、壓縮表?
  靜態(tài)表是默認(rèn)的存儲格式,靜態(tài)表中的字段都是非變長的字段,優(yōu)點是:存儲非常迅速,容易緩存,出現(xiàn)故障容易恢復(fù);缺點是:占用的空間通常比動態(tài)表多。(注意: 在存儲時,列的寬度不足時,用空格補足,當(dāng)時在訪問的時候并不會得到這些空格)?
  動態(tài)表的字段是變長的,優(yōu)點是:占用的空間相對較少,但是頻繁地更新刪除記錄會產(chǎn)生碎片,需要定期改善性能,并且出現(xiàn)故障的時候恢復(fù)相對比較困難。?
  壓縮表占用磁盤空間小,每個記錄是被單獨壓縮的,所以只有非常小的訪問開支。?
  InnoDB存儲方式為兩種:使用共享表空間存儲 、使用多表空間
?
-  簡述數(shù)據(jù)三大范式?
?
什么是范式?
?
簡言之就是,數(shù)據(jù)庫設(shè)計對數(shù)據(jù)的存儲性能,還有開發(fā)人員對數(shù)據(jù)的操作都有莫大的關(guān)系。所以建立科學(xué)的,規(guī)范的的數(shù)據(jù)庫是需要滿足一些規(guī)范的來優(yōu)化數(shù)據(jù)數(shù)據(jù)存儲方式。在關(guān)系型數(shù)據(jù)庫中這些規(guī)范就可以稱為范式。(簡單來說,就是根據(jù)需要,來優(yōu)化數(shù)據(jù)存儲方式!)
?
什么是三大范式?
?
第一范式:當(dāng)關(guān)系模式R的所有屬性都不能在分解為更基本的數(shù)據(jù)單位時,稱R是滿足第一范式的,簡記為1NF。滿足第一范式是關(guān)系模式規(guī)范化的最低要求,否則,將有很多基本操作在這樣的關(guān)系模式中實現(xiàn)不了。(說白了,就是關(guān)系模式R的所有屬性不能再分解了,那么R就滿足第一范式!)
?
特性:
?
1、每一列屬性都是不可再分的屬性值,確保每一列的原子性
?
2、兩列的屬性相近或相似或一樣,盡量合并屬性一樣的列,確保不產(chǎn)生冗余數(shù)據(jù)。
?
?
?
如果需求知道那個省那個市并按其分類,那么顯然第一個表格是不容易滿足需求的,也不符合第一范式。
?
?
?
?
顯然第一個表結(jié)構(gòu)不但不能滿足足夠多物品的要求,還會在物品少時產(chǎn)生冗余。也是不符合第一范式的。
?
第二范式:如果關(guān)系模式R滿足第一范式,并且R得所有非主屬性都完全依賴于R的每一個候選關(guān)鍵屬性,稱R滿足第二范式,簡記為2NF。(說白了,就是非主屬性都要依賴于每一個關(guān)鍵屬性!)
?
每一行的數(shù)據(jù)只能與其中一列相關(guān),即一行數(shù)據(jù)只做一件事。只要數(shù)據(jù)列中出現(xiàn)數(shù)據(jù)重復(fù),就要把表拆分開來。
?
?
一個人同時訂幾個房間,就會出來一個訂單號多條數(shù)據(jù),這樣子聯(lián)系人都是重復(fù)的,就會造成數(shù)據(jù)冗余。我們應(yīng)該把他拆開來。
?
?
?
?
這樣便實現(xiàn)一條數(shù)據(jù)做一件事,不摻雜復(fù)雜的關(guān)系邏輯。同時對表數(shù)據(jù)的更新維護也更易操作。
?
第三范式:設(shè)R是一個滿足第一范式條件的關(guān)系模式,X是R的任意屬性集,如果X非傳遞依賴于R的任意一個候選關(guān)鍵字,稱R滿足第三范式,簡記為3NF.
?
數(shù)據(jù)不能存在傳遞關(guān)系,即沒個屬性都跟主鍵有直接關(guān)系而不是間接關(guān)系。像:a-->b-->c ?屬性之間含有這樣的關(guān)系,是不符合第三范式的。
?
比如Student表(學(xué)號,姓名,年齡,性別,所在院校,院校地址,院校電話)
?
這樣一個表結(jié)構(gòu),就存在上述關(guān)系。 學(xué)號-->?所在院校 --> (院校地址,院校電話)
?
這樣的表結(jié)構(gòu),我們應(yīng)該拆開來,如下。
?
(學(xué)號,姓名,年齡,性別,所在院校)--(所在院校,院校地址,院校電話)
?
-  什么是事務(wù)?MySQL如何支持事務(wù)?
?
什么是事務(wù)?
?
事務(wù)是由一步或幾步數(shù)據(jù)庫操作序列組成邏輯執(zhí)行單元,這系列操作要么全部執(zhí)行,要么全部放棄執(zhí)行。程序和事務(wù)是兩個不同的概念。一般而言:一段程序中可能包含多個事務(wù)。(說白了就是幾步的數(shù)據(jù)庫操作而構(gòu)成的邏輯執(zhí)行單元)
?
事務(wù)具有四個特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持續(xù)性(Durability)。這四個特性也簡稱ACID性。
?
(1)原子性:事務(wù)是應(yīng)用中最小的執(zhí)行單位,就如原子是自然界最小顆粒,具有不可再分的特征一樣。事務(wù)是應(yīng)用中不可再分的最小邏輯執(zhí)行體。(最小了,不可再分了)
?
(2)一致性:事務(wù)執(zhí)行的結(jié)果,必須使數(shù)據(jù)庫從一個一致性狀態(tài),變到另一個一致性狀態(tài)。當(dāng)數(shù)據(jù)庫中只包含事務(wù)成功提交的結(jié)果時,數(shù)據(jù)庫處于一致性狀態(tài)。一致性是通過原子性來保證的。(說罷了就是白狗變成了黑狗,不能出現(xiàn)斑點狗!)
?
(3)隔離性:各個事務(wù)的執(zhí)行互不干擾,任意一個事務(wù)的內(nèi)部操作對其他并發(fā)的事務(wù),都是隔離的。也就是說:并發(fā)執(zhí)行的事務(wù)之間不能看到對方的中間狀態(tài),并發(fā)執(zhí)行的事務(wù)之間不能相互影響。(說白了,就是你做你的,我做我的!)
?
(4)持續(xù)性:持續(xù)性也稱為持久性,指事務(wù)一旦提交,對數(shù)據(jù)所做的任何改變,都要記錄到永久存儲器中,通常是保存進物理數(shù)據(jù)庫。(說白了就是一條道跑到黑)
?
MySQL如何支持事務(wù)?
?
MYSQL的事務(wù)處理主要有兩種方法
?
  1.用begin,rollback,commit來實現(xiàn)
    begin開始一個事務(wù)
    rollback事務(wù)回滾
???    commit 事務(wù)確認(rèn)
  2.直接用set來改變mysql的自動提交模式
???    ? ?mysql默認(rèn)是自動提交的,也就是你提交一個query,就直接執(zhí)行!可以通過
???    ? ?set autocommit = 0 禁止自動提交
???    ? ?set autocommit = 1 開啟自動提交
? ? ? ?來實現(xiàn)事務(wù)的處理
?
-  簡述數(shù)據(jù)庫設(shè)計中一對多和多對多的應(yīng)用場景?
-  如何基于數(shù)據(jù)庫實現(xiàn)商城商品計數(shù)器?
-  常見SQL(必備)
-  數(shù)據(jù)庫操作1、顯示數(shù)據(jù)庫 1 SHOW DATABASES; 2、創(chuàng)建數(shù)據(jù)庫 1 2 3 4 5 # utf-8 CREATE DATABASE 數(shù)據(jù)庫名稱 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; # gbk CREATE DATABASE 數(shù)據(jù)庫名稱 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci; 3、使用數(shù)據(jù)庫 1 USE db_name; 顯示當(dāng)前使用的數(shù)據(jù)庫中所有表:SHOW TABLES; 4、用戶管理 1 2 3 4 5 6 7 8 9 10 創(chuàng)建用戶 ????create user?'用戶名'@'IP地址'?identified by?'密碼'; 刪除用戶 ????drop user?'用戶名'@'IP地址'; 修改用戶 ????rename user?'用戶名'@'IP地址'; to?'新用戶名'@'IP地址';; 修改密碼 ????set password?for?'用戶名'@'IP地址'?= Password('新密碼') ?? PS:用戶權(quán)限相關(guān)數(shù)據(jù)保存在mysql數(shù)據(jù)庫的user表中,所以也可以直接對其進行操作(不建議) 5、授權(quán)管理 1 2 3 show grants?for?'用戶'@'IP地址'??????????????????-- 查看權(quán)限 grant? 權(quán)限 on 數(shù)據(jù)庫.表 to???'用戶'@'IP地址'??????-- 授權(quán) revoke 權(quán)限 on 數(shù)據(jù)庫.表 from?'用戶'@'IP地址'??????-- 取消權(quán)限 
-  、數(shù)據(jù)表基本1、創(chuàng)建表 1 2 3 4 create table 表名( ????列名? 類型? 是否可以為空, ????列名? 類型? 是否可以為空 )ENGINE=InnoDB DEFAULT CHARSET=utf8 
-  2、刪除表 1 drop table 表名 3、清空表 1 2 delete?from 表名 truncate table 表名 4、修改表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 添加列:alter table 表名 add 列名 類型 刪除列:alter table 表名 drop column 列名 修改列: ????????alter table 表名 modify column 列名 類型;? -- 類型 ????????alter table 表名 change 原列名 新列名 類型; -- 列名,類型 ?? 添加主鍵: ????????alter table 表名 add primary key(列名); 刪除主鍵: ????????alter table 表名 drop primary key; ????????alter table 表名? modify? 列名 int, drop primary key; ?? 添加外鍵:alter table 從表 add constraint 外鍵名稱(形如:FK_從表_主表) foreign key 從表(外鍵字段) references 主表(主鍵字段); 刪除外鍵:alter table 表名 drop foreign key 外鍵名稱 ?? 修改默認(rèn)值:ALTER TABLE testalter_tbl ALTER i SET DEFAULT 1000; 刪除默認(rèn)值:ALTER TABLE testalter_tbl ALTER i DROP DEFAULT; 5、基本數(shù)據(jù)類型 MySQL的數(shù)據(jù)類型大致分為:數(shù)值、時間和字符串 
-  表內(nèi)容操作1、增 1 2 3 insert?into?表 (列名,列名...)?values?(值,值,值...) insert?into?表 (列名,列名...)?values?(值,值,值...),(值,值,值...) insert?into?表 (列名,列名...)?select?(列名,列名...)?from?表 2、刪 1 2 delete?from?表 delete?from?表?where?id=1?and?name='alex' 3、改 1 update?表?set?name?=?'alex'?where?id>1 4、查 1 2 3 select?*?from?表 select?*?from?表?where?id > 1 select?nid,name,gender?as?gg?from?表?where?id > 1 5、其他 
-  MySQL服務(wù)器默認(rèn)端口是什么?MySQL服務(wù)器的默認(rèn)端口是3306。 
-  ?什么是數(shù)據(jù)庫約束,常見的約束有哪幾種?數(shù)據(jù)庫約束用于保證數(shù)據(jù)庫表數(shù)據(jù)的完整性(正確性和一致性)。可以通過定義約束\索引\觸發(fā)器來保證數(shù)據(jù)的完整性。 總體來講,約束可以分為: 主鍵約束:primary key; 外鍵約束:foreign key; 唯一約束:unique; 檢查約束:check; 空值約束:not null; 默認(rèn)值約束:default;
-  MySQL基本語法增:創(chuàng)建數(shù)據(jù)表 USE database CREATE TABLE example(id INT, name VARCHAR(20), sex BOOLEAN);刪: ALTER TABLE 表名 DROP 屬性名; # 刪除字段 DROP TABLE 表名; # 刪除表改: ALTER TABLE 舊表名 RENAME 新表名; # 修改表名 ALTER TABLE 表名 MODIFY 屬性名 數(shù)據(jù)類型; # 修改字段數(shù)據(jù)類型查: SELECT * FROM 表名 WHERE id=1; # 條件查詢 SELECT * FROM 表名 WHERE 字段名 BETWEEN 條件一 AND 條件二 # 范圍查詢 SELECT COUNT(*) FROM 表名; # 查詢表共有多少條記錄觸發(fā)器:是由INSERT、UPDATE和DELETE等事件來觸發(fā)某種特定操作,滿足觸發(fā)條件時,數(shù)據(jù)庫系統(tǒng)會執(zhí)行觸發(fā)器中定義的語句,這樣可以保證某些操作之間的一致性。 CREATE TRIGGER 觸發(fā)器名稱 BEFORE|AFTER 觸發(fā)事件 ON 表名稱 FOR EACH ROW BEGIN 執(zhí)行語句 END
-  簡述觸發(fā)器、函數(shù)、視圖、存儲過程?
?
1、視圖
?
視圖只是一種邏輯對象,是一種虛擬表,它并不是物理對象,因為視圖不占物理存儲空間,在視圖中被查詢的表稱為視圖的基表,大多數(shù)的select語句都可以用在創(chuàng)建視圖中(說白了,視圖就是一種虛擬表,就像是一張電子照片)
?
優(yōu)點:集中用戶使用的數(shù)據(jù),掩碼數(shù)據(jù)的復(fù)雜性,簡化權(quán)限管理以及為向其他應(yīng)用程序輸出而重新組織數(shù)據(jù)等
?
2、觸發(fā)器
?
(1)觸發(fā)器是一個特殊的存儲過程,它是MySQL在insert、update、delete的時候自動執(zhí)行的代碼塊。
?
(2)觸發(fā)器必須定義在特定的表上。
?
(3)自動執(zhí)行,不能直接調(diào)用,
?
(說白了,觸發(fā)器其實就是一個神,他會待在自己的廟宇中,當(dāng)百姓受難了,通過一些禱告儀式,如insert、update、delete,他會自動的進行降妖除魔!)
?
3、函數(shù)
?
它跟php或js中的函數(shù)幾乎一樣:需要先定義,然后調(diào)用(使用)。
?
只是規(guī)定,這個函數(shù),必須要返回數(shù)據(jù)——要有返回值
?
4、存儲過程
?
存儲過程(procedure),概念類似于函數(shù),就是把一段代碼封裝起來,當(dāng)要執(zhí)行這一段代碼的時候,可以通過調(diào)用該存儲過程來實現(xiàn)。在封裝的語句體里面,可以同if/else ,case,while等控制結(jié)構(gòu),可以進行sql編程,查看現(xiàn)有的存儲過程。
?
?
?
-  MySQL索引種類
?
1、普通索引
?
這是最基本的索引,它沒有任何限制,比如上文中為title字段創(chuàng)建的索引就是一個普通索引,MyIASM中默認(rèn)的BTREE類型的索引,也是我們大多數(shù)情況下用到的索引。
?
–直接創(chuàng)建索引 CREATE INDEX index_name ON table(column(length)) –修改表結(jié)構(gòu)的方式添加索引 ALTER TABLE table_name ADD INDEX index_name ON (column(length)) –創(chuàng)建表的時候同時創(chuàng)建索引 CREATE TABLE `table` ( `id` int(11) NOT NULL AUTO_INCREMENT , `title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL , `time` int(10) NULL DEFAULT NULL , PRIMARY KEY (`id`), INDEX index_name (title(length)) ) –刪除索引 DROP INDEX index_name ON table?
2、 唯一索引
?
與普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值(注意和主鍵不同)。如果是組合索引,則列值的組合必須唯一,創(chuàng)建方法和普通索引類似。
?
–創(chuàng)建唯一索引 CREATE?UNIQUE?INDEX?indexName?ON?table(column(length)) –修改表結(jié)構(gòu) ALTER?TABLE?table_name?ADD?UNIQUE?indexName?ON?(column(length)) –創(chuàng)建表的時候直接指定 CREATE?TABLE?`table` ( `id`?int(11)?NOT?NULL?AUTO_INCREMENT , `title`?char(255)?CHARACTER?SET?utf8?COLLATE?utf8_general_ci?NOT?NULL?, `content` text?CHARACTER?SET?utf8?COLLATE?utf8_general_ci?NULL?, `time`?int(10)?NULL?DEFAULT?NULL?, PRIMARY?KEY?(`id`), UNIQUE?indexName (title(length)) );?
3、全文索引(FULLTEXT)
?
MySQL從3.23.23版開始支持全文索引和全文檢索,FULLTEXT索引僅可用于 MyISAM 表;他們可以從CHAR、VARCHAR或TEXT列中作為CREATE TABLE語句的一部分被創(chuàng)建,或是隨后使用ALTER TABLE 或CREATE INDEX被添加。對于較大的數(shù)據(jù)集,將你的資料輸入一個沒有FULLTEXT索引的表中,然后創(chuàng)建索引,其速度比把資料輸入現(xiàn)有FULLTEXT索引的速度更為快。不過切記對于大容量的數(shù)據(jù)表,生成全文索引是一個非常消耗時間非常消耗硬盤空間的做法。
?
–創(chuàng)建表的適合添加全文索引 CREATE?TABLE?`table` ( `id`?int(11)?NOT?NULL?AUTO_INCREMENT , `title`?char(255)?CHARACTER?SET?utf8?COLLATE?utf8_general_ci?NOT?NULL?, `content` text?CHARACTER?SET?utf8?COLLATE?utf8_general_ci?NULL?, `time`?int(10)?NULL?DEFAULT?NULL?, PRIMARY?KEY?(`id`), FULLTEXT (content) ); –修改表結(jié)構(gòu)添加全文索引 ALTER?TABLE?article?ADD?FULLTEXT index_content(content) –直接創(chuàng)建索引 CREATE?FULLTEXT?INDEX?index_content?ON?article(content)?
4.、單列索引、多列索引
多個單列索引與單個多列索引的查詢效果不同,因為執(zhí)行查詢時,MySQL只能使用一個索引,會從多個索引中選擇一個限制最為嚴(yán)格的索引。
5.、組合索引(最左前綴)
平時用的SQL查詢語句一般都有比較多的限制條件,所以為了進一步榨取MySQL的效率,就要考慮建立組合索引。例如上表中針對title和time建立一個組合索引:ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))。建立這樣的組合索引,其實是相當(dāng)于分別建立了下面兩組組合索引:
?
–title,time
–title
?
為什么沒有time這樣的組合索引呢?這是因為MySQL組合索引“最左前綴”的結(jié)果。簡單的理解就是只從最左面的開始組合。并不是只要包含這兩列的查詢都會用到該組合索引,如下面的幾個SQL所示:
?
–使用到上面的索引 SELECT?*?FROM?article WHREE title='測試'?AND?time=1234567890; SELECT?*?FROM?article WHREE utitle='測試'; –不使用上面的索引 SELECT?*?FROM?article WHREE?time=1234567890;?
?
?
-  索引在什么情況下遵循最左前綴的規(guī)則?
?
索引的最左前綴原理:
?
通常我們在建立聯(lián)合索引的時候,也就是對多個字段建立索引,相信建立過索引的同學(xué)們會發(fā)現(xiàn),無論是oralce還是mysql都會讓我們選擇索引的順序,比如我們想在a,b,c三個字段上建立一個聯(lián)合索引,我們可以選擇自己想要的優(yōu)先級,a、b、c,或者是b、a、c 或者是c、a、b等順序。為什么數(shù)據(jù)庫會讓我們選擇字段的順序呢?不都是三個字段的聯(lián)合索引么?這里就引出了數(shù)據(jù)庫索引的最左前綴原理。
?
比如:索引index1:(a,b,c)有三個字段,我們在使用sql語句來查詢的時候,會發(fā)現(xiàn)很多情況下不按照我們想象的來走索引。
?
select * from table where c = '1'?
這個sql語句是不會走index1索引的
?
select * from table where b =‘1’ and c ='2'?
這個語句也不會走index1索引。
?
什么語句會走index1索引呢?
?
答案是:
?
select * from table?where?a?= '1'??select * from table?where?a?= '1'?and?b = ‘2’??select * from table?where?a?= '1'?and?b = ‘2’? and c='3'?
我們可以發(fā)現(xiàn)一個共同點,就是所有走索引index1的sql語句的查詢條件里面都帶有a字段,那么問題來了,index1的索引的最左邊的列字段是a,是不是查詢條件中包含a就會走索引呢?
?
例如:
?
select * from table where a = '1' and c= ‘2’?
這個sql語句,按照之前的理解,包含a字段,會走索引,但是是不是所有字段都走了索引呢?
?
我們來做個實驗:
?
我這里有一個表:
?
?
建立了一個聯(lián)合索引,prinIdAndOrder里面有三個字段 ?PARENT_ID, MENU_ORDER, MENU_NAME
?
接下來測試之前的語句:
?
EXPLAIN SELECT?t.*? FROMsys_menu t? WHERE t.`PARENT_ID` = '0'?AND t.`MENU_NAME` = '系統(tǒng)工具'?
這一句sql就相當(dāng)于之前的select * from table where a = '1' and c= ‘2’這個sql語句了,我們來看看解釋計劃:
?
?
可以看到走了索引prinIdAndOrder,但是旁邊的key_len=303,但道理key_len應(yīng)該是大于303的,為什么呢?因為PARENT_ID字段的類型是varchar(100) NULL,所以key_len=100*3+2+1=303,但是還有MENU_NAME呢!具體的key_len的計算方法,大家可以百度,我的表的字符集是utf-8,不同字符集的表的計算方式不一樣。這里的解釋計劃顯示key_len只有303,說明只是走了字段PARENT_ID的索引,沒有走MENU_NAME的索引。
?
這也是最左前綴原理的一部分,索引index1:(a,b,c),只會走a、a,b、a,b,c 三種類型的查詢,其實這里說的有一點問題,a,c也走,但是只走a字段索引,不會走c字段。
?
另外還有一個特殊情況說明下,select * from table where a = '1' and b > ‘2’ ?and c='3' 這種類型的也只會有a與b走索引,c不會走。
?
像select * from table where a = '1' and b > ‘2’ ?and c='3' 這種類型的sql語句,在a、b走完索引后,c肯定是無序了,所以c就沒法走索引,數(shù)據(jù)庫會覺得還不如全表掃描c字段來的快。不知道我說明白沒,感覺這一塊說的始終有點牽強。
?
-  主鍵和外鍵的區(qū)別?
?
主鍵
?
定義:唯一標(biāo)識一條記錄,不能有重復(fù)的,不允許為空
?
作用:用來保證數(shù)據(jù)完整性
?
個數(shù):主鍵只能有一個
?
ALTER TABLE “表名” ADD PRIMARY KEY (字段名)?
外鍵
?
定義:表的外鍵是另一表的主鍵, 外鍵可以有重復(fù)的, 可以是空值
?
作用:用來和其他表建立聯(lián)系用的
?
個數(shù):一個表可以有多個外鍵
?
ALTER TABLE “表名” ADD FOREIGN KEY (字段名) REFERENCES “另一張表名”( 字段名)?
?
?
-  MySQL常見的函數(shù)?
MySQL常見的函數(shù)
-  列舉 創(chuàng)建索引但是無法命中索引的8種情況。
?
1、如果條件中有or,即使其中有條件帶索引也不會使用(這也是為什么盡量少用or的原因)
?
?
注意:要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引
?
2、對于多列索引,不是使用的第一部分(第一個),則不會使用索引
?
3、like查詢是以%開頭
?
?
4、如果列類型是字符串,那一定要在條件中將數(shù)據(jù)使用引號引用起來,否則不使用索引
?
?
?
5、如果mysql估計使用全表掃描要比使用索引快,則不使用索引
?
其他
?
?
?
?
-  如何開啟慢日志查詢?
?
1、為什么要開啟慢日志查詢?
?
開啟慢查詢?nèi)罩?#xff0c;可以讓MySQL記錄下查詢超過指定時間的語句,通過定位分析性能的瓶頸,才能更好的優(yōu)化數(shù)據(jù)庫系統(tǒng)的性能。
?
2、參數(shù)說明
?
slow_query_log 慢查詢開啟狀態(tài)
slow_query_log_file 慢查詢?nèi)罩敬娣诺奈恢?#xff08;這個目錄需要MySQL的運行帳號的可寫權(quán)限,一般設(shè)置為MySQL的數(shù)據(jù)存放目錄)
long_query_time 查詢超過多少秒才記錄
?
3、設(shè)置步驟
?
①.查看慢查詢相關(guān)參數(shù)
?
mysql> show variables like 'slow_query%'; +---------------------------+----------------------------------+ | Variable_name | Value | +---------------------------+----------------------------------+ | slow_query_log | OFF | | slow_query_log_file | /mysql/data/localhost-slow.log | +---------------------------+----------------------------------+mysql> show variables like 'long_query_time'; +-----------------+-----------+ | Variable_name | Value | +-----------------+-----------+ | long_query_time | 10.000000 | +-----------------+-----------+?
②.設(shè)置方法
?
將 slow_query_log 全局變量設(shè)置為“ON”狀態(tài)
?
mysql> set global slow_query_log='ON';?
?
設(shè)置慢查詢?nèi)罩敬娣诺奈恢?/p>
?
mysql> set global slow_query_log_file='/var/lib/mysql/test-10-226-slow.log';?
?
查詢超過1秒就記錄
?
mysql> set global long_query_time=1;?
?
經(jīng)過這些操作,則慢日志查詢也就開啟了!但這種方法只是臨時生效,mysql重啟后就會失效
?
所以我們不能讓他失效,所以需進行如下操作
?
編輯配置文件/etc/my.cnf加入如下內(nèi)容
?
[mysqld] slow_query_log = ON slow_query_log_file = /var/lib/mysql/test-10-226-slow.log long_query_time = 1?
?
修改配置后重啟
?
mysqlsystemctl restart mysqld mysql -uroot -p
?
?
使用下面命令驗證
?
show variables like 'slow_query%';?
mysql永久開啟了漫查詢?nèi)罩竟δ?/p>
?
?
-  數(shù)據(jù)庫導(dǎo)入導(dǎo)出命令(結(jié)構(gòu)+數(shù)據(jù))?
?
在命令行下mysql的數(shù)據(jù)導(dǎo)出有個很好用命令mysqldump,它的參數(shù)有一大把,可以這樣查看:
?
mysqldump?
(mysqldump命令位于mysql/bin/目錄中) //要專到mysql/bin/目錄中才能使用,直接cmd運行命令窗口使用不了,專到數(shù)據(jù)庫所在的mysql/bin/目錄中使用.
?
最常用的:
?
mysqldump -uroot -pmysql databasefoo table1 table2 > foo.sql?
這樣就可以將數(shù)據(jù)庫databasefoo的表table1,table2以sql形式導(dǎo)入foo.sql中,其中-uroot參數(shù)表示訪問數(shù)據(jù)庫的用戶名是root,如果有密碼還需要加上-p參數(shù)
?
C:\Users\jack> mysqldump -uroot -pmysql sva_rec date_drv > e:\date_drv.sql?
mysql的數(shù)據(jù)導(dǎo)入也是相當(dāng)便捷的,如:
?
mysql -uroot databasefoo < foo.sql?
這樣就可以將foo.sql的數(shù)據(jù)全部導(dǎo)入數(shù)據(jù)庫databasefoo
?
導(dǎo)出整個數(shù)據(jù)庫
?
mysqldump -u用戶名 -p密碼 ?數(shù)據(jù)庫名 > 導(dǎo)出的文件名
?
C:\Users\jack> mysqldump -uroot -pmysql sva_rec? > e:\sva_rec.sql?
導(dǎo)出一個表,包括表結(jié)構(gòu)和數(shù)據(jù)
?
mysqldump -u用戶名 -p 密碼 ?數(shù)據(jù)庫名 表名> 導(dǎo)出的文件名
?
C:\Users\jack> mysqldump -uroot -pmysql sva_rec date_rec_drv> e:\date_rec_drv.sql?
導(dǎo)出一個數(shù)據(jù)庫結(jié)構(gòu)
?
C:\Users\jack> mysqldump -uroot -pmysql -d sva_rec > e:\sva_rec.sql?
導(dǎo)出一個表,只有表結(jié)構(gòu)
?
mysqldump -u用戶名 -p 密碼 -d數(shù)據(jù)庫名 ?表名> 導(dǎo)出的文件名
?
C:\Users\jack> mysqldump -uroot -pmysql -d sva_rec date_rec_drv> e:\date_rec_drv.sql?
導(dǎo)入數(shù)據(jù)庫
?
常用source 命令
進入mysql數(shù)據(jù)庫控制臺,
如mysql -u root -p
mysql>use 數(shù)據(jù)庫
然后使用source命令,后面參數(shù)為腳本文件(如這里用到的.sql)
mysql>source d:wcnc_db.sql
?
-  數(shù)據(jù)庫優(yōu)化方案?
?
關(guān)于數(shù)據(jù)庫的優(yōu)化方案,可參考下面的鏈接
?
數(shù)據(jù)庫SQL優(yōu)化大總結(jié)1之- 百萬級數(shù)據(jù)庫優(yōu)化方案
?
-  char和varchar的區(qū)別?
?
就長度來說:
?
??char的長度是不可變的;
?
??而varchar的長度是可變的,也就是說,定義一個char[10]和varchar[10],如果存進去的是‘csdn’,那么char所占的長度依然為10,除了字符‘csdn’外,后面跟六個空格,而varchar就立馬把長度變?yōu)?了,取數(shù)據(jù)的時候,char類型的要用trim()去掉多余的空格,而varchar是不需要的,盡管如此,char的存取速度還是要比varchar要快得多,因為其長度固定,方便程序的存儲與查找;但是char也為此付出的是空間的代價,因為其長度固定,所以難免會有多余的空格占位符占據(jù)空間,可謂是以空間換取時間效率,而varchar是以空間效率為首位的。
?
就存儲方式來說:
?
??char的存儲方式是,對英文字符(ASCII)占用1個字節(jié),對一個漢字占用兩個字節(jié);
?
??而varchar的存儲方式是,對每個英文字符占用2個字節(jié),漢字也占用2個字節(jié),兩者的存儲數(shù)據(jù)都非unicode的字符數(shù)據(jù)。
?
-  簡述MySQL的執(zhí)行計劃?
https://www.cnblogs.com/xinysu/p/7860609.html
MySQL_執(zhí)行計劃詳細(xì)說明
-  在對name做了唯一索引前提下,簡述以下區(qū)別:??
 ? ? ? ? select * from tb where name = ‘Oldboy-Wupeiqi’ ??
 ? ? ? ? select * from tb where name = ‘Oldboy-Wupeiqi’ limit 1
-  1000w條數(shù)據(jù),使用limit offset 分頁時,為什么越往后翻越慢?如何解決?
?
在mysql中l(wèi)imit可以實現(xiàn)快速分頁,但是如果數(shù)據(jù)到了幾百萬時我們的limit必須優(yōu)化才能有效的合理的實現(xiàn)分頁了,否則可能卡死你的服務(wù)器哦。
?
當(dāng)一個表數(shù)據(jù)有幾百萬的數(shù)據(jù)的時候成了問題!
?
如 * from table limit 0,10 這個沒有問題 當(dāng) limit 200000,10 的時候數(shù)據(jù)讀取就很慢,可以按照一下方法解決第一頁會很快
?
PERCONA PERFORMANCE CONFERENCE 2009上,來自雅虎的幾位工程師帶來了一篇”EfficientPagination Using MySQL”的報告
?
limit10000,20的意思掃描滿足條件的10020行,扔掉前面的10000行,返回最后的20行,問題就在這里。
?
LIMIT 451350 , 30 掃描了45萬多行,怪不得慢的都堵死了。
?
但是,limit 30 這樣的語句僅僅掃描30行。
?
那么如果我們之前記錄了最大ID,就可以在這里做文章
?
舉個例子
?
日常分頁SQL語句
?
select id,name,content from users order by id asc limit 100000,20?
掃描100020行
?
如果記錄了上次的最大ID
?
select id,name,content from users where id>10073 order by id asc limit 20?
掃描20行。
?
總數(shù)據(jù)有500萬左右
?
以下例子 當(dāng) select * from wl_tagindex where byname='f' order by id limit 300000,10 執(zhí)行時間是 3.21s
?
優(yōu)化后:
?
select * from (select id from wl_tagindexwhere byname='f' order by id limit 300000,10 ) a left join wl_tagindex b on a.id=b.id?
執(zhí)行時間為 0.11s 速度明顯提升
這里需要說明的是 我這里用到的字段是 byname ,id 需要把這兩個字段做復(fù)合索引,否則的話效果提升不明顯
?
總結(jié)
?
當(dāng)一個數(shù)據(jù)庫表過于龐大,LIMIT offset, length中的offset值過大,則SQL查詢語句會非常緩慢,你需增加order by,并且order by字段需要建立索引。
?
如果使用子查詢?nèi)?yōu)化LIMIT的話,則子查詢必須是連續(xù)的,某種意義來講,子查詢不應(yīng)該有where條件,where會過濾數(shù)據(jù),使數(shù)據(jù)失去連續(xù)性。
?
如果你查詢的記錄比較大,并且數(shù)據(jù)傳輸量比較大,比如包含了text類型的field,則可以通過建立子查詢。
?
SELECT id,title,content FROM items WHERE id IN (SELECT id FROM items ORDER BY id limit 900000, 10);?
如果limit語句的offset較大,你可以通過傳遞pk鍵值來減小offset = 0,這個主鍵最好是int類型并且auto_increment
?
SELECT * FROM users WHERE uid > 456891 ORDER BY uid LIMIT 0, 10;?
這條語句,大意如下:
?
SELECT * FROM users WHERE uid >= (SELECT uid FROM users ORDER BY uid limit 895682, 1) limit 0, 10;?
如果limit的offset值過大,用戶也會翻頁疲勞,你可以設(shè)置一個offset最大的,超過了可以另行處理,一般連續(xù)翻頁過大,用戶體驗很差,則應(yīng)該提供更優(yōu)的用戶體驗給用戶。
?
關(guān)于limit 分頁優(yōu)化方法請參考下面的鏈接:
?
MYSQL分頁limit速度太慢的優(yōu)化方法
?
-  什么是索引合并?
?
什么是索引合并?
?
下面我們看下mysql文檔中對索引合并的說明:
?
The Index Merge method is used to retrieve rows with several range scans and to merge their results into one. The merge can produce unions, intersections, or unions-of-intersections of its underlying scans. This access method merges index scans from a single table; it does not merge scans across multiple tables.
?
根據(jù)官方文檔中的說明,我們可以了解到:
?
1、索引合并是把幾個索引的范圍掃描合并成一個索引。
?
2、索引合并的時候,會對索引進行并集,交集或者先交集再并集操作,以便合并成一個索引。
?
3、這些需要合并的索引只能是一個表的。不能對多表進行索引合并。
?
怎么確定使用了索引合并?
?
在使用explain對sql語句進行操作時,如果使用了索引合并,那么在輸出內(nèi)容的type列會顯示 index_merge,key列會顯示出所有使用的索引。如下:
?
使用索引合并的示例
?
數(shù)據(jù)表結(jié)構(gòu):
?
mysql> show create table test\G *************************** 1. row ***************************Table: test Create Table: CREATE TABLE `test` (`id` int(11) NOT NULL AUTO_INCREMENT,`key1_part1` int(11) NOT NULL DEFAULT '0',`key1_part2` int(11) NOT NULL DEFAULT '0',`key2_part1` int(11) NOT NULL DEFAULT '0',`key2_part2` int(11) NOT NULL DEFAULT '0',PRIMARY KEY (`id`),KEY `key1` (`key1_part1`,`key1_part2`),KEY `key2` (`key2_part1`,`key2_part2`) ) ENGINE=MyISAM AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)?
數(shù)據(jù)
?
?
使用索引合并的案例
?
mysql> explain select * from test where (key1_part1=4 and key1_part2=4) or key2_part1=4\G *************************** 1. row ***************************id: 1select_type: SIMPLEtable: testtype: index_merge possible_keys: key1,key2key: key1,key2key_len: 8,4ref: NULLrows: 3Extra: Using sort_union(key1,key2); Using where 1 row in set (0.00 sec)?
未使用索引合并的案例
?
mysql> explain select * from test where (key1_part1=1 and key1_part2=1) or key2_part1=4\G *************************** 1. row ***************************id: 1select_type: SIMPLEtable: testtype: ALL possible_keys: key1,key2key: NULLkey_len: NULLref: NULLrows: 29Extra: Using where 1 row in set (0.00 sec)?
從上面的兩個案例大家可以發(fā)現(xiàn),相同模式的sql語句,可能有時能使用索引,有時不能使用索引。是否能使用索引,取決于mysql查詢優(yōu)化器對統(tǒng)計數(shù)據(jù)分析后,是否認(rèn)為使用索引更快。因此,單純的討論一條sql是否可以使用索引有點片面,還需要考慮數(shù)據(jù)。
?
注意事項
?
mysql5.6.7之前的版本遵守range優(yōu)先的原則。也就是說,當(dāng)一個索引的一個連續(xù)段,包含所有符合查詢要求的數(shù)據(jù)時,哪怕索引合并能提供效率,也不再使用索引合并。舉個例子:
?
mysql> explain select * from test where (key1_part1=1 and key1_part2=1) and key2_part1=1\G *************************** 1. row ***************************id: 1select_type: SIMPLEtable: testtype: ref possible_keys: key1,key2key: key2key_len: 4ref: constrows: 9Extra: Using where 1 row in set (0.00 sec)?
上面符合查詢要求的結(jié)果只有一條,而這一條記錄被索引key2所包含。
?
可以看到這條sql語句使用了key2索引。但是這個并不是最快的執(zhí)行方式。其實,把索引key1和索引key2進行索引合并,取交集后,就發(fā)現(xiàn)只有一條記錄適合。應(yīng)該查詢效率會更快。
?
tips:這條sql語句未在mysql5.6.7之后版本執(zhí)行驗證,以上為理論推導(dǎo)。有興趣的話,您可以到mysql5.6.7之后版本上驗證下。
?
-  什么是覆蓋索引?
?
什么是覆蓋索引?
?
通常開發(fā)人員會根據(jù)查詢的where條件來創(chuàng)建合適的索引,但是優(yōu)秀的索引設(shè)計應(yīng)該考慮到整個查詢。其實mysql可以使用索引來直接獲取列的數(shù)據(jù)。如果索引的葉子節(jié)點包含了要查詢的數(shù)據(jù),那么就不用回表查詢了,也就是說這種索引包含(亦稱覆蓋)所有需要查詢的字段的值,我們稱這種索引為覆蓋索引。
?
注:引入數(shù)據(jù)表t_user,插入約1千萬條記錄,用作下文例子使用。
?
?
1、工欲善其事,必先利其器
?
?explain命令是查看查詢優(yōu)化器如何決定執(zhí)行查詢的主要方法。要使用此命令,只需要在select關(guān)鍵字之前添加這個命令即可。當(dāng)執(zhí)行查詢時,它會返回信息,顯示出執(zhí)行計劃中的每一部分和執(zhí)行的次序,而并非真正執(zhí)行這個查詢。如下所示,是執(zhí)行explain的顯示結(jié)果,其中sql語句中的\G表示將輸出按列顯示:
?
?
當(dāng)發(fā)起一個被索引覆蓋的查詢時,在explain的Extra列可以看到 Using index的標(biāo)識。
?
?2、場景查詢表中name列有值的記錄數(shù)
?
(1)查詢表中name列有值的記錄數(shù)
?
?
?
查詢語句用SQL_NO_CACHE關(guān)鍵字來禁止緩存查詢結(jié)果。此查詢耗時6.43秒
?
(2)執(zhí)行計劃
?
?
?
從圖的執(zhí)行計劃得知,type:ALL,表示MySQL掃描整張表,從頭到尾去找到需要的行。下面對此查詢列建立索引。
?
?(3)為name列建立索引
?
?
(4)重新執(zhí)行的查詢sql
?
?
?
如圖所示,為name列建立索引之后,重新執(zhí)行查詢。此時查詢耗時3.80秒,比未加索引提高了2.63秒
?
(5)重新查看執(zhí)行計劃
?
?
?
從圖的查詢計劃可知,type:index,這個跟全表掃描一樣,只是MySQL掃描表時按索引次序進行而不是行。但是看到Extra:Using index,說明MySQL正在使用覆蓋索引,它只掃描索引的數(shù)據(jù),而不是按索引次序的每一行。它比按索引次序全表掃描的開銷少很多。
?
?3、分頁查詢email
?
?(1)分頁查詢email
?
?
?
從圖可知,分頁查詢耗時53.99
?
?(2)分頁查詢執(zhí)行計劃
?
?如圖所示,type:All,說明MySQL進行了全表掃描。下面在password和email列上創(chuàng)建聯(lián)合索引。
?
?
?
(3)添加聯(lián)合索引
?
?
?
(4)重新分頁查詢
?
?
?
如圖所示,分頁查詢基本不耗時間。
?
(5)重新執(zhí)行查詢計劃
?
?
?
從圖可知,Extra:Using index,MySQL使用了覆蓋索引進行查詢。查詢效率得到極大的提升。
?
?4、覆蓋索引總結(jié)
?
?回想一下,如果查詢只需要掃描索引而無須回表,將帶來諸多好處。
?
(1)索引條目通常遠小于數(shù)據(jù)行大小,如果只讀取索引,MySQL就會極大地減少數(shù)據(jù)訪問量。
?
(2)索引按照列值順序存儲,對于I/O密集的范圍查詢會比隨機從磁盤中讀取每一行數(shù)據(jù)的I/O要少很多。
?
(3)InnoDB的輔助索引(亦稱二級索引)在葉子節(jié)點中保存了行的主鍵值,如果二級索引能夠覆蓋查詢,則可不必對主鍵索引進行二次查詢了。
?
覆蓋索引就是從索引中直接獲取查詢結(jié)果,要使用覆蓋索引需要注意select查詢列中包含在索引列中;where條件包含索引列或者復(fù)合索引的前導(dǎo)列;查詢結(jié)果的字段長度盡可能少。
?
-  簡述數(shù)據(jù)庫讀寫分離?
?
什么是讀寫分離?
?
MySQL Proxy最強大的一項功能是實現(xiàn)“讀寫分離(Read/Write Splitting)”。基本的原理是讓主數(shù)據(jù)庫處理事務(wù)性查詢,而從數(shù)據(jù)庫處理SELECT查詢。數(shù)據(jù)庫復(fù)制被用來把事務(wù)性查詢導(dǎo)致的變更同步到集群中的從數(shù)據(jù)庫。 當(dāng)然,主服務(wù)器也可以提供查詢服務(wù)。使用讀寫分離最大的作用無非是環(huán)境服務(wù)器壓力。可以看下這張圖:
?
?
讀寫分離的好處
?
1、增加冗余
?
2、增加了機器的處理能力
?
3、對于讀操作為主的應(yīng)用,使用讀寫分離是最好的場景,因為可以確保寫的服務(wù)器壓力更小,而讀又可以接受點時間上的延遲。
?
讀寫分離提高性能之原因
?
1、物理服務(wù)器增加,負(fù)荷增加
2、主從只負(fù)責(zé)各自的寫和讀,極大程度的緩解X鎖和S鎖爭用
3、從庫可配置myisam引擎,提升查詢性能以及節(jié)約系統(tǒng)開銷
4、從庫同步主庫的數(shù)據(jù)和主庫直接寫還是有區(qū)別的,通過主庫發(fā)送來的binlog恢復(fù)數(shù)據(jù),但是,最重要區(qū)別在于主庫向從庫發(fā)送binlog是異步的,從庫恢復(fù)數(shù)據(jù)也是異步的
5、讀寫分離適用與讀遠大于寫的場景,如果只有一臺服務(wù)器,當(dāng)select很多時,update和delete會被這些select訪問中的數(shù)據(jù)堵塞,等待select結(jié)束,并發(fā)性能不高。 對于寫和讀比例相近的應(yīng)用,應(yīng)該部署雙主相互復(fù)制
?
6、可以在從庫啟動是增加一些參數(shù)來提高其讀的性能,例如--skip-innodb、--skip-bdb、--low-priority-updates以及--delay-key-write=ALL。當(dāng)然這些設(shè)置也是需要根據(jù)具體業(yè)務(wù)需求來定得,不一定能用上
?
7、分?jǐn)傋x取。假如我們有1主3從,不考慮上述1中提到的從庫單方面設(shè)置,假設(shè)現(xiàn)在1分鐘內(nèi)有10條寫入,150條讀取。那么,1主3從相當(dāng)于共計40條寫入,而讀取總數(shù)沒變,因此平均下來每臺服務(wù)器承擔(dān)了10條寫入和50條讀取(主庫不承擔(dān)讀取操作)。因此,雖然寫入沒變,但是讀取大大分?jǐn)偭?#xff0c;提高了系統(tǒng)性能。另外,當(dāng)讀取被分?jǐn)偤?#xff0c;又間接提高了寫入的性能。所以,總體性能提高了,說白了就是拿機器和帶寬換性能。MySQL官方文檔中有相關(guān)演算公式:官方文檔?見6.9FAQ之“MySQL復(fù)制能夠何時和多大程度提高系統(tǒng)性能”
?
8、MySQL復(fù)制另外一大功能是增加冗余,提高可用性,當(dāng)一臺數(shù)據(jù)庫服務(wù)器宕機后能通過調(diào)整另外一臺從庫來以最快的速度恢復(fù)服務(wù),因此不能光看性能,也就是說1主1從也是可以的。
?
讀寫分離示意圖
?
?
?
?
-  簡述數(shù)據(jù)庫分庫分表?(水平、垂直)
-  Redis是什么
- 是一個完全開源免費的key-value內(nèi)存數(shù)據(jù)庫
- 通常被認(rèn)為是一個數(shù)據(jù)結(jié)構(gòu)服務(wù)器,主要是因為其有著豐富的數(shù)據(jù)結(jié)構(gòu) strings、map、 list、sets、 sorted sets
redis和memcached比較?
?
1、Redis和Memcache都是將數(shù)據(jù)存放在內(nèi)存中,都是內(nèi)存數(shù)據(jù)庫。不過memcache還可用于緩存其他東西,例如圖片、視頻等等;
?
2、Redis不僅僅支持簡單的k/v類型的數(shù)據(jù),同時還提供list,set,hash等數(shù)據(jù)結(jié)構(gòu)的存儲;
?
3、虛擬內(nèi)存--Redis當(dāng)物理內(nèi)存用完時,可以將一些很久沒用到的value 交換到磁盤;
?
4、過期策略--memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire 設(shè)定,例如expire name 10;
?
5、分布式--設(shè)定memcache集群,利用magent做一主多從;redis可以做一主多從。都可以一主一從;
?
6、存儲數(shù)據(jù)安全--memcache掛掉后,數(shù)據(jù)沒了;redis可以定期保存到磁盤(持久化);
?
7、災(zāi)難恢復(fù)--memcache掛掉后,數(shù)據(jù)不可恢復(fù); redis數(shù)據(jù)丟失后可以通過aof恢復(fù);
?
8、Redis支持?jǐn)?shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份;
?
-  redis中數(shù)據(jù)庫默認(rèn)是多少個db 及作用?
?
redis下,數(shù)據(jù)庫是由一個整數(shù)索引標(biāo)識,而不是由一個數(shù)據(jù)庫名稱。默認(rèn)情況下,一個客戶端連接到數(shù)據(jù)庫0。redis配置文件中下面的參數(shù)來控制數(shù)據(jù)庫總數(shù):
?
?/etc/redis/redis.conf?
?
文件中,有個配置項 databases = 16 //默認(rèn)有16個數(shù)據(jù)庫
?
?
-  python操作redis的模塊?
?
什么是redis?
?
redis是一個key-value存儲系統(tǒng)。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數(shù)據(jù)類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎(chǔ)上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實現(xiàn)了master-slave(主從)同步。
?
上面的話好像很專業(yè)的樣子,這里我們簡單的理解為,其實redis就是一個消息中間件,可以作為多個進程的消息中轉(zhuǎn)站,是比之前我們用的manage模塊更方便自由的共享內(nèi)存。
?
1、基本操作
?
之前我們已經(jīng)知道,redis是以key-value的形式存儲的,所以我們在操作的時候。首先我們將redis所在主機的ip和發(fā)布端口作為參數(shù)實例化了一個對象r,然后執(zhí)行set('name','Eva_J'),這樣我們就在內(nèi)存中存儲了一個key為name,值為‘Eva_J’的項。我們可以理解為{'name':'Eva_J'},當(dāng)我們要讀取的之后,只需要get('name'),就會得到'Eva_J'的值。
?
?
2、連接池
?
?redis-py使用connection pool來管理對一個redis server的所有連接,避免每次建立、釋放連接的開銷。默認(rèn),每個Redis實例都會維護一個自己的連接池。可以直接建立一個連接池,然后作為參數(shù)Redis,這樣就可以實現(xiàn)多個Redis實例共享一個連接池。
?
?
?
3、管道
?
?redis-py默認(rèn)在執(zhí)行每次請求都會創(chuàng)建(連接池申請連接)和斷開(歸還連接池)一次連接操作,如果想要在一次請求中指定多個命令,則可以使用pipline實現(xiàn)一次請求指定多個命令,并且默認(rèn)情況下一次pipline 是原子性操作。?
?
4、發(fā)布訂閱
?
?
發(fā)布者:服務(wù)器
?
訂閱者:Dashboad和數(shù)據(jù)處理
?
Demo如下:
?
定義一個redishelper類,建立與redis連接,定義頻道為fm92.4,定義發(fā)布public及訂閱subscribe方法。
?
?
?
訂閱者:導(dǎo)入剛剛我們寫好的類,實例化對象,調(diào)用訂閱方法,就可以使用while True接收信息了。
?
?
發(fā)布者:導(dǎo)入剛剛我們寫好的類,實例化對象,調(diào)用發(fā)布方法,下例發(fā)布了一條消息‘hello’
?
?
?
-  如果redis中的某個列表中的數(shù)據(jù)量非常大,如果實現(xiàn)循環(huán)顯示每一個值?
-  redis如何實現(xiàn)主從復(fù)制?以及數(shù)據(jù)同步機制?
?
redis主從復(fù)制
?
和Mysql主從復(fù)制的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會產(chǎn)生讀壓力特別大的情況。為了分擔(dān)讀壓力,Redis支持主從復(fù)制,Redis的主從結(jié)構(gòu)可以采用一主多從或者級聯(lián)結(jié)構(gòu),Redis主從復(fù)制可以根據(jù)是否是全量分為全量同步和增量同步。下圖為級聯(lián)結(jié)構(gòu)。
?
?
全量同步
?
Redis全量復(fù)制一般發(fā)生在Slave初始化階段,這時Slave需要將Master上的所有數(shù)據(jù)都復(fù)制一份。具體步驟如下:?
-? 從服務(wù)器連接主服務(wù)器,發(fā)送SYNC命令;?
-? 主服務(wù)器接收到SYNC命名后,開始執(zhí)行BGSAVE命令生成RDB文件并使用緩沖區(qū)記錄此后執(zhí)行的所有寫命令;?
-? 主服務(wù)器BGSAVE執(zhí)行完后,向所有從服務(wù)器發(fā)送快照文件,并在發(fā)送期間繼續(xù)記錄被執(zhí)行的寫命令;?
-? 從服務(wù)器收到快照文件后丟棄所有舊數(shù)據(jù),載入收到的快照;?
-? 主服務(wù)器快照發(fā)送完畢后開始向從服務(wù)器發(fā)送緩沖區(qū)中的寫命令;?
-? 從服務(wù)器完成對快照的載入,開始接收命令請求,并執(zhí)行來自主服務(wù)器緩沖區(qū)的寫命令;
?
?
?
完成上面幾個步驟后就完成了從服務(wù)器數(shù)據(jù)初始化的所有操作,從服務(wù)器此時可以接收來自用戶的讀請求。
?
增量同步
?
Redis增量復(fù)制是指Slave初始化后開始正常工作時主服務(wù)器發(fā)生的寫操作同步到從服務(wù)器的過程。?
增量復(fù)制的過程主要是主服務(wù)器每執(zhí)行一個寫命令就會向從服務(wù)器發(fā)送相同的寫命令,從服務(wù)器接收并執(zhí)行收到的寫命令。
?
Redis主從同步策略
?
主從剛剛連接的時候,進行全量同步;全同步結(jié)束后,進行增量同步。當(dāng)然,如果有需要,slave 在任何時候都可以發(fā)起全量同步。redis 策略是,無論如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
?
關(guān)于其同步機制,請點擊這里
?
-  redis中的sentinel的作用?
?
Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當(dāng)用Redis做Master-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現(xiàn)自動進行主備切換,而Redis-sentinel本身也是一個獨立運行的進程,它能監(jiān)控多個master-slave集群,發(fā)現(xiàn)master宕機后能進行自動切換。
?
它的主要功能有以下幾點:
?
不時地監(jiān)控redis是否按照預(yù)期良好地運行;
?
如果發(fā)現(xiàn)某個redis節(jié)點運行出現(xiàn)狀況,能夠通知另外一個進程(例如它的客戶端);
?
能夠進行自動切換。當(dāng)一個master節(jié)點不可用時,能夠選舉出master的多個slave(如果有超過一個slave的話)中的一個來作為新的master,其它的slave節(jié)點會將它所追隨的master的地址改為被提升為master的slave的新地址。
?
Sentinel支持集群
?
很顯然,只使用單個sentinel進程來監(jiān)控redis集群是不可靠的,當(dāng)sentinel進程宕掉后(sentinel本身也有單點問題,single-point-of-failure)整個集群系統(tǒng)將無法按照預(yù)期的方式運行。所以有必要將sentinel集群,這樣有幾個好處:
?
-  即使有一些sentinel進程宕掉了,依然可以進行redis集群的主備切換; 
-  如果只有一個sentinel進程,如果這個進程運行出錯,或者是網(wǎng)絡(luò)堵塞,那么將無法實現(xiàn)redis集群的主備切換(單點問題); 
-  如果有多個sentinel,redis的客戶端可以隨意地連接任意一個sentinel來獲得關(guān)于redis集群中的信息。 
?
Sentinel版本
?
Sentinel當(dāng)前最新的穩(wěn)定版本稱為Sentinel 2(與之前的Sentinel 1區(qū)分開來)。隨著redis2.8的安裝包一起發(fā)行。安裝完Redis2.8后,可以在redis2.8/src/里面找到Redis-sentinel的啟動程序。
?
強烈建議:
如果你使用的是redis2.6(sentinel版本為sentinel 1),你最好應(yīng)該使用redis2.8版本的sentinel 2,因為sentinel 1有很多的Bug,已經(jīng)被官方棄用,所以強烈建議使用redis2.8以及sentinel 2。
?
運行Sentinel
?
運行sentinel有兩種方式:
?
第一種
?
  redis-sentinel /path/to/sentinel.conf
  第二種
?
  redis-server /path/to/sentinel.conf?--sentinel
以上兩種方式,都必須指定一個sentinel的配置文件sentinel.conf,如果不指定,將無法啟動sentinel。sentinel默認(rèn)監(jiān)聽26379端口,
?
所以運行前必須確定該端口沒有被別的進程占用。
?
Sentinel的配置
?
Redis源碼包中包含了一個sentinel.conf文件作為sentinel的配置文件,配置文件自帶了關(guān)于各個配置項的解釋。典型的配置項如下所示:
?
sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 60000 sentinel failover-timeout mymaster 180000 sentinel parallel-syncs mymaster 1sentinel monitor resque 192.168.1.3 6380 4 sentinel down-after-milliseconds resque 10000 sentinel failover-timeout resque 180000 sentinel parallel-syncs resque 5?
上面的配置項配置了兩個名字分別為mymaster和resque的master,配置文件只需要配置master的信息就好啦,不用配置slave的信息,因為slave能夠被自動檢測到(master節(jié)點會有關(guān)于slave的消息)。需要注意的是,配置文件在sentinel運行期間是會被動態(tài)修改的,例如當(dāng)發(fā)生主備切換時候,配置文件中的master會被修改為另外一個slave。這樣,之后sentinel如果重啟時,就可以根據(jù)這個配置來恢復(fù)其之前所監(jiān)控的redis集群的狀態(tài)。
?
sentinel monitor mymaster 127.0.0.1 6379 2?
這一行代表sentinel監(jiān)控的master的名字叫做mymaster,地址為127.0.0.1:6379,行尾最后的一個2代表什么意思呢?我們知道,網(wǎng)絡(luò)是不可靠的,有時候一個sentinel會因為網(wǎng)絡(luò)堵塞而誤以為一個master redis已經(jīng)死掉了,當(dāng)sentinel集群式,解決這個問題的方法就變得很簡單,只需要多個sentinel互相溝通來確認(rèn)某個master是否真的死了,這個2代表,當(dāng)集群中有2個sentinel認(rèn)為master死了時,才能真正認(rèn)為該master已經(jīng)不可用了。(sentinel集群中各個sentinel也有互相通信,通過gossip協(xié)議)。
?
除了第一行配置,我們發(fā)現(xiàn)剩下的配置都有一個統(tǒng)一的格式:
?
sentinel <option_name> <master_name> <option_value>?
接下來我們根據(jù)上面格式中的option_name一個一個來解釋這些配置項:
?
down-after-milliseconds
sentinel會向master發(fā)送心跳PING來確認(rèn)master是否存活,如果master在“一定時間范圍”內(nèi)不回應(yīng)PONG?或者是回復(fù)了一個錯誤消息,那么這個sentinel會主觀地(單方面地)認(rèn)為這個master已經(jīng)不可用了(subjectively down, 也簡稱為SDOWN)。而這個down-after-milliseconds就是用來指定這個“一定時間范圍”的,單位是毫秒。
?
不過需要注意的是,這個時候sentinel并不會馬上進行failover主備切換,這個sentinel還需要參考sentinel集群中其他sentinel的意見,如果超過某個數(shù)量的sentinel也主觀地認(rèn)為該master死了,那么這個master就會被客觀地(注意哦,這次不是主觀,是客觀,與剛才的subjectively down相對,這次是objectively down,簡稱為ODOWN)認(rèn)為已經(jīng)死了。需要一起做出決定的sentinel數(shù)量在上一條配置中進行配置。?
parallel-syncs
在發(fā)生failover主備切換時,這個選項指定了最多可以有多少個slave同時對新的master進行同步,這個數(shù)字越小,完成failover所需的時間就越長,但是如果這個數(shù)字越大,就意味著越多的slave因為replication而不可用。可以通過將這個值設(shè)為 1 來保證每次只有一個slave處于不能處理命令請求的狀態(tài)。
?
其他配置項在sentinel.conf中都有很詳細(xì)的解釋。
所有的配置都可以在運行時用命令SENTINEL SET command動態(tài)修改。
?
Sentinel的“仲裁會”
?
前面我們談到,當(dāng)一個master被sentinel集群監(jiān)控時,需要為它指定一個參數(shù),這個參數(shù)指定了當(dāng)需要判決master為不可用,并且進行failover時,所需要的sentinel數(shù)量,本文中我們暫時稱這個參數(shù)為票數(shù)
?
不過,當(dāng)failover主備切換真正被觸發(fā)后,failover并不會馬上進行,還需要sentinel中的大多數(shù)sentinel授權(quán)后才可以進行failover。
當(dāng)ODOWN時,failover被觸發(fā)。failover一旦被觸發(fā),嘗試去進行failover的sentinel會去獲得“大多數(shù)”sentinel的授權(quán)(如果票數(shù)比大多數(shù)還要大的時候,則詢問更多的sentinel)
這個區(qū)別看起來很微妙,但是很容易理解和使用。例如,集群中有5個sentinel,票數(shù)被設(shè)置為2,當(dāng)2個sentinel認(rèn)為一個master已經(jīng)不可用了以后,將會觸發(fā)failover,但是,進行failover的那個sentinel必須先獲得至少3個sentinel的授權(quán)才可以實行failover。
如果票數(shù)被設(shè)置為5,要達到ODOWN狀態(tài),必須所有5個sentinel都主觀認(rèn)為master為不可用,要進行failover,那么得獲得所有5個sentinel的授權(quán)。
?
配置版本號
?
為什么要先獲得大多數(shù)sentinel的認(rèn)可時才能真正去執(zhí)行failover呢?
?
當(dāng)一個sentinel被授權(quán)后,它將會獲得宕掉的master的一份最新配置版本號,當(dāng)failover執(zhí)行結(jié)束以后,這個版本號將會被用于最新的配置。因為大多數(shù)sentinel都已經(jīng)知道該版本號已經(jīng)被要執(zhí)行failover的sentinel拿走了,所以其他的sentinel都不能再去使用這個版本號。這意味著,每次failover都會附帶有一個獨一無二的版本號。我們將會看到這樣做的重要性。
?
而且,sentinel集群都遵守一個規(guī)則:如果sentinel A推薦sentinel B去執(zhí)行failover,B會等待一段時間后,自行再次去對同一個master執(zhí)行failover,這個等待的時間是通過failover-timeout配置項去配置的。從這個規(guī)則可以看出,sentinel集群中的sentinel不會再同一時刻并發(fā)去failover同一個master,第一個進行failover的sentinel如果失敗了,另外一個將會在一定時間內(nèi)進行重新進行failover,以此類推。
?
redis sentinel保證了活躍性:如果大多數(shù)sentinel能夠互相通信,最終將會有一個被授權(quán)去進行failover.
redis sentinel也保證了安全性:每個試圖去failover同一個master的sentinel都會得到一個獨一無二的版本號。
?
配置傳播
?
一旦一個sentinel成功地對一個master進行了failover,它將會把關(guān)于master的最新配置通過廣播形式通知其它sentinel,其它的sentinel則更新對應(yīng)master的配置。
?
一個faiover要想被成功實行,sentinel必須能夠向選為master的slave發(fā)送SLAVEOF NO ONE命令,然后能夠通過INFO命令看到新master的配置信息。
?
當(dāng)將一個slave選舉為master并發(fā)送SLAVEOF NO ONE后,即使其它的slave還沒針對新master重新配置自己,failover也被認(rèn)為是成功了的,然后所有sentinels將會發(fā)布新的配置信息。
?
新配在集群中相互傳播的方式,就是為什么我們需要當(dāng)一個sentinel進行failover時必須被授權(quán)一個版本號的原因。
?
每個sentinel使用##發(fā)布/訂閱##的方式持續(xù)地傳播master的配置版本信息,配置傳播的##發(fā)布/訂閱##管道是:__sentinel__:hello。
?
因為每一個配置都有一個版本號,所以以版本號最大的那個為標(biāo)準(zhǔn)。
?
舉個栗子:假設(shè)有一個名為mymaster的地址為192.168.1.50:6379。一開始,集群中所有的sentinel都知道這個地址,于是為mymaster的配置打上版本號1。一段時候后mymaster死了,有一個sentinel被授權(quán)用版本號2對其進行failover。如果failover成功了,假設(shè)地址改為了192.168.1.50:9000,此時配置的版本號為2,進行failover的sentinel會將新配置廣播給其他的sentinel,由于其他sentinel維護的版本號為1,發(fā)現(xiàn)新配置的版本號為2時,版本號變大了,說明配置更新了,于是就會采用最新的版本號為2的配置。
?
這意味著sentinel集群保證了第二種活躍性:一個能夠互相通信的sentinel集群最終會采用版本號最高且相同的配置。
?
SDOWN和ODOWN的更多細(xì)節(jié)
?
sentinel對于不可用有兩種不同的看法,一個叫主觀不可用(SDOWN),另外一個叫客觀不可用(ODOWN)。SDOWN是sentinel自己主觀上檢測到的關(guān)于master的狀態(tài),ODOWN需要一定數(shù)量的sentinel達成一致意見才能認(rèn)為一個master客觀上已經(jīng)宕掉,各個sentinel之間通過命令SENTINEL is_master_down_by_addr來獲得其它sentinel對master的檢測結(jié)果。
?
從sentinel的角度來看,如果發(fā)送了PING心跳后,在一定時間內(nèi)沒有收到合法的回復(fù),就達到了SDOWN的條件。這個時間在配置中通過is-master-down-after-milliseconds參數(shù)配置。
?
當(dāng)sentinel發(fā)送PING后,以下回復(fù)之一都被認(rèn)為是合法的:
?
PING replied with +PONG.
PING replied with -LOADING error.
PING replied with -MASTERDOWN error.
其它任何回復(fù)(或者根本沒有回復(fù))都是不合法的。
?
從SDOWN切換到ODOWN不需要任何一致性算法,只需要一個gossip協(xié)議:如果一個sentinel收到了足夠多的sentinel發(fā)來消息告訴它某個master已經(jīng)down掉了,SDOWN狀態(tài)就會變成ODOWN狀態(tài)。如果之后master可用了,這個狀態(tài)就會相應(yīng)地被清理掉。
?
正如之前已經(jīng)解釋過了,真正進行failover需要一個授權(quán)的過程,但是所有的failover都開始于一個ODOWN狀態(tài)。
?
ODOWN狀態(tài)只適用于master,對于不是master的redis節(jié)點sentinel之間不需要任何協(xié)商,slaves和sentinel不會有ODOWN狀態(tài)。
?
Sentinel之間和Slaves之間的自動發(fā)現(xiàn)機制
?
雖然sentinel集群中各個sentinel都互相連接彼此來檢查對方的可用性以及互相發(fā)送消息。但是你不用在任何一個sentinel配置任何其它的sentinel的節(jié)點。因為sentinel利用了master的發(fā)布/訂閱機制去自動發(fā)現(xiàn)其它也監(jiān)控了統(tǒng)一master的sentinel節(jié)點。
?
通過向名為__sentinel__:hello的管道中發(fā)送消息來實現(xiàn)。
?
同樣,你也不需要在sentinel中配置某個master的所有slave的地址,sentinel會通過詢問master來得到這些slave的地址的。
?
每個sentinel通過向每個master和slave的發(fā)布/訂閱頻道__sentinel__:hello每秒發(fā)送一次消息,來宣布它的存在。
每個sentinel也訂閱了每個master和slave的頻道__sentinel__:hello的內(nèi)容,來發(fā)現(xiàn)未知的sentinel,當(dāng)檢測到了新的sentinel,則將其加入到自身維護的master監(jiān)控列表中。
每個sentinel發(fā)送的消息中也包含了其當(dāng)前維護的最新的master配置。如果某個sentinel發(fā)現(xiàn)
自己的配置版本低于接收到的配置版本,則會用新的配置更新自己的master配置。
?
在為一個master添加一個新的sentinel前,sentinel總是檢查是否已經(jīng)有sentinel與新的sentinel的進程號或者是地址是一樣的。如果是那樣,這個sentinel將會被刪除,而把新的sentinel添加上去。
?
網(wǎng)絡(luò)隔離時的一致性
?
redis sentinel集群的配置的一致性模型為最終一致性,集群中每個sentinel最終都會采用最高版本的配置。然而,在實際的應(yīng)用環(huán)境中,有三個不同的角色會與sentinel打交道:
?
-  Redis實例. 
-  Sentinel實例. 
-  客戶端. 
?
為了考察整個系統(tǒng)的行為我們必須同時考慮到這三個角色。
?
下面有個簡單的例子,有三個主機,每個主機分別運行一個redis和一個sentinel:
?
+-------------+| Sentinel 1 | <--- Client A | Redis 1 (M) | +-------------+ | | +-------------+ | +------------+ | Sentinel 2 |-----+-- / partition / ----| Sentinel 3 | <--- Client B | Redis 2 (S) | | Redis 3 (M)| +-------------+ +------------+?
在這個系統(tǒng)中,初始狀態(tài)下redis3是master, redis1和redis2是slave。之后redis3所在的主機網(wǎng)絡(luò)不可用了,sentinel1和sentinel2啟動了failover并把redis1選舉為master。
?
Sentinel集群的特性保證了sentinel1和sentinel2得到了關(guān)于master的最新配置。但是sentinel3依然持著的是就的配置,因為它與外界隔離了。
?
當(dāng)網(wǎng)絡(luò)恢復(fù)以后,我們知道sentinel3將會更新它的配置。但是,如果客戶端所連接的master被網(wǎng)絡(luò)隔離,會發(fā)生什么呢?
?
客戶端將依然可以向redis3寫數(shù)據(jù),但是當(dāng)網(wǎng)絡(luò)恢復(fù)后,redis3就會變成redis的一個slave,那么,在網(wǎng)絡(luò)隔離期間,客戶端向redis3寫的數(shù)據(jù)將會丟失。
?
也許你不會希望這個場景發(fā)生:
?
-  如果你把redis當(dāng)做緩存來使用,那么你也許能容忍這部分?jǐn)?shù)據(jù)的丟失。 
-  但如果你把redis當(dāng)做一個存儲系統(tǒng)來使用,你也許就無法容忍這部分?jǐn)?shù)據(jù)的丟失了。 
?
因為redis采用的是異步復(fù)制,在這樣的場景下,沒有辦法避免數(shù)據(jù)的丟失。然而,你可以通過以下配置來配置redis3和redis1,使得數(shù)據(jù)不會丟失。
?
min-slaves-to-write 1 min-slaves-max-lag 10?
通過上面的配置,當(dāng)一個redis是master時,如果它不能向至少一個slave寫數(shù)據(jù)(上面的min-slaves-to-write指定了slave的數(shù)量),它將會拒絕接受客戶端的寫請求。由于復(fù)制是異步的,master無法向slave寫數(shù)據(jù)意味著slave要么斷開連接了,要么不在指定時間內(nèi)向master發(fā)送同步數(shù)據(jù)的請求了(上面的min-slaves-max-lag指定了這個時間)。
?
Sentinel狀態(tài)持久化
?
snetinel的狀態(tài)會被持久化地寫入sentinel的配置文件中。每次當(dāng)收到一個新的配置時,或者新創(chuàng)建一個配置時,配置會被持久化到硬盤中,并帶上配置的版本戳。這意味著,可以安全的停止和重啟sentinel進程。
?
無failover時的配置糾正
?
即使當(dāng)前沒有failover正在進行,sentinel依然會使用當(dāng)前配置去設(shè)置監(jiān)控的master。特別是:
?
-  根據(jù)最新配置確認(rèn)為slaves的節(jié)點卻聲稱自己是master(上文例子中被網(wǎng)絡(luò)隔離后的的redis3),這時它們會被重新配置為當(dāng)前master的slave。 
-  如果slaves連接了一個錯誤的master,將會被改正過來,連接到正確的master。 
?
Slave選舉與優(yōu)先級
?
當(dāng)一個sentinel準(zhǔn)備好了要進行failover,并且收到了其他sentinel的授權(quán),那么就需要選舉出一個合適的slave來做為新的master。
?
slave的選舉主要會評估slave的以下幾個方面:
?
-  與master斷開連接的次數(shù) 
-  Slave的優(yōu)先級 
-  數(shù)據(jù)復(fù)制的下標(biāo)(用來評估slave當(dāng)前擁有多少master的數(shù)據(jù)) 
-  進程ID 
?
如果一個slave與master失去聯(lián)系超過10次,并且每次都超過了配置的最大失聯(lián)時間(down-after-milliseconds),如果sentinel在進行failover時發(fā)現(xiàn)slave失聯(lián),那么這個slave就會被sentinel認(rèn)為不適合用來做新master的。
?
更嚴(yán)格的定義是,如果一個slave持續(xù)斷開連接的時間超過
?
(down-after-milliseconds *?10) + milliseconds_since_master_is_in_SDOWN_state?
就會被認(rèn)為失去選舉資格。
符合上述條件的slave才會被列入master候選人列表,并根據(jù)以下順序來進行排序:
?
sentinel首先會根據(jù)slaves的優(yōu)先級來進行排序,優(yōu)先級越小排名越靠前。
如果優(yōu)先級相同,則查看復(fù)制的下標(biāo),哪個從master接收的復(fù)制數(shù)據(jù)多,哪個就靠前。
如果優(yōu)先級和下標(biāo)都相同,就選擇進程ID較小的那個。
?
一個redis無論是master還是slave,都必須在配置中指定一個slave優(yōu)先級。要注意到master也是有可能通過failover變成slave的。
?
如果一個redis的slave優(yōu)先級配置為0,那么它將永遠不會被選為master。但是它依然會從master哪里復(fù)制數(shù)據(jù)。
?
Sentinel和Redis身份驗證
?
當(dāng)一個master配置為需要密碼才能連接時,客戶端和slave在連接時都需要提供密碼。
?
master通過requirepass設(shè)置自身的密碼,不提供密碼無法連接到這個master。
slave通過masterauth來設(shè)置訪問master時的密碼。
?
但是當(dāng)使用了sentinel時,由于一個master可能會變成一個slave,一個slave也可能會變成master,所以需要同時設(shè)置上述兩個配置項。
?
詳細(xì)信息,請點擊這里
?
-  如何實現(xiàn)redis集群?
?
由于Redis出眾的性能,其在眾多的移動互聯(lián)網(wǎng)企業(yè)中得到廣泛的應(yīng)用。Redis在3.0版本前只支持單實例模式,雖然現(xiàn)在的服務(wù)器內(nèi)存可以到100GB、200GB的規(guī)模,但是單實例模式限制了Redis沒法滿足業(yè)務(wù)的需求(例如新浪微博就曾經(jīng)用Redis存儲了超過1TB的數(shù)據(jù))。Redis的開發(fā)者Antirez早在博客上就提出在Redis 3.0版本中加入集群的功能,但3.0版本等到2015年才發(fā)布正式版。各大企業(yè)在3.0版本還沒發(fā)布前為了解決Redis的存儲瓶頸,紛紛推出了各自的Redis集群方案。這些方案的核心思想是把數(shù)據(jù)分片(sharding)存儲在多個Redis實例中,每一片就是一個Redis實例。
?
下面介紹Redis的集群方案。
?
1、客戶端分片
?
客戶端分片是把分片的邏輯放在Redis客戶端實現(xiàn),通過Redis客戶端預(yù)先定義好的路由規(guī)則,把對Key的訪問轉(zhuǎn)發(fā)到不同的Redis實例中,最后把返回結(jié)果匯集。這種方案的模式如下圖所示。
?
?
客戶端分片的好處是所有的邏輯都是可控的,不依賴于第三方分布式中間件。開發(fā)人員清楚怎么實現(xiàn)分片、路由的規(guī)則,不用擔(dān)心踩坑。
?
客戶端分片方案有下面這些缺點:
?
●這是一種靜態(tài)的分片方案,需要增加或者減少Redis實例的數(shù)量,需要手工調(diào)整分片的程序。
?
●可運維性差,集群的數(shù)據(jù)出了任何問題都需要運維人員和開發(fā)人員一起合作,減緩了解決問題的速度,增加了跨部門溝通的成本。
?
●在不同的客戶端程序中,維護相同的分片邏輯成本巨大。例如,系統(tǒng)中有兩套業(yè)務(wù)系統(tǒng)共用一套Redis集群,一套業(yè)務(wù)系統(tǒng)用Java實現(xiàn),另一套業(yè)務(wù)系統(tǒng)用PHP實現(xiàn)。為了保證分片邏輯的一致性,在Java客戶端中實現(xiàn)的分片邏輯也需要在PHP客戶端實現(xiàn)一次。相同的邏輯在不同的系統(tǒng)中分別實現(xiàn),這種設(shè)計本來就非常糟糕,而且需要耗費巨大的開發(fā)成本保證兩套業(yè)務(wù)系統(tǒng)分片邏輯的一致性。
?
2、Twemproxy
?
Twemproxy是由Twitter開源的Redis代理,其基本原理是:Redis客戶端把請求發(fā)送到Twemproxy,Twemproxy根據(jù)路由規(guī)則發(fā)送到正確的Redis實例,最后Twemproxy把結(jié)果匯集返回給客戶端。
?
Twemproxy通過引入一個代理層,將多個Redis實例進行統(tǒng)一管理,使Redis客戶端只需要在Twemproxy上進行操作,而不需要關(guān)心后面有多少個Redis實例,從而實現(xiàn)了Redis集群。
?
?Twemproxy集群架構(gòu)如下圖所示:
?
?
Twemproxy的優(yōu)點如下:
?
●客戶端像連接Redis實例一樣連接Twemproxy,不需要改任何的代碼邏輯。
?
●支持無效Redis實例的自動刪除。
?
●Twemproxy與Redis實例保持連接,減少了客戶端與Redis實例的連接數(shù)。
?
Twemproxy的缺點如下:
?
●由于Redis客戶端的每個請求都經(jīng)過Twemproxy代理才能到達Redis服務(wù)器,這個過程中會產(chǎn)生性能損失。
?
●沒有友好的監(jiān)控管理后臺界面,不利于運維監(jiān)控。
?
●最大的問題是Twemproxy無法平滑地增加Redis實例。對于運維人員來說,當(dāng)因為業(yè)務(wù)需要增加Redis實例時工作量非常大。
?
Twemproxy作為最被廣泛使用、最久經(jīng)考驗、穩(wěn)定性最高的Redis代理,在業(yè)界被廣泛使用。
?
?3、Redis 3.0集群
?
Redis 3.0集群采用了P2P的模式,完全去中心化。Redis把所有的Key分成了16384個slot,每個Redis實例負(fù)責(zé)其中一部分slot。集群中的所有信息(節(jié)點、端口、slot等),都通過節(jié)點之間定期的數(shù)據(jù)交換而更新。
?
Redis客戶端在任意一個Redis實例發(fā)出請求,如果所需數(shù)據(jù)不在該實例中,通過重定向命令引導(dǎo)客戶端訪問所需的實例。
?
Redis 3.0集群的工作流程如下圖所示:
?
?
如圖所示Redis集群內(nèi)的機器定期交換數(shù)據(jù),工作流程如下:
?
(1) Redis客戶端在Redis2實例上訪問某個數(shù)據(jù)。
?
(2) 在Redis2內(nèi)發(fā)現(xiàn)這個數(shù)據(jù)是在Redis3這個實例中,給Redis客戶端發(fā)送一個重定向的命令。
?
(3) Redis客戶端收到重定向命令后,訪問Redis3實例獲取所需的數(shù)據(jù)。
?
Redis 3.0的集群方案有以下兩個問題:
?
●一個Redis實例具備了“數(shù)據(jù)存儲”和“路由重定向”,完全去中心化的設(shè)計。這帶來的好處是部署非常簡單,直接部署Redis就行,不像Codis有那么多的組件和依賴。但帶來的問題是很難對業(yè)務(wù)進行無痛的升級,如果哪天Redis集群出了什么嚴(yán)重的Bug,就只能回滾整個Redis集群。
?
●對協(xié)議進行了較大的修改,對應(yīng)的Redis客戶端也需要升級。升級Redis客戶端后誰能確保沒有Bug?而且對于線上已經(jīng)大規(guī)模運行的業(yè)務(wù),升級代碼中的Redis客戶端也是一個很麻煩的事情。
?
綜合上面所述的兩個問題,Redis 3.0集群在業(yè)界并沒有被大規(guī)模使用。
?
4、云服務(wù)器上的集群服務(wù)
?
國內(nèi)的云服務(wù)器提供商阿里云、UCloud等均推出了基于Redis的云存儲服務(wù)。
?
這個服務(wù)的特性如下。
?
(1)動態(tài)擴容
?
用戶可以通過控制面板升級所需的Redis存儲空間,擴容的過程中服務(wù)部不需要中斷或停止,整個擴容過程對用戶透明、無感知,這點是非常實用的,在前面介紹的方案中,解決Redis平滑擴容是個很煩瑣的任務(wù),現(xiàn)在按幾下鼠標(biāo)就能搞定,大大減少了運維的負(fù)擔(dān)。
?
(2)數(shù)據(jù)多備
?
數(shù)據(jù)保存在一主一備兩臺機器中,其中一臺機器宕機了,數(shù)據(jù)還在另外一臺機器上有備份。
?
(3)自動容災(zāi)
?
主機宕機后系統(tǒng)能自動檢測并切換到備機上,實現(xiàn)服務(wù)的高可用。
?
(4)實惠
?
很多情況下為了使Redis的性能更高,需要購買一臺專門的服務(wù)器用于Redis的存儲服務(wù),但這樣子CPU、內(nèi)存等資源就浪費了,購買Redis云存儲服務(wù)就很好地解決了這個問題。
?
有了Redis云存儲服務(wù),能使App后臺開發(fā)人員從煩瑣運維中解放出來。App后臺要搭建一個高可用、高性能的Redis服務(wù),需要投入相當(dāng)?shù)倪\維成本和精力。如果使用云存儲服務(wù),就沒必要投入這些成本和精力,可以讓App后臺開發(fā)人員更專注于業(yè)務(wù)。
?
-  redis中默認(rèn)有多少個哈希槽?
?
Redis 集群中內(nèi)置了?16384?個哈希槽,當(dāng)需要在 Redis 集群中放置一個 key-value時,redis 先對 key 使用 crc16 算法算出一個結(jié)果,然后把結(jié)果對 16384 求余數(shù),這樣每個 key 都會對應(yīng)一個編號在 0-16383 之間的哈希槽,redis 會根據(jù)節(jié)點數(shù)量大致均等的將哈希槽映射到不同的節(jié)點。
?
Redis 集群沒有使用一致性hash, 而是引入了哈希槽的概念。
?
Redis 集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽.集群的每個節(jié)點負(fù)責(zé)一部分hash槽。這種結(jié)構(gòu)很容易添加或者刪除節(jié)點,并且無論是添加刪除或者修改某一個節(jié)點,都不會造成集群不可用的狀態(tài)。
?
使用哈希槽的好處就在于可以方便的添加或移除節(jié)點。
?
當(dāng)需要增加節(jié)點時,只需要把其他節(jié)點的某些哈希槽挪到新節(jié)點就可以了;
?
當(dāng)需要移除節(jié)點時,只需要把移除節(jié)點上的哈希槽挪到其他節(jié)點就行了;
?
在這一點上,我們以后新增或移除節(jié)點的時候不用先停掉所有的 redis 服務(wù)。
?
?
?
"用了哈希槽的概念,而沒有用一致性哈希算法,不都是哈希么?這樣做的原因是為什么呢?"
Redis Cluster是自己做的crc16的簡單hash算法,沒有用一致性hash。Redis的作者認(rèn)為它的crc16(key) mod 16384的效果已經(jīng)不錯了,雖然沒有一致性hash靈活,但實現(xiàn)很簡單,節(jié)點增刪時處理起來也很方便。
?
"為了動態(tài)增刪節(jié)點的時候,不至于丟失數(shù)據(jù)么?"
節(jié)點增刪時不丟失數(shù)據(jù)和hash算法沒什么關(guān)系,不丟失數(shù)據(jù)要求的是一份數(shù)據(jù)有多個副本。
?
“還有集群總共有2的14次方,16384個哈希槽,那么每一個哈希槽中存的key 和 value是什么?”
當(dāng)你往Redis Cluster中加入一個Key時,會根據(jù)crc16(key) mod 16384計算這個key應(yīng)該分布到哪個hash slot中,一個hash slot中會有很多key和value。你可以理解成表的分區(qū),使用單節(jié)點時的redis時只有一個表,所有的key都放在這個表里;改用Redis Cluster以后會自動為你生成16384個分區(qū)表,你insert數(shù)據(jù)時會根據(jù)上面的簡單算法來決定你的key應(yīng)該存在哪個分區(qū),每個分區(qū)里有很多key。
?
-  簡述redis的有哪幾種持久化策略及比較?
?
Redis 提供了多種不同級別的持久化方式:
?
RDB 持久化可以在指定的時間間隔內(nèi)生成數(shù)據(jù)集的時間點快照(point-in-time snapshot)。
?
AOF 持久化記錄服務(wù)器執(zhí)行的所有寫操作命令,并在服務(wù)器啟動時,通過重新執(zhí)行這些命令來還原數(shù)據(jù)集。 AOF 文件中的命令全部以 Redis 協(xié)議的格式來保存,新命令會被追加到文件的末尾。 Redis 還可以在后臺對 AOF 文件進行重寫(rewrite),使得 AOF 文件的體積不會超出保存數(shù)據(jù)集狀態(tài)所需的實際大小。
?
Redis 還可以同時使用 AOF 持久化和 RDB 持久化。 在這種情況下, 當(dāng) Redis 重啟時, 它會優(yōu)先使用 AOF 文件來還原數(shù)據(jù)集, 因為 AOF 文件保存的數(shù)據(jù)集通常比 RDB 文件所保存的數(shù)據(jù)集更完整。
?
你甚至可以關(guān)閉持久化功能,讓數(shù)據(jù)只在服務(wù)器運行時存在。
?
RDB知識點
?
RDB 的優(yōu)點
?
RDB 是一個非常緊湊(compact)的文件,它保存了 Redis 在某個時間點上的數(shù)據(jù)集。 這種文件非常適合用于進行備份: 比如說,你可以在最近的 24 小時內(nèi),每小時備份一次 RDB 文件,并且在每個月的每一天,也備份一個 RDB 文件。 這樣的話,即使遇上問題,也可以隨時將數(shù)據(jù)集還原到不同的版本。
?
RDB 非常適用于災(zāi)難恢復(fù)(disaster recovery):它只有一個文件,并且內(nèi)容都非常緊湊,可以(在加密后)將它傳送到別的數(shù)據(jù)中心,或者亞馬遜 S3 中。
?
RDB 可以最大化 Redis 的性能:父進程在保存 RDB 文件時唯一要做的就是 fork 出一個子進程,然后這個子進程就會處理接下來的所有保存工作,父進程無須執(zhí)行任何磁盤 I/O 操作。
?
RDB 在恢復(fù)大數(shù)據(jù)集時的速度比 AOF 的恢復(fù)速度要快。
?
RDB 的缺點
?
如果你需要盡量避免在服務(wù)器故障時丟失數(shù)據(jù),那么 RDB 不適合你。 雖然 Redis 允許你設(shè)置不同的保存點(save point)來控制保存 RDB 文件的頻率, 但是, 因為RDB 文件需要保存整個數(shù)據(jù)集的狀態(tài), 所以它并不是一個輕松的操作。 因此你可能會至少 5 分鐘才保存一次 RDB 文件。 在這種情況下, 一旦發(fā)生故障停機, 你就可能會丟失好幾分鐘的數(shù)據(jù)。
?
每次保存 RDB 的時候,Redis 都要 fork() 出一個子進程,并由子進程來進行實際的持久化工作。 在數(shù)據(jù)集比較龐大時, fork() 可能會非常耗時,造成服務(wù)器在某某毫秒內(nèi)停止處理客戶端; 如果數(shù)據(jù)集非常巨大,并且 CPU 時間非常緊張的話,那么這種停止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也需要進行 fork() ,但無論 AOF 重寫的執(zhí)行間隔有多長,數(shù)據(jù)的耐久性都不會有任何損失。
?
AOF知識點
?
AOF 的優(yōu)點
?
使用 AOF 持久化會讓 Redis 變得非常耐久(much more durable):你可以設(shè)置不同的 fsync 策略,比如無 fsync ,每秒鐘一次 fsync ,或者每次執(zhí)行寫入命令時 fsync 。 AOF 的默認(rèn)策略為每秒鐘 fsync 一次,在這種配置下,Redis 仍然可以保持良好的性能,并且就算發(fā)生故障停機,也最多只會丟失一秒鐘的數(shù)據(jù)( fsync 會在后臺線程執(zhí)行,所以主線程可以繼續(xù)努力地處理命令請求)。
?
AOF 文件是一個只進行追加操作的日志文件(append only log), 因此對 AOF 文件的寫入不需要進行 seek , 即使日志因為某些原因而包含了未寫入完整的命令(比如寫入時磁盤已滿,寫入中途停機,等等), redis-check-aof 工具也可以輕易地修復(fù)這種問題。
?
Redis 可以在 AOF 文件體積變得過大時,自動地在后臺對 AOF 進行重寫: 重寫后的新 AOF 文件包含了恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合。 整個重寫操作是絕對安全的,因為 Redis 在創(chuàng)建新 AOF 文件的過程中,會繼續(xù)將命令追加到現(xiàn)有的 AOF 文件里面,即使重寫過程中發(fā)生停機,現(xiàn)有的 AOF 文件也不會丟失。 而一旦新 AOF 文件創(chuàng)建完畢,Redis 就會從舊 AOF 文件切換到新 AOF 文件,并開始對新 AOF 文件進行追加操作。
?
AOF 文件有序地保存了對數(shù)據(jù)庫執(zhí)行的所有寫入操作, 這些寫入操作以 Redis 協(xié)議的格式保存, 因此 AOF 文件的內(nèi)容非常容易被人讀懂, 對文件進行分析(parse)也很輕松。 導(dǎo)出(export) AOF 文件也非常簡單: 舉個例子, 如果你不小心執(zhí)行了 FLUSHALL 命令, 但只要 AOF 文件未被重寫, 那么只要停止服務(wù)器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重啟 Redis , 就可以將數(shù)據(jù)集恢復(fù)到 FLUSHALL 執(zhí)行之前的狀態(tài)。
?
AOF 的缺點
?
對于相同的數(shù)據(jù)集來說,AOF 文件的體積通常要大于 RDB 文件的體積。
?
根據(jù)所使用的 fsync 策略,AOF 的速度可能會慢于 RDB 。 在一般情況下, 每秒 fsync 的性能依然非常高, 而關(guān)閉 fsync 可以讓 AOF 的速度和 RDB 一樣快, 即使在高負(fù)荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 可以提供更有保證的最大延遲時間(latency)。
?
AOF 在過去曾經(jīng)發(fā)生過這樣的 bug : 因為個別命令的原因,導(dǎo)致 AOF 文件在重新載入時,無法將數(shù)據(jù)集恢復(fù)成保存時的原樣。 (舉個例子,阻塞命令 BRPOPLPUSH 就曾經(jīng)引起過這樣的 bug 。) 測試套件里為這種情況添加了測試: 它們會自動生成隨機的、復(fù)雜的數(shù)據(jù)集, 并通過重新載入這些數(shù)據(jù)來確保一切正常。 雖然這種 bug 在 AOF 文件中并不常見, 但是對比來說, RDB 幾乎是不可能出現(xiàn)這種 bug 的。
?
-  列舉redis支持的過期策略。
-  MySQL 里有 2000w 數(shù)據(jù),redis 中只存 20w 的數(shù)據(jù),如何保證 redis 中都是熱點數(shù)據(jù)??
-  寫代碼,基于redis的列表實現(xiàn) 先進先出、后進先出隊列、優(yōu)先級隊列。
-  如何基于redis實現(xiàn)消息隊列?
-  如何基于redis實現(xiàn)發(fā)布和訂閱?以及發(fā)布訂閱和消息隊列的區(qū)別?
-  什么是codis及作用?
-  什么是twemproxy及作用?
-  寫代碼實現(xiàn)redis事務(wù)操作。
-  redis中的watch的命令的作用?
-  基于redis如何實現(xiàn)商城商品數(shù)量計數(shù)器?
-  簡述redis分布式鎖和redlock的實現(xiàn)機制。
-  什么是一致性哈希?Python中是否有相應(yīng)模塊?
-  如何高效的找到redis中所有以oldboy開頭的key?
?
轉(zhuǎn)載于:https://www.cnblogs.com/lmx123/p/9219491.html
總結(jié)
以上是生活随笔為你收集整理的python面试题库——3数据库和缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Linux 基础学习大考核
- 下一篇: 7月14号day6总结
