使用t-sql语句修改表中的某些数据及数据类型。_Java面试——数据库知识点
微信公眾號:猿的夜場
關注可了解更多的技術文檔。問題或建議,請公眾號留言!
MySQL
1、建
主鍵:數據庫表中對儲存數據對象予以唯一和完整標識的數據列或屬性的組合。一個數據列只能有一個主鍵,且主鍵的取值不能缺失,即不能為空值(Null)。
超鍵:在關系中能唯一標識元組的屬性集稱為關系模式的超鍵。一個屬性可以為作為一個超鍵,多個屬性組合在一起也可以作為一個超鍵。超鍵包含候選鍵和主鍵。
候選鍵:是最小超鍵,即沒有冗余元素的超鍵。
外鍵:在一個表中存在的另一個表的主鍵稱此表的外鍵。
2、事務的四個特性
數據庫事務transanction正確執行的四個基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔離性(Isolation)、持久性(Durability)。
原子性:整個事務中的所有操作,要么全部完成,要么全部不完成,不可能停滯在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性:在事務開始之前和事務結束以后,數據庫的完整性約束沒有被破壞。
隔離性:隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,運行在相同的時間內,執行 相同的功能,事務的隔離性將確保每一事務在系統中認為只有該事務在使用系統。這種屬性有時稱為串行化,為了防止事務操作間的混淆,必須串行化或序列化請 求,使得在同一時間僅有一個請求用于同一數據。
持久性:在事務完成以后,該事務所對數據庫所作的更改便持久的保存在數據庫之中,并不會被回滾。
3、視圖的作用
視圖是虛擬的表,與包含數據的表不一樣,視圖只包含使用時動態檢索數據的查詢;不包含任何列或數據。使用視圖可以簡化復雜的sql操作,隱藏具體的細節,保護數據;視圖創建后,可以使用與表相同的方式利用它們。
視圖不能被索引,也不能有關聯的觸發器或默認值,如果視圖本身內有order by 則對視圖再次order by將被覆蓋。
創建視圖:
create?view?XXX?as?XXX;對于某些視圖比如未使用聯結子查詢分組聚集函數Distinct Union等,是可以對其更新的,對視圖的更新將對基表進行更新;但是視圖主要用于簡化檢索,保護數據,并不用于更新,而且大部分視圖都不可以更新。
drop、delete與truncate的區別
drop直接刪掉表 truncate刪除表中數據,再插入時自增長id又從1開始 delete刪除表中數據,可以加where字句。
DELETE語句執行刪除的過程是每次從表中刪除一行,并且同時將該行的刪除操作作為事務記錄在日志中保存以便進行進行回滾操作。TRUNCATE TABLE 則一次性地從表中刪除所有的數據并不把單獨的刪除操作記錄記入日志保存,刪除行是不能恢復的。并且在刪除的過程中不會激活與表有關的刪除觸發器。執行速度快。
表和索引所占空間。當表被TRUNCATE 后,這個表和索引所占用的空間會恢復到初始大小,而DELETE操作不會減少表或索引所占用的空間。drop語句將表所占用的空間全釋放掉。
一般而言,drop > truncate > delete
應用范圍。TRUNCATE 只能對TABLE;DELETE可以是table和view
TRUNCATE 和DELETE只刪除數據,而DROP則刪除整個表(結構和數據)。
truncate與不帶where的delete :只刪除數據,而不刪除表的結構(定義)drop語句將刪除表的結構被依賴的約束(constrain),觸發器(trigger)索引(index);依賴于該表的存儲過程/函數將被保留,但其狀態會變為:invalid。
delete語句為DML(data maintain Language),這個操作會被放到 rollback segment中,事務提交后才生效。如果有相應的 tigger,執行的時候將被觸發。
truncate、drop是DLL(data define language),操作立即生效,原數據不放到 rollback segment中,不能回滾
在沒有備份情況下,謹慎使用 drop 與 truncate。要刪除部分數據行采用delete且注意結合where來約束影響范圍。回滾段要足夠大。要刪除表用drop;若想保留表而將表中數據刪除,如果于事務無關,用truncate即可實現。如果和事務有關,或老師想觸發trigger,還是用delete。
Truncate table 表名 速度快,而且效率高,因為truncate table 在功能上與不帶 WHERE 子句的 DELETE 語句相同:二者均刪除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日志資源少。DELETE 語句每次刪除一行,并在事務日志中為所刪除的每行記錄一項。TRUNCATE TABLE 通過釋放存儲表數據所用的數據頁來刪除數據,并且只在事務日志中記錄頁的釋放。
TRUNCATE TABLE 刪除表中的所有行,但表結構及其列、約束、索引等保持不變。新行標識所用的計數值重置為該列的種子。如果想保留標識計數值,請改用 DELETE。如果要刪除表定義及其數據,請使用 DROP TABLE 語句。
對于由 FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應使用不帶 WHERE 子句的 DELETE 語句。由于 TRUNCATE TABLE 不記錄在日志中,所以它不能激活觸發器。
索引
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。索引的實現通常使用B樹及其變種B+樹。在數據之外,數據庫系統還維護著滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
為表設置索引要付出代價的:
一是增加了數據庫的存儲空間;
二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)。
優點:
通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性;
可以大大加快數據的檢索速度,這也是創建索引的最主要的原因;
可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義;
在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間;
通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。
缺點:
創建索引和維護索引要耗費時間,這種時間隨著數據量的增加而增加;
索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大;
當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。
不具備創建索引列的特點:
對于那些在查詢中很少使用或者參考的列不應該創建索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,并不能提高查詢速度。相反,由于增加了索引,反而降低了系統的維護速度和增大了空間需求。
對于那些只有很少數據值的列也不應該增加索引。這是因為,由于這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,并不能明顯加快檢索速度。
對于那些定義為text, image和bit數據類型的列不應該增加索引。這是因為,這些列的數據量要么相當大,要么取值很少。
當修改性能遠遠大于檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大于檢索性能時,不應該創建索引。
數據庫的三種索引:
唯一索引:是不允許其中任何兩行具有相同索引值的索引。當現有數據中存在重復的鍵值時,大多數數據庫不允許將新創建的唯一索引與表一起保存。數據庫還可能防止添加將在表中創建重復鍵值的新數據。
主鍵索引 :數據庫表經常有一列或列組合,其值唯一標識表中的每一行。該列稱為表的主鍵。在數據庫關系圖中為表定義主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特定類型。
聚集索引 :在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引。
連接查詢
外連接 :
包括左向外聯接、右向外聯接或完整外部聯接。
左連接:left join 或 left outer join
左向外聯接的結果集包括 LEFT OUTER 子句中指定的左表的所有行,而不僅僅是聯接列所匹配的行。如果左表的某行在右表中沒有匹配行,則在相關聯的結果集行中右表的所有選擇列表列均為空值(null)。
select?*?from?table1?left?join?table2?on?table1.id=table2.id右連接:right join 或 right outer join
右向外聯接是左向外聯接的反向聯接。將返回右表的所有行。如果右表的某行在左表中沒有匹配行,則將為左表返回空值。
select?*?from?table1?right?join?table2?on?table1.id=table2.id完整外部聯接:full join 或 full outer join
完整外部聯接返回左表和右表中的所有行。當某行在另一個表中沒有匹配行時,則另一個表的選擇列表列包含空值。如果表之間有匹配行,則整個結果集行包含基表的數據值。
select?*?from?table1?full?join?table2?on?table1.id=table2.id內連接:
內聯接是用比較運算符比較要聯接列的值的聯接
1.內連接:join 或 inner join
select?*?from?table1?join?table2?on?table1.id=table2.id2.等價(與下列執行效果相同)
select?a.*,b.*?from?table1?a,table2?b?where?a.id=b.idselect?*?from?table1?cross?join?table2?where?table1.id=table2.id?#注:cross join后加條件只能用where,不能用on
交叉連接(完全):
沒有 WHERE 子句的交叉聯接將產生聯接所涉及的表的笛卡爾積。第一個表的行數乘以第二個表的行數等于笛卡爾積結果集的大小。(table1和table2交叉連接產生3*3=9條記錄)
1.交叉連接:cross join (不帶條件where…)
select?*?from?table1?cross?join?table22.、等價(與下列執行效果相同)
select?*?from?table1,table2數據庫范式
第一范式(1NF):
在任何一個關系數據庫中,第一范式(1NF)是對關系模式的基本要求,不滿足第一范式(1NF)的數據庫就不是關系數據庫。
所謂第一范式(1NF)是指數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重復的屬性。如果出現重復的屬性,就可能需要定義一個新的實體,新的實體由重復的屬性構成,新實體與原實體之間為一對多關系。在第一范式(1NF)中表的每一行只包含一個實例的信息。簡而言之,第一范式就是無重復的列。
第二范式(2NF):
是在第一范式(1NF)的基礎上建立起來的,即滿足第二范式(2NF)必須先滿足第一范式(1NF)。第二范式(2NF)要求數據庫表中的每個實例或行必須可以被惟一地區分。為實現區分通常需要為表加上一個列,以存儲各個實例的惟一標識。這個惟一屬性列被稱為主關鍵字或主鍵、主碼。
第二范式(2NF)要求實體的屬性完全依賴于主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那么這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關系。為實現區分通常需要為表加上一個列,以存儲各個實例的惟一標識。簡而言之,第二范式就是非主屬性非部分依賴于主關鍵字。
第三范式(3NF):
滿足第三范式(3NF)必須先滿足第二范式(2NF)。簡而言之,第三范式(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息。例如,存在一個部門信息表,其中每個部門有部門編號(dept_id)、部門名稱、部門簡介等信息。那么在員工信息表中列出部門編號后就不能再將部門名稱、部門簡介等與部門有關的信息再加入員工信息表中。如果不存在部門信息表,則根據第三范式(3NF)也應該構建它,否則就會有大量的數據冗余。簡而言之,第三范式就是屬性不依賴于其它非主屬性。
SQL語句優化
應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描;
應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描。如:select id from t where num is null可以在num上設置默認值0,確保表中num列沒有null值,然后這樣查詢:select id from t where num=0;
很多時候用 exists 代替 in 是一個好的選擇;
用Where子句替換HAVING 子句 因為HAVING 只會在檢索出所有記錄之后才對結果集進行過濾;
在表中建立索引,優先考慮where、group by使用到的字段;
盡量避免使用select *,返回無用的字段會降低查詢效率;
盡量避免使用in和not in,會導致數據庫引擎放棄索引進行全表掃描;
盡量避免使用or,會導致數據庫引擎放棄索引進行全表掃描;
盡量避免在字段開頭模糊查詢,會導致數據庫引擎放棄索引進行全表掃描。
數據庫結構優化
范式優化:比如消除冗余(節省空間);
反范式優化:比如適當加冗余等(減少join);
拆分表(垂直拆分和水平拆分):分區將數據在物理上分隔開,不同分區的數據可以制定保存在處于不同磁盤上的數據文件里。
MySQL中myisam與innodb的區別
InnoDB支持事物,而MyISAM不支持事物;
InnoDB支持行級鎖,而MyISAM支持表級鎖;
InnoDB支持MVCC, 而MyISAM不支持;
InnoDB支持外鍵,而MyISAM不支持;
InnoDB不支持全文索引,而MyISAM支持;
InnoDB不能通過直接拷貝表文件的方法拷貝表到另外一臺機器, myisam 支持;
InnoDB表支持多種行格式, myisam 不支持;
InnoDB是索引組織表, myisam 是堆表。
Innodb引擎的4大特性
插入緩沖(insert buffer)
二次寫(double write)
自適應哈希索引(ahi)
預讀(read ahead)
四種事務隔離級別
讀未提交(read uncommitted) :可以讀取其他 session 未提交的臟數據。
讀已提交(read committed) :允許不可重復讀取,但不允許臟讀取。提交后,其他會話可以看到提交的數據。
可重復讀(repeatable read) :禁止不可重復讀取和臟讀取、以及幻讀(innodb 獨有)。
串行(serializable):事務只能一個接著一個地執行,但不能并發執行。事務隔離級別最高。
| 讀未提交(read-uncommitted) | 是 | 是 | 是 |
| 不可重復讀(read-committed) | 否 | 是 | 是 |
| 可重復讀(repeatable-read) | 否 | 否 | 是 |
| 串行化(serializable) | 否 | 否 | 否 |
注:mysql默認是 可重復讀(repeatable-read),oracle默認是讀已提交(read committed)。
MySQL B+Tree索引和Hash索引的區別
Hash索引結構的特殊性,其檢索效率非常高,索引的檢索可以一次定位;
B+樹索引需要從根節點到枝節點,最后才能訪問到頁節點這樣多次的IO訪問。
樂觀鎖和悲觀鎖
悲觀鎖(Pessimistic Lock)的特點是先獲取鎖,再進行業務操作,即“悲觀”的認為獲取鎖是非常有可能失敗的,因此要先確保獲取鎖成功再進行業務操作。通常所說的“一鎖二查三更新”即指的是使用悲觀鎖。通常來講在數據庫上的悲觀鎖需要數據庫本身提供支持,即通過常用的select … for update操作來實現悲觀鎖。當數據庫執行select for update時會獲取被select中的數據行的行鎖,因此其他并發執行的select for update如果試圖選中同一行則會發生排斥(需要等待行鎖被釋放),因此達到鎖的效果。select for update獲取的行鎖會在當前事務結束時自動釋放,因此必須在事務中使用。
樂觀鎖(Optimistic Lock),也叫樂觀并發控制,它假設多用戶并發的事務在處理時不會彼此互相影響,各事務能夠在不產生鎖的情況下處理各自影響的那部分數據。在提交數據更新之前,每個事務會先檢查在該事務讀取數據后,有沒有其他事務又修改了該數據。如果其他事務有更新的話,那么當前正在提交的事務會進行回滾。樂觀鎖的特點先進行業務操作,不到萬不得已不去拿鎖。即“樂觀”的認為拿鎖多半是會成功的,因此在進行完業務操作需要實際更新數據的最后一步再去拿一下鎖就好。
總結:
悲觀鎖和樂觀鎖是數據庫用來保證數據并發安全防止更新丟失的兩種方法,例子在select … for update前加個事務就可以防止更新丟失。悲觀鎖和樂觀鎖大部分場景下差異不大,一些獨特場景下有一些差別,一般我們可以從如下幾個方面來判斷。
響應速度:如果需要非常高的響應速度,建議采用樂觀鎖方案,成功就執行,不成功就失敗,不需要等待其他并發去釋放鎖。
沖突頻率:如果沖突頻率非常高,建議采用悲觀鎖,保證成功率,如果沖突頻率大,樂觀鎖會需要多次重試才能成功,代價比較大。
重試代價:如果重試代價大,建議采用悲觀鎖。
非關系型數據庫和關系型數據庫區別
非關系型數據庫的優勢:
性能:NOSQL是基于鍵值對的,可以想象成表中的主鍵和值的對應關系,而且不需要經過SQL層的解析,所以性能非常高。
可擴展性:同樣也是因為基于鍵值對,數據之間沒有耦合性,所以非常容易水平擴展。
關系型數據庫的優勢:
復雜查詢:可以用SQL語句方便的在一個表以及多個表之間做非常復雜的數據查詢。
事務支持:使得對于安全性能很高的數據訪問要求得以實現。
EXPLAIN
語法:
EXPLAIN?SELECTEXPLAIN EXTENDED SELECT 將執行計劃“反編譯”成SELECT語句,運行SHOW WARNINGS 可得到被MySQL優化器優化后的查詢語句 ;
EXPLAIN PARTITIONS SELECT 用于分區表的EXPLAIN;
在Navicat圖形化界面中,點擊“解釋”出現執行計劃的信息。
執行計劃中的信息:
1.id:包含一組數字,表示查詢中執行select子句或操作表的順序。id相同,可以認為是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行。
2.select_type:主要用于區別普通查詢, 聯合查詢, 子查詢等復雜查詢。
SIMPLE:查詢中不包含子查詢或者UNION
查詢中若包含任何復雜的子部分,最外層查詢則被標記為:PRIMARY
在SELECT或WHERE列表中包含了子查詢,該子查詢被標記為:SUBQUERY
在FROM列表中包含的子查詢被標記為:DERIVED(衍生)
若第二個SELECT出現在UNION之后,則被標記為UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED
從UNION表獲取結果的SELECT被標記為:UNION RESULT
3.type:表示MySQL在表中找到所需行的方式,又稱“訪問類型”(ALL、index、range、ref、eq_ref、const、system、NULL),由左至右,由最差到最好
ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行
index:Full Index Scan,index與ALL區別為index類型只遍歷索引樹
range:索引范圍掃描,對索引的掃描開始于某一點,返回匹配值域的行,常見于between、等的查詢
ref:非唯一性索引掃描,返回匹配某個單獨值的所有行。常見于使用非唯一索引即唯一索引的非唯一前綴進行的查找
eq_ref:唯一性索引掃描,對于每個索引鍵,表中只有一條記錄與之匹配。常見于主鍵或唯一索引掃描
const、system:當MySQL對查詢某部分進行優化,并轉換為一個常量時,使用這些類型訪問。如將主鍵置于where列表中,MySQL就能將該查詢轉換為一個常量
system是const類型的特例,當查詢的表只有一行的情況下, 使用system
NULL:MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引
4.possible_keys:指出MySQL能使用哪個索引在表中找到行,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢使用
5.key:顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL
查詢中若使用了覆蓋索引,則該索引僅出現在key列表中
6.key_len:表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度
key_len顯示的值為索引字段的最大可能長度,并非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的
7.ref:表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值
8.rows:表示MySQL根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數
9.Extra:包含不適合在其他列中顯示但十分重要的額外信息
Using index:該值表示相應的select操作中使用了覆蓋索引(Covering Index)。
MySQL可以利用索引返回select列表中的字段,而不必根據索引再次讀取數據文件包含所有滿足查詢需要的數據的索引稱為 覆蓋索引(Covering Index)
Using where:表示MySQL服務器在存儲引擎受到記錄后進行“后過濾”(Post-filter),如果查詢未能使用索引,Using where的作用只是提醒我們MySQL將用where子句來過濾結果集
Using temporary:表示MySQL需要使用臨時表來存儲結果集,常見于排序和分組查詢
Using filesort:MySQL中無法利用索引完成的排序操作稱為“文件排序”
注意:如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可select *,因為如果將所有字段一起做索引會導致索引文件過大,查詢性能下降
執行計劃的局限:
EXPLAIN不會告訴你關于觸發器、存儲過程的信息或用戶自定義函數對查詢的影響情況
EXPLAIN不考慮各種Cache
EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作
部分統計信息是估算的,并非精確值
EXPALIN只能解釋SELECT操作,其他操作要重寫為SELECT后查看執行計劃
Redis
概念
Redis 是一個開源的使用 ANSI C 語言編寫、遵守 BSD 協議、支持網絡、可基于內存亦可持久化的日志型、Key-Value 數據庫,并提供多種語言的 API的非關系型數據庫。
傳統數據庫遵循 ACID 規則。而 Nosql(Not Only SQL 的縮寫,是對不同于傳統的關系型數據庫的數據庫管理系統的統稱) 一般為分布式而分布式一般遵循 CAP 定理。
Redis支持的數據類型
String:string類型是二進制安全的。意思是redis的string可以包含任何數據。比如jpg圖片或者序列化的對象 。string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB;
Hash:hash 是一個鍵值(key=>value)對集合。Redis hash是一個string類型的field和value的映射表,hash特別適合用于存儲對象;
List:列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊);
Set:Set是string類型的無序集合。集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1);
zset(有序集合):zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重復。
Redis的持久化
1.持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。Redis 提供了兩種持久化方式:
RDB(默認):Redis DataBase縮寫,功能核心函數rdbSave(生成RDB文件)和rdbLoad(從文件加載內存)兩個函數;
AOF :Append-only file縮寫,每當執行服務器(定時)任務或者函數時flushAppendOnlyFile 函數都會被調用, 這個函數執行以下兩個工作aof寫入保存:1).WRITE:根據條件,將 aof_buf 中的緩存寫入到 AOF 文件;2).SAVE:根據條件,調用 fsync 或 fdatasync 函數,將 AOF 文件保存到磁盤中。
2.存儲結構:內容是redis通訊協議(RESP )格式的命令文本存儲。
3.RDB和AOF的比較:
aof文件比rdb更新頻率高,優先使用aof還原數據;
aof比rdb更安全也更大;
rdb性能比aof好;
如果兩個都配了優先加載AOF。
4.RESP:是redis客戶端和服務端之前使用的一種通訊協議;RESP 的特點:實現簡單、快速解析、可讀性好。
Redis的架構模式
單機版:
特點:簡單
問題:內存容量有限 、處理能力有限 、無法高可用。
主從復制:
Redis 的復制(replication)功能允許用戶根據一個 Redis 服務器來創建任意多個該服務器的復制品,其中被復制的服務器為主服務器(master),而通過復制創建出來的服務器復制品則為從服務器(slave)。只要主從服務器之間的網絡連接正常,主從服務器兩者會具有相同的數據,主服務器就會一直將發生在自己身上的數據更新同步 給從服務器,從而一直保證主從服務器的數據相同。
特點:master/slave 角色、master/slave 數據相同、降低 master 讀壓力在轉交從庫;
問題:無法保證高可用、沒有解決 master 寫的壓力。
哨兵:
Redis sentinel 是一個分布式系統中監控 redis 主從服務器,并在主服務器下線時自動進行故障轉移。
1.特性:
監控(Monitoring):Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
提醒(Notification):當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
自動故障遷移(Automatic failover):當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作。
2.特點:保證高可用、監控各個節點、自動故障遷移;
3.缺點:主從模式,切換需要時間丟數據、沒有解決 master 寫的壓力。
集群(proxy 型):
Twemproxy 是一個 Twitter 開源的一個 redis 和 memcache 快速/輕量級代理服務器;Twemproxy 是一個快速的單線程代理程序,支持 Memcached ASCII 協議和 redis 協議。
1.特點:
多種 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins ;
支持失敗節點自動刪除;
后端 Sharding 分片邏輯對業務透明,業務方的讀寫方式和操作單個 Redis 一致。
2.缺點:增加了新的 proxy,需要維護其高可用。
集群(直連型):
從redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用無中心結構,每個節點保存數據和整個集群狀態,每個節點都和其他所有節點連接。
1.特點:
無中心架構(不存在哪個節點影響性能瓶頸),少了 proxy 層;
數據按照 slot 存儲分布在多個節點,節點間數據共享,可動態調整數據分布;
可擴展性,可線性擴展到 1000 個節點,節點可動態添加或刪除;
高可用性,部分節點不可用時,集群仍可用。通過增加 Slave 做備份數據副本;
實現故障自動 failover,節點之間通過 gossip 協議交換狀態信息,用投票機制完成 Slave到 Master 的角色提升。
2.缺點:
資源隔離性較差,容易出現相互影響的情況;
數據通過異步復制,不保證數據的強一致性。
緩存穿透和緩存雪崩
緩存穿透:
1.理解一:一般的緩存系統,都是按照key去緩存查詢,如果不存在對應的value,就應該去后端系統查找(比如DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對后端系統造成很大的壓力。這就叫做緩存穿透。
2.如何避免:
對查詢結果為空的情況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了之后清理緩存。
對一定不存在的key進行過濾。可以把所有的可能存在的key放到一個大的Bitmap中,查詢時通過該bitmap過濾。
3.理解二:緩存穿透是指查詢一個一定不存在的數據。由于緩存不命中,并且出于容錯考慮,如果從數據庫查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,失去了緩存的意義。
請求的數據在緩存大量不命中,導致請求走數據庫。
4.解決方法:
由于請求的參數是不合法的(每次都請求不存在的參數),于是我們可以使用布隆過濾器(BloomFilter)或者壓縮filter提前攔截,不合法就不讓這個請求到數據庫層;
當我們從數據庫找不到的時候,我們也將這個空對象設置到緩存里邊去。下次再請求的時候,就可以從緩存里邊獲取了。
緩存雪崩:
1.理解一:當緩存服務器重啟或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給后端系統帶來很大壓力。導致系統崩潰。
2.如何避免:
在緩存失效后,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
做二級緩存,A1為原始緩存,A2為拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置為短期,A2設置為長期
不同的key,設置不同的過期時間,讓緩存失效的時間點盡量均勻。
3.理解二:
Redis掛掉了,請求全部走數據庫;
對緩存數據設置相同的過期時間,導致某段時間內緩存失效,請求全部走數據庫。
4.解決方法:
對于“Redis掛掉了,請求全部走數據庫”這種情況,可以有以下的思路:
事發前:實現Redis的高可用(主從架構+Sentinel 或者Redis Cluster),盡量避免Redis掛掉這種情況發生;
事發中:萬一Redis真的掛了,我們可以設置本地緩存(ehcache)+限流(hystrix),盡量避免我們的數據庫被干掉(起碼能保證我們的服務還是能正常工作的);
事發后:redis持久化,重啟后自動從磁盤上加載數據,快速恢復緩存數據。
對于“對緩存數據設置相同的過期時間,導致某段時間內緩存失效,請求全部走數據庫。”這種情況,非常好解決:
在緩存的時候給過期時間加上一個隨機值,這樣就會大幅度的減少緩存在同一時間過期。
為什么redis需要把所有數據放到內存中
Redis為了達到最快的讀寫速度將數據都讀到內存中,并通過異步的方式將數據寫入磁盤。所以redis具有快速和數據持久化的特征。如果不將數據放在內存中,磁盤I/O速度為嚴重影響redis的性能。在內存越來越便宜的今天,redis將會越來越受歡迎。如果設置了最大使用的內存,則數據已有記錄數達到內存限值后不能繼續插入新值。
Redis的單進程單線程
Redis利用隊列技術將并發訪問變為串行訪問,消除了傳統數據庫串行控制的開銷。
Redis的回收策略
volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰;
volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰;
volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰;
allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰;
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰;
no-enviction(驅逐):禁止驅逐數據。
使用Redis的好處
速度快:因為數據存在內存中,類似于HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1);
支持豐富數據類型:支持string,list,set,sorted set,hash;
支持事務:操作都是原子性,所謂的原子性就是對數據的更改要么全部執行,要么全部不執行;
豐富的特性:可用于緩存,消息,按key設置過期時間,過期后將會自動刪除。
Redis 最適合的場景
會話緩存(Session Cache)
最常用的一種使用Redis的情景是會話緩存(session cache)。用Redis緩存會話比其他存儲(如Memcached)的優勢在于:Redis提供持久化。當維護一個不是嚴格要求一致性的緩存時,如果用戶的購物車信息全部丟失,大部分人都會不高興的,現在,他們還會這樣嗎?幸運的是,隨著 Redis 這些年的改進,很容易找到怎么恰當的使用Redis來緩存會話的文檔。甚至廣為人知的商業平臺Magento也提供Redis的插件。
全頁緩存(FPC)
除基本的會話token之外,Redis還提供很簡便的FPC平臺。回到一致性問題,即使重啟了Redis實例,因為有磁盤的持久化,用戶也不會看到頁面加載速度的下降,這是一個極大改進,類似PHP本地FPC。再次以Magento為例,Magento提供一個插件來使用Redis作為全頁緩存后端。此外,對WordPress的用戶來說,Pantheon有一個非常好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
隊列
Reids在內存存儲引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作為一個很好的消息隊列平臺來使用。Redis作為隊列使用的操作,就類似于本地程序語言(如Python)對 list 的 push/pop 操作。
如果你快速的在Google中搜索“Redis queues”,你馬上就能找到大量的開源項目,這些項目的目的就是利用Redis創建非常好的后端工具,以滿足各種隊列需求。例如,Celery有一個后臺就是使用Redis作為broker,你可以從這里去查看。
排行榜/計數器
Redis在內存中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)也使得我們在執行這些操作的時候變的非常簡單,Redis只是正好提供了這兩種數據結構。所以,我們要從排序集合中獲取到排名最靠前的10個用戶–我們稱之為“user_scores”,我們只需要像下面一樣執行即可:
當然,這是假定你是根據你用戶的分數做遞增的排序。如果你想返回用戶及用戶的分數,你需要這樣執行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一個很好的例子,用Ruby實現的,它的排行榜就是使用Redis來存儲數據的,你可以在這里看到。
發布/訂閱
Redis的發布/訂閱功能。發布/訂閱的使用場景確實非常多。我已看見人們在社交網絡連接中使用,還可作為基于發布/訂閱的腳本觸發器,甚至用Redis的發布/訂閱功能來建立聊天系統。
Redis支持的Java客戶端
Redisson(官方推薦使用):是一個高級的分布式協調Redis客服端,能幫助用戶在分布式環境中輕松實現一些Java的對象;
Jedis:Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支持;
lettuce
Redisson和Jedis的區別:Redisson實現了分布式和可擴展的Java數據結構,和Jedis相比,功能較為簡單,不支持字符串操作,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。
Redis哈希槽
Redis集群沒有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽,集群的每個節點負責一部分hash槽
Redis管道的作用
一次請求/響應服務器能實現處理新的請求即使舊的請求還未被響應。這樣就可以將多個命令發送到服務器,而不用等待回復,最后在一個步驟中讀取該答復。
Redis事務
事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。事務是一個原子操作:事務中的命令要么全部被執行,要么全部都不執行。
Redis事務相關的命令:MULTI、EXEC、DISCARD、WATCH
Redis的分布式事務
對于讀操作
如果我們的數據在緩存里邊有,那么就直接取緩存的;
如果緩存里沒有我們想要的數據,我們會先去查詢數據庫,然后將數據庫查出來的數據寫到緩存中;
最后將數據返回給請求。
對于更新操作
一般來說,執行更新操作時,我們會有兩種選擇:
先操作數據庫,再操作緩存
先操作緩存,再操作數據庫
如果原子性被破壞了,可能會有以下的情況:
操作數據庫成功了,操作緩存失敗了。
操作緩存成功了,操作數據庫失敗了。
發布/訂閱
更新緩存
刪除緩存
一般我們都是采取刪除緩存緩存策略的,原因如下:
高并發環境下,無論是先操作數據庫還是后操作數據庫而言,如果加上更新緩存,那就更加容易導致數據庫與緩存數據不一致問題。(刪除緩存直接和簡單很多)
如果每次更新了數據庫,都要更新緩存【這里指的是頻繁更新的場景,這會耗費一定的性能】,倒不如直接刪除掉。等再次讀取時,緩存里沒有,那我到數據庫找,在數據庫找到再寫到緩存里邊(體現懶加載)
基于這兩點,對于緩存在更新時而言,都是建議執行刪除操作!
發布/訂閱
先操作數據庫,成功;
再刪除緩存,也成功;
如果原子性被破壞了:
第一步成功(操作數據庫),第二步失敗(刪除緩存),會導致數據庫里是新數據,而緩存里是舊數據。
如果第一步(操作數據庫)就失敗了,我們可以直接返回錯誤(Exception),不會出現數據不一致。
如果在高并發的場景下,出現數據庫與緩存數據不一致的概率特別低,也不是沒有:
緩存剛好失效
線程A查詢數據庫,得一個舊值
線程B將新值寫入數據庫
線程B刪除緩存
線程A將查到的舊值寫入緩存
要達成上述情況,還是說一句概率特別低:
因為這個條件需要發生在讀緩存時緩存失效,而且并發著有一個寫操作。而實際上數據庫的寫操作會比讀操作慢得多,而且還要鎖表,而讀操作必需在寫操作前進入數據庫操作,而又要晚于寫操作更新緩存,所有的這些條件都具備的概率基本并不大。
刪除緩存失敗的解決思路:
將需要刪除的key發送到消息隊列中
自己消費消息,獲得需要刪除的key
不斷重試刪除操作,直到成功
發布/訂閱
先刪除緩存,成功;
再更新數據庫,也成功;
如果原子性被破壞了:
第一步成功(刪除緩存),第二步失敗(更新數據庫),數據庫和緩存的數據還是一致的。
如果第一步(刪除緩存)就失敗了,我們可以直接返回錯誤(Exception),數據庫和緩存的數據還是一致的。
看起來是很美好,但是我們在并發場景下分析一下,就知道還是有問題的了:
線程A刪除了緩存
線程B查詢,發現緩存已不存在
線程B去數據庫查詢得到舊值
線程B將舊值寫入緩存
線程A將新值寫入數據庫
所以也會導致數據庫和緩存不一致的問題,并發下解決數據庫與緩存不一致的思路:將刪除緩存、修改數據庫、讀取緩存等的操作積壓到隊列里邊,實現串行化。
發布/訂閱
我們可以發現,兩種策略各自有優缺點:
先刪除緩存,再更新數據庫
在高并發下表現不如意,在原子性被破壞時表現優異
先更新數據庫,再刪除緩存(Cache Aside Pattern設計模式)
在高并發下表現優異,在原子性被破壞時表現不如意
Redis與Memcached的區別與比較
Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。memcache支持簡單的數據類型,String;
Redis支持數據的備份,即master-slave模式的數據備份;
Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用,而Memecache把數據全部存在內存之中;
Redis的速度比memcached快很多;
Memcached是多線程,非阻塞IO復用的網絡模型;Redis使用單線程的IO復用模型。
歡迎關注
總結
以上是生活随笔為你收集整理的使用t-sql语句修改表中的某些数据及数据类型。_Java面试——数据库知识点的全部內容,希望文章能夠幫你解決所遇到的問題。