# MySQL的存儲(chǔ)引擎
`MyISAM`(默認(rèn)表類型):非事務(wù)的存儲(chǔ)引擎,基于傳統(tǒng)的`ISAM`(有索引的順序訪問方法)類型,是存儲(chǔ)記錄和文件的標(biāo)準(zhǔn)方法,不是事務(wù)安全,不支持外鍵,適用于頻繁的查詢。表鎖,不會(huì)出現(xiàn)死鎖,適合小數(shù)據(jù)和小并發(fā)。
- 為什么不會(huì)出死鎖?(沒有事務(wù)就不會(huì)繼續(xù)持有鎖)
答:因?yàn)閌MyISAM`再查詢的時(shí)候,會(huì)同時(shí)鎖定這個(gè)`sql`里面所有用到的表(獲取鎖的順序是一致的),不局限與一張表,再寫鎖又重疊時(shí),就得等待。
**注意:【`MySQL5.5`之前默認(rèn)的是`MyISAM`引擎了,5.5之后的版本默認(rèn)都是`innodb`作為存儲(chǔ)引擎】**
`innodb`:支持事務(wù)安全的存儲(chǔ)引擎,適用于插入和更新,支持外鍵,行鎖,事務(wù)。適合大數(shù)據(jù),大并發(fā)。特別是針對多個(gè)并發(fā)和`QPS`較高的情況。
- `QPS:`就是每秒查詢率,`QPS`是對一個(gè)特定服務(wù)器再規(guī)定時(shí)間內(nèi)能處理多少流量的衡量標(biāo)準(zhǔn)。
- `TPS:`就是每秒傳輸處理的事務(wù)個(gè)數(shù)。
- `innodb`的行鎖模式:共享鎖,排他鎖,意向共享鎖(表鎖),意向排他鎖(表鎖),間隙鎖。(注意:如果`sql`語句沒有使用索引,`innodb`不能確定操作的行時(shí),使用意向鎖(表鎖))。
- 死鎖問題
- 什么是死鎖?
死鎖就是當(dāng)倆個(gè)事務(wù)都需要獲取對方持有的排他鎖才能完成事務(wù)的時(shí)候,就導(dǎo)致了循環(huán)鎖等待,常見的死鎖類型。
- 解決辦法
1. 數(shù)據(jù)庫參數(shù) 2. 盡量約定程序讀取表的順序 3. 在處理一個(gè)表時(shí),盡量對處理的順序排序 4. 調(diào)整事務(wù)隔離級(jí)別(避免倆個(gè)事務(wù)同時(shí)操作一行不存在的數(shù)據(jù),容易發(fā)生死鎖)
存儲(chǔ)引擎還有:
- `MERGE:`將多個(gè)類似的`MyISAM`表分組為一個(gè)表,可以處理非事務(wù)性表,默認(rèn)情況下包括這些表。 - `MEMORY:`提供內(nèi)存中的表,以前稱為堆。它在RAM中處理所有數(shù)據(jù),以便比在磁盤上存儲(chǔ)數(shù)據(jù)更快地訪問。用于快速查找引用和其他相同的數(shù)據(jù)。 - `EXAMPLE:`可以使用此引擎創(chuàng)建表,但不能存儲(chǔ)或獲取數(shù)據(jù)。這樣做的目的是教開發(fā)人員如何編寫新的存儲(chǔ)引擎。 - `ARCHIVE:`用于存儲(chǔ)大量數(shù)據(jù),不支持索引。 - `CSV:`在文本文件中以逗號(hào)分隔值格式存儲(chǔ)數(shù)據(jù)。 - `BLACKHOLE:`受要存儲(chǔ)的數(shù)據(jù),但始終返回空。 - `FEDERATED:`將數(shù)據(jù)存儲(chǔ)在遠(yuǎn)程數(shù)據(jù)庫中。
# 數(shù)據(jù)表的類型
`MyISAM`,`InnoDB`,`MEMORY`,`HEAP`,`BOB`,`ARCHIVE`,`CSV`等
- `MYISAM:`成熟穩(wěn)定,易于管理,快速讀取。表級(jí)鎖。 - `Innodb:`數(shù)據(jù)行鎖。占用空間大,不支持全文索引。
# `MySQL`作為發(fā)布系統(tǒng)的儲(chǔ)存,一天五萬條以上的增量,怎么優(yōu)化?
1. 設(shè)計(jì)良好的數(shù)據(jù)庫結(jié)構(gòu),允許部分?jǐn)?shù)據(jù)冗余,盡量避免join查詢,提高效率。 2. 選擇合適的表字段類型和存儲(chǔ)引擎,適當(dāng)添加索引。 3. `MySQL`庫主從讀寫分離。 4. 找規(guī)律分表,減少表單中的數(shù)據(jù)量,提高查詢速度。 5. 添加緩存機(jī)制??梢允褂胉Redis`緩存。 6. 不經(jīng)常改動(dòng)的頁面,生成靜態(tài)頁面。 7. 寫高效率的`sql`語句。如:`SELECT * FROM TABEL 改為 SELECT field_1, field_2, field_3 FROM TABLE`。
為什么要避免使用join查詢?
答:減少消耗。
# 對于大流量網(wǎng)站,如何解決各頁面統(tǒng)計(jì)訪問量問題?
1. 確認(rèn)服務(wù)器是否能支撐當(dāng)前訪問量。 2. 優(yōu)化數(shù)據(jù)庫訪問。 3. 禁止外部訪問,如圖片盜鏈。 4. 控制文件下載。 5. 使用不同主機(jī)進(jìn)行分流。 6. 使用瀏覽統(tǒng)計(jì)軟件,了解訪問量,有針對性的進(jìn)行優(yōu)化。
# 如何進(jìn)行`SQL`優(yōu)化?
1. 選擇正確的存儲(chǔ)引擎。 每個(gè)引擎都有利有弊,比如`MyISAM`,適用于大量查詢,對大量寫操作并不是很好,`update`一個(gè)字段都會(huì)把整個(gè)表鎖起來,而I`nnodb`,對一些小的應(yīng)用,它比`MyISAM`慢,但它支持行鎖,再寫操作的時(shí)候,很優(yōu)秀,它還支持更多的高級(jí)應(yīng)用。 2. 優(yōu)化字段的數(shù)據(jù)類型 一個(gè)原則,越小的越快,如果一個(gè)表只有幾列,那我們就不用用`INT`來做主鍵,可以使用`MEDIUMINT`,`SMALLINT`或是更小的`TINYINT`會(huì)更經(jīng)濟(jì)一些,如果不需要記錄時(shí)間,使用`DATE`要比`DATETIME`好的多,也要留夠足夠的空間進(jìn)行擴(kuò)展。 3. 為搜索字段添加索引 索引不一定只添加給主鍵或唯一的字段,如果在表中有某個(gè)字段經(jīng)常用來做搜索,那就為它建立索引,如果要搜索的字段是大的文本字段,那應(yīng)該為它建立全文索引。 4. 避免使用`select *`因?yàn)閺臄?shù)據(jù)庫讀出的數(shù)據(jù)越多,那么查詢就會(huì)越慢。如果數(shù)據(jù)庫服務(wù)和WEB服務(wù)器在不同的機(jī)器上的話,還會(huì)增加網(wǎng)絡(luò)傳輸?shù)呢?fù)載。即使要查詢表的所有字段,也盡量不要用`*`通配符。 5. 使用`ENUM`而不是`VARCHAR` `ENUM`類型是非??旌途o湊的,它保存的是`TINYINT`,但外表上顯示的是字符串,做一些選項(xiàng)列表很好,比如:性別,民族,部門,狀態(tài)之類的字段,取值有限而且固定。 6. 盡可能使用`NOT NULL` `NULL`其實(shí)也需要額外空間的,在進(jìn)行比較的時(shí)候,程序也會(huì)變得復(fù)雜,并不是并不可以用`NULL`,在現(xiàn)實(shí)的復(fù)雜情況下,依然會(huì)有些情況需要使用`NULL`值。 7. 固定長度的表會(huì)更快 如果表中的所有字段都是固定長度的,那整個(gè)表會(huì)被認(rèn)為是`“static”`或“`fixed-lenght”`。例如表中沒有`VARCHAR`,`TEXT`,`BLOB`,只要表中其中一個(gè)字段是這些類型,那么這個(gè)表就不是“固定長度靜態(tài)表”了,這樣的話`MySQL`引擎會(huì)用另一種方法來處理。 固定長度的表也容易被緩存和重建,唯一的副作用就是,固定長度的字段會(huì)浪費(fèi)一些空間,因?yàn)楣潭ㄩL度的字段無論用不用,都會(huì)分配那么多的空間。
# 如何設(shè)計(jì)一個(gè)高并發(fā)的系統(tǒng)
1. 數(shù)據(jù)庫優(yōu)化,喝的事務(wù)隔離級(jí)別,`SQL`語句,索引優(yōu)化。 2. 使用緩存,盡量減少數(shù)據(jù)庫`IO`操作。 3. 分布式數(shù)據(jù)庫,分布式緩存。 4. 服務(wù)器負(fù)載均衡。
# 什么情況下設(shè)置了索引卻無法使用
1. 以%開頭`LIKE`,模糊匹配。 2. `OR`語句前后沒有同時(shí)使用索引。 3. 數(shù)據(jù)類型出現(xiàn)隱式轉(zhuǎn)化,如`varchar`不加單引號(hào)可能會(huì)轉(zhuǎn)換為`int`型。
# `SQL`注入的主要特點(diǎn)
1. 變種極多,攻擊簡單,危害極大。 2. 未經(jīng)授權(quán)操作數(shù)據(jù)庫的數(shù)據(jù)。 3. 惡意篡改網(wǎng)頁。 4. 網(wǎng)頁掛木馬。 5. 私自添加系統(tǒng)賬號(hào)或是數(shù)據(jù)庫使用者賬號(hào)。
# 優(yōu)化數(shù)據(jù)庫的方法
1. 選取最適合的字段屬性,盡可能減少定義字段寬度,盡量把字段設(shè)成`NOT NULL`。 2. 使用`exists`替代`in`,用`not exists`替代`not in`。 3. 使用連接`(JOIN)`來替代子查詢。 4. 適用聯(lián)合`(NUION)`來代替手動(dòng)創(chuàng)建的臨時(shí)表。 5. 事務(wù)處理。 6. 鎖定表,優(yōu)化事務(wù)處理。 7. 適當(dāng)用外鍵,優(yōu)化鎖定表。 8. 建立索引。 9. 優(yōu)化查詢語句。
# 數(shù)據(jù)庫中的事務(wù)是什么
事務(wù)作為一個(gè)單元的一組有序的數(shù)據(jù)操作,如果組中的所有操作都完成,則認(rèn)定事務(wù)成功,即使只有一個(gè)失敗,事務(wù)也不成功。如果所有操作完成,事務(wù)則進(jìn)行提交,其修改將作用于所有其他數(shù)據(jù)庫進(jìn)程。如果一個(gè)操作失敗,則事務(wù)將回滾,該事務(wù)所有的操作的影響都會(huì)取消。
- `ACID`四大特性 - 原子性:不可分割,事務(wù)要么全部被執(zhí)行,要么全部不執(zhí)行。 - 一致性:事務(wù)的執(zhí)行使得數(shù)據(jù)庫從一種正確的狀態(tài)轉(zhuǎn)換成另一種正確的狀態(tài)。 - 隔離性:在事務(wù)正確提交前,不允許把該事務(wù)對數(shù)據(jù)的任何改變提供給任何其他事務(wù)。 - 持久性:事務(wù)正確提交后,將結(jié)果永久保存到數(shù)據(jù)庫中,即使在事務(wù)提交后,有了其他故障,事務(wù)處理結(jié)果也會(huì)得到保存。
# 索引的目的是什么?
1. 快速訪問數(shù)據(jù)表中特定信息,提高檢索速度。 2. 創(chuàng)建唯一性索引,保證每一行數(shù)據(jù)的唯一性。 3. 加速表和表之間的連接。 4. 使用分組和排序子句進(jìn)行數(shù)據(jù)檢索時(shí),可顯著的減少分組和排序的時(shí)間。
# 索引對數(shù)據(jù)庫系統(tǒng)的負(fù)面影響是什么? 創(chuàng)建索引和維護(hù)索引需要消耗時(shí)間,這個(gè)時(shí)間會(huì)隨著數(shù)據(jù)量的增加而增加,索引需要占用物理空間。當(dāng)對表進(jìn)行增刪改查的時(shí)候索引也需要?jiǎng)討B(tài)維護(hù),這樣就降低了數(shù)據(jù)的維護(hù)速度。 # 為數(shù)據(jù)表建立索引的原則
1. 頻繁使用的,用以縮小查詢范圍的字段上建立索引。 2. 頻繁使用的,需要排序的字段上建立索引。
# 什么情況下不宜建立索引
對于查詢中涉及很少的列,或是重復(fù)值較多的列,不宜建立索引。
一些特殊的數(shù)據(jù)類型,不宜就建立索引。如`text`文本字段。
# 左連接和右連接的區(qū)別
左連接:
- 左連接會(huì)讀取左表中的全部數(shù)據(jù),即使右表中沒有對應(yīng)的數(shù)據(jù)(如果倆個(gè)表有相同的數(shù)據(jù),只會(huì)顯示一個(gè)),用`NULL`填充。
右連接:
- 右連接會(huì)讀取右表的全部數(shù)據(jù),即使左表中沒有對應(yīng)的數(shù)據(jù)(如果倆個(gè)表有相同的數(shù)據(jù),只會(huì)顯示一個(gè)),用`NULL`填充。
# 什么是鎖?
數(shù)據(jù)庫是一個(gè)多用戶使用的共享資源,當(dāng)多個(gè)用戶并發(fā)的存取數(shù)據(jù)時(shí),在數(shù)據(jù)庫中就會(huì)產(chǎn)生多個(gè)事務(wù)同時(shí)存取同一個(gè)數(shù)據(jù)的情況,若對并發(fā)操作不加控制可能就會(huì)讀取和儲(chǔ)存不正確的數(shù)據(jù),破壞數(shù)據(jù)庫的一致性。
# 什么是存儲(chǔ)過程,用什么來調(diào)用?
存儲(chǔ)過程就是一個(gè)預(yù)編譯的`SQL`語句,優(yōu)點(diǎn)是允許模塊化設(shè)計(jì),只需要?jiǎng)?chuàng)建一次,就可以在該程序中多次調(diào)用,如果某次操作需要執(zhí)行多次`SQL`,使用存儲(chǔ)過程比單純的`SQL`語句要快??梢允褂靡粋€(gè)命令對象進(jìn)行調(diào)用。
# 索引的作用,和它的優(yōu)缺點(diǎn)
索引就是一種特殊的查詢表,數(shù)據(jù)庫引擎可以用它加速對數(shù)據(jù)的檢索,索引是唯一的,在創(chuàng)建時(shí)可以以指定單個(gè)列或是多個(gè)列。缺點(diǎn)是它減慢了數(shù)據(jù)錄入的速度,同時(shí)也增加了數(shù)據(jù)庫的尺寸大小。
# 主鍵,外鍵,索引的區(qū)別?
主鍵:
- 唯一標(biāo)識(shí)一條記錄,不可重復(fù),不可為`NULL`。 - 用來保證數(shù)據(jù)的完整性。 - 只能有一個(gè)。
外鍵:
- 表的外鍵是另一個(gè)表的主鍵,外鍵可以重復(fù),可以為空。 - 用來和其他表建立聯(lián)系。 - 一個(gè)表可以有多個(gè)外鍵。
索引:
- 該字段沒有重復(fù)值,可以有一個(gè)是空值。 - 提高查詢效率排序速度。 - 一個(gè)表可以有多個(gè)唯一索引。
# 對`SQL`語句的優(yōu)化方法 1. 避免在索引列上使用計(jì)算。 2. 避免在索引列上使用`IS NULL`和`IS NOT NULL`。 3. 對查詢進(jìn)行優(yōu)化,盡量避免全表掃描,首先因該考慮在`where`和`order by`涉及的列上建立索引。 4. 避免在`where`子句對字段進(jìn)行null值判斷,這件導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。 5. 避免在`where`子句中對字段進(jìn)行表達(dá)式操作,也會(huì)導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。
# `SQL`語句中“相關(guān)子查詢”和“非相關(guān)子查詢”有什么區(qū)別 如果你想加載一篇你寫過的.md文件,在上方工具欄可以選擇導(dǎo)入功能進(jìn)行對應(yīng)擴(kuò)展名的文件導(dǎo)入, 繼續(xù)你的創(chuàng)作。
子查詢:嵌套在其他查詢中的查詢。
非相關(guān)子查詢:
- 非相關(guān)子查詢是獨(dú)立于外部查詢的子查詢,子查詢總共執(zhí)行一次,執(zhí)行完畢后將值傳遞給外部的查詢。
相關(guān)子查詢:
- 相關(guān)子查詢的執(zhí)行依賴于外部的查詢數(shù)據(jù),外部查詢執(zhí)行一次,子查詢就會(huì)執(zhí)行一次。
【所以非相關(guān)子查詢比相關(guān)子查詢效率高】
# `char`和`varchar`的區(qū)別
- char`類型的數(shù)據(jù)列里,每個(gè)值都占`M`個(gè)字節(jié),如果長度小于`M`,就會(huì)在它的右邊用空格字符進(jìn)行補(bǔ)足(在檢索操作中填補(bǔ)出來的空格符將會(huì)被去掉)。 - `vachar`類型的數(shù)據(jù)列里,每個(gè)值只占用剛好夠用的字節(jié)再加上一個(gè)用來記錄長度的字節(jié),所以總長度為`L+1`字節(jié)。
# `SQL`問題
- 臟讀
- 在一個(gè)事務(wù)處理過程中讀取到了另一個(gè)未提交事務(wù)中的數(shù)據(jù)。
【例子】
A在一個(gè)轉(zhuǎn)賬事務(wù)中,轉(zhuǎn)了100給B,此時(shí)B讀到了這個(gè)轉(zhuǎn)賬的數(shù)據(jù),然后做了一些操作(給A發(fā)貨,或是其他),可是這個(gè)時(shí)候A的事務(wù)并沒有提交,如果A回滾了事務(wù),那這就是臟讀。
- 不可重復(fù)讀
- 對數(shù)據(jù)庫中的某個(gè)數(shù)據(jù),一個(gè)事務(wù)范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值,是由于在查詢間隔,被另一個(gè)事務(wù)修改并提交了。
【例子】
事務(wù)A在讀取某一數(shù)據(jù),而事務(wù)B立馬修改了這個(gè)數(shù)據(jù)并且提交了事務(wù)到數(shù)據(jù)庫,事務(wù)A再次讀取就得到了不同的結(jié)果。發(fā)生了不重復(fù)讀。
- 幻讀
- 事務(wù)非獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象。
【例子】
事務(wù)A對一個(gè)表中所有的行的某個(gè)數(shù)據(jù)項(xiàng)做了從“1”修改為“2”的操作,這時(shí)事務(wù)B又對這個(gè)表中插入了一行數(shù)據(jù)項(xiàng),這個(gè)數(shù)據(jù)的數(shù)值還是“1”并且提給了數(shù)據(jù)庫,如果事務(wù)A查看剛剛修改的數(shù)據(jù),會(huì)發(fā)現(xiàn)還有一數(shù)據(jù)沒有修改,而這行數(shù)據(jù)時(shí)事務(wù)B中添加的,就像產(chǎn)生的幻覺一樣。發(fā)生了幻讀。
# `MySQL`事務(wù)隔離級(jí)別
1. `read uncmmited`:讀到未提交數(shù)據(jù) - 最低級(jí)別,無法保證任情況 2. `read commited`:讀已提交 - 可避免臟讀 3. `repeatable read`:可重復(fù)讀 - 可避免臟讀、不可重復(fù)讀 4. `serializable`:串行事務(wù) - 可避免臟讀、不可重復(fù)讀、幻讀
**【`MySQL`默認(rèn)事務(wù)隔離級(jí)別為`Repeatable Read`(可重復(fù)讀)】**
# `MySQL`臨時(shí)表
什么是臨時(shí)表:臨時(shí)表是`MySQL`用于存儲(chǔ)中間結(jié)果集的表,臨時(shí)表只在當(dāng)前連接可看,當(dāng)連接關(guān)閉時(shí)會(huì)自動(dòng)刪除表并釋放所有空間。
為什么會(huì)產(chǎn)生臨時(shí)表:一般是因?yàn)閺?fù)雜的`SQL`導(dǎo)致臨時(shí)表被大量創(chuàng)建
- 進(jìn)行`union`查詢時(shí) - 用到`temptable`算法或者是`union`查詢中的視圖 - `ORDER BY`和`GROUP BY`的子句不一樣時(shí) - 表連接中,`ORDER BY`的列不是驅(qū)動(dòng)表中的 - `DISTINCT`查詢并且加上`ORDER BY`時(shí) - `SQL`中用到`SLQ_SMALL_RESULT`選項(xiàng)時(shí) - `RROM`中的子查詢
臨時(shí)表分為倆種:
- 內(nèi)存臨時(shí)表 - 采用的是`memory`存儲(chǔ)引擎 - 磁盤臨時(shí)表 - 菜用的是`myisam`存儲(chǔ)引擎
# 什么是視圖,游標(biāo)是什么?
視圖:視圖是一種虛擬表,具有和物理表相同的功能。可以對視圖表進(jìn)行增刪改查操作,視圖通常是有一個(gè)表或者多個(gè)表的子集。對視圖的修改不會(huì)影響基本表。
- 【使得我們獲取數(shù)據(jù)更容易,相比多表查詢】
游標(biāo):是對查詢出來的結(jié)果集作為一個(gè)單元來有效的處理。游標(biāo)可以定在該單元的特定行,從結(jié)果集的當(dāng)前行檢索一行或多行??梢詫Y(jié)果集當(dāng)前行進(jìn)行修改。
- 【一般不會(huì)使用,但需要逐條處理數(shù)據(jù)的時(shí)候,游標(biāo)顯得十分重要】
|