一、索引解決了什么問題
1,提升了查詢效率,它就像字典的目錄,讓我們可以快速查找到想要的數(shù)據(jù)。
2,提高了CPU使用率,由于索引的數(shù)據(jù)結(jié)構(gòu)是b+樹,帶著排序功能,所以一定程度上可以達到此目的。
hash 屬于無序的數(shù)據(jù)結(jié)構(gòu)。當(dāng)進行范圍查找的時候無效。
mysql 的索引類型跟存儲引擎是相關(guān)的,innodb 存儲引擎數(shù)據(jù)文件跟索引文件全部放在ibd文件中,而myisam的數(shù)據(jù)文件放在myd文件中,索引放在myi文件中,其實區(qū)分聚簇索引和非聚簇索引的非常簡單。只要判斷數(shù)據(jù)跟索引是否存儲在一起就可以了。innodb 存儲引擎在進行數(shù)據(jù)插入的時候,數(shù)據(jù)必須要跟索引放在一起,如果有主鍵就使用主鍵,沒有主鍵就使用唯一建沒有唯一索引就使用6字節(jié)的rowid,因此跟數(shù)據(jù)綁定在一起的就是聚簇索引。而為了避免數(shù)據(jù)坑余存儲,其他的索引的葉子節(jié)點中存儲的都是聚簇索引的key值,因此innodb中既有聚簇索引也有非聚簇索引,而myisam中只有非聚簇索引。
- innodb 的四大特性。
一般3-4層的b+tree足以支持千萬級別的數(shù)據(jù)量存儲
索引設(shè)計的時候盡可能讓key占用存儲空間。
其他索引的葉子節(jié)點中存儲的數(shù)據(jù)不在是整行的記錄,而是聚簇索引的id值。
二、索引帶來了什么問題
1,占用了磁盤空間,創(chuàng)建索引會占用物理空間的。
2,降低了增刪改的效率,為什么這么說呢,因為索引結(jié)構(gòu)是
b+樹,每次操作都會btree都會進行一次排序,這便影響了效率
3,不適用于任何場景,比如數(shù)據(jù)量少的表或者修改操作頻繁的字段
1、常用索引類型:
主鍵索引:主鍵,值是唯一的,不為null
唯一索引:union,值是唯一的,可為null(這也是和主鍵索引的區(qū)別)
單值索引:index,單個字段,但是一個表可以有多個單值索引
復(fù)合索引:index, 多個列組成的索引,類似二級目錄,先查找第一個字段,查到數(shù)據(jù)后再找第二個
8.索引有哪幾種類型?
1)普通索引 NORMAL
- 這是最基本的索引類型,基于普通字段建立的索引,沒有任何限制。
CREATE INDEX <索引的名字> ON tablename (字段名);
ALTER TABLE tablename ADD INDEX [索引的名字] (字段名);
CREATE TABLE tablename ( [...], INDEX [索引的名字] (字段名) );
2)唯一索引 UNIQUE
- 與"普通索引"類似,不同的就是:索引字段的值必須唯一,但允許有空值 。
CREATE UNIQUE INDEX <索引的名字> ON tablename (字段名);
ALTER TABLE tablename ADD UNIQUE INDEX [索引的名字] (字段名);
CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (字段名) ;
3)主鍵索引 PRIMARY KEY
- 它是一種特殊的唯一索引,不允許有空值。在創(chuàng)建或修改表時追加主鍵約束即可,每個表只能有一個主鍵。
CREATE TABLE tablename ( [...], PRIMARY KEY (字段名) );
ALTER TABLE tablename ADD PRIMARY KEY (字段名);
4)復(fù)合索引
- 用戶可以在多個列上建立索引,這種索引叫做組復(fù)合索引(組合索引)。復(fù)合索引可以代替多個單一索引,相比多個單一索引復(fù)合索引所需的開銷更小。
CREATE INDEX <索引的名字> ON tablename (字段名1,字段名2...);
ALTER TABLE tablename ADD INDEX [索引的名字] (字段名1,字段名2...);
CREATE TABLE tablename ( [...], INDEX [索引的名字] (字段名1,字段名2...) );
-
復(fù)合索引使用注意事項:
- 何時使用復(fù)合索引,要根據(jù)where條件建索引,注意不要過多使用索引,過多使用會對更新操作效率有很大影響。
-
如果表已經(jīng)建立了(col1,col2),就沒有必要再單獨建立(col1);如果現(xiàn)在有(col1)索引,如果查詢需要col1和col2條件,可以建立(col1,col2)復(fù)合索引,對于查詢有一定提高。
5) 全文索引
查詢操作在數(shù)據(jù)量比較少時,可以使用like模糊查詢,但是對于大量的文本數(shù)據(jù)檢索,效率很低。如果使用全文索引,查詢速度會比like快很多倍。
在MySQL 5.6 以前的版本,只有MyISAM存儲引擎支持全文索引,從MySQL 5.6開始MyISAM和InnoDB存儲引擎均支持。
CREATE FULLTEXT INDEX <索引的名字> ON tablename (字段名);
ALTER TABLE tablename ADD FULLTEXT [索引的名字] (字段名);
CREATE TABLE tablename ( [...], FULLTEXT KEY [索引的名字] (字段名) ;
全文索引方式有自然語言檢索 IN NATURAL LANGUAGE MODE和布爾檢索 IN BOOLEAN MODE兩種
和常用的like模糊查詢不同,全文索引有自己的語法格式,使用 match 和 against 關(guān)鍵字,比如
SELECT * FROM users3 WHERE MATCH(NAME) AGAINST('aabb');
-- * 表示通配符,只能在詞的后面
SELECT * FROM users3 WHERE MATCH(NAME) AGAINST('aa*' IN BOOLEAN MODE);
全文索引使用注意事項:
- 全文索引必須在字符串、文本字段上建立。
- 全文索引字段值必須在最小字符和最大字符之間的才會有效。(innodb:3-84;myisam:4-84)
2、如何創(chuàng)建,刪除,查看索引的格式,下面參考一下即可
- 創(chuàng)建:create 索引類型 索引名稱 on student(s_name);
- 刪除: drop index 索引名 on 表名;
- 查看: show index from 表名
索引可以大大提高MySQL的檢索速度。
避免對索引字段進行計算操作
◆避免在索引字段上使用not,<>,!=
◆避免在索引列上使用IS NULL和IS NOT NULL
◆避免在索引列上出現(xiàn)數(shù)據(jù)類型轉(zhuǎn)換
◆避免在索引字段上使用函數(shù)
◆避免建立索引的列中使用空值。
(1)索引分 單列索引 和 組合索引。
1、單列索引,即一個索引只包含單個列,一個表可以有多個單列索引,但這不是組合索引。
2、組合索引,即一個索引包含多個列。
(4)索引缺點:
1、雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,
如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數(shù)據(jù),
還要保存一下索引文件。過多的使用索引將會造成濫用
索引種類 - 普通索引:僅加速查詢
- 唯一索引:加速查詢 + 列值唯一(可以有null)
- 主鍵索引:加速查詢 + 列值唯一(不可以有null)+ 表中只有一個
- 組合索引:多列值組成一個索引,專門用于組合搜索,其效率大于索引合并
- 全文索引:對文本的內(nèi)容進行分詞,進行搜索。
索引對數(shù)據(jù)庫的影響
聚集索引,非聚集索引
MyISAM的索引與行記錄是分開存儲的,叫做非聚集索引(UnClustered Index)。
MyISAM的索引是一個單獨的文件,數(shù)據(jù)也是一個單獨的文件,索引和存儲的數(shù)據(jù)分離。每一個索引都會查找同一份數(shù)據(jù)。獨立運行的。
InnoDB的主鍵索引與行記錄是存儲在一起的,故叫做聚集索引(Clustered Index):
索引的設(shè)計原則有哪些?
在進行索引設(shè)計的時候,應(yīng)該保證索引字段占用的空間越小越好,這只是一個大的方向,還有一些細節(jié)需要注意:
1.適合索引的列時出現(xiàn)在where字句中的列,或者連接子句中指定的列
2基數(shù)比較小的表,索引效果比較差,沒有必要建立索引
3早選擇索引的時候,越短越好,可以指定某列的一部分,沒有必要全部字段的值。
4不要給表中的每一個字段都創(chuàng)建索引,并不是索引越多越好
5定義有外鍵的數(shù)據(jù)列一定要創(chuàng)建索引
6更新頻繁的字段不要有索引
7創(chuàng)建的索引的列不要過多,可以創(chuàng)建組合索引,但是組合索引的列的個數(shù)不建議太多
8大文本,大的對象不適合創(chuàng)建索引?
回表操作
id,name ,age,gender
id 主鍵,name普通索引
select * from table where name='zhang';
先根據(jù)name b+tree匹配到對應(yīng)的葉子節(jié)點,查詢到對應(yīng)行記錄
的id值,在根據(jù)id去id的b+tree中檢索整行的記錄,這個過程就稱為回表操作, 要盡量避免回表操作。
索引覆蓋
覆蓋索引是一種避免回表查詢的優(yōu)化策略: 只需要在一棵索引樹上就能獲取SQL所需的所有列數(shù)據(jù),無需回表,速度更快。**
具體的實現(xiàn)方式:
將被查詢的字段建立普通索引或者聯(lián)合索引*,這樣的話就可以直接返回索引中的的數(shù)據(jù),不需要再通過聚集索引去定位行記錄,避免了回表的情況發(fā)生。
select id ,name from table where name='zhang';
先根據(jù)name的值去nanme b+tree 檢索對應(yīng)的記錄,能獲取到id的屬性值,索引的葉子節(jié)點中包含了
查詢的所有列,此時不需要回表,這個過程就成為索引覆蓋,using idex 的提示信息,推薦使用
在某些場景中,可以考慮將要查詢的所有列都變成組合索引。此時使用索引覆蓋,加快查詢效率。
索引哪些情況下會失效?
1. 查詢條件包含 or,會導(dǎo)致索引失效。
2. 隱式類型轉(zhuǎn)換,會導(dǎo)致索引失效,例如 age 字段類型是 int,我們 where age = “1”,這樣就會觸發(fā)隱式類型轉(zhuǎn)換
3. like 通配符會導(dǎo)致索引失效,注意:”ABC%” 不會失效,會走 range 索引,”% ABC” 索引會失效
4. 聯(lián)合索引,查詢時的條件列不是聯(lián)合索引中的第一個列,索引失效。
5. 對索引字段進行函數(shù)運算。
6. 對索引列運算(如,+、-、*、/),索引失效。
7. 索引字段上使用(!= 或者 < >,not in)時,會導(dǎo)致索引失效。
8. 索引字段上使用 is null, is not null,可能導(dǎo)致索引失效。
9. 相 join 的兩個表的字符編碼不同,不能命中索引,會導(dǎo)致笛卡爾積的循環(huán)計算
10. mysql 估計使用全表掃描要比使用索引快,則不使用索引。
索引下推
select id ,name from table where name='zhang' and age=12;
沒有索引下推之前:
先根據(jù)name 從存儲引擎中拉取數(shù)據(jù)到server層,然后在server層中對age進行數(shù)據(jù)過濾
有了索引下推之后
根據(jù)name和age兩個條件來做數(shù)據(jù)篩選,將篩選之后的結(jié)果返回給server層
索引的優(yōu)化:
一般我們并不是出現(xiàn)了問題菜進行優(yōu)化的,在進行數(shù)據(jù)庫建模和數(shù)據(jù)庫設(shè)
計的時候會預(yù)先考慮到一些優(yōu)化的問,
比如表字段的類型,長度等,包括創(chuàng)建合適的索引等方式,但是這種方式只
能提前的預(yù)防。并不一定能解決索引的問題索引
當(dāng)我們生產(chǎn)的環(huán)境中出現(xiàn)sql問題的時候我們從數(shù)據(jù)庫的性能監(jiān)控,
索引的創(chuàng)建和維護,sql的語句調(diào)整。參數(shù)的設(shè)置,
性能的監(jiān)控會選擇show profiles,performenace ,schema來檢測
mysql為什么要主從復(fù)制
1.在復(fù)雜的系統(tǒng)中,有這么一個情景。有一句sql語句需要鎖表。導(dǎo)致暫時不能使用讀的服務(wù),
那么就很影響運行中的業(yè)務(wù),使用主從復(fù)制,讓主庫負(fù)責(zé)寫,從庫負(fù)責(zé)讀,這樣主庫出現(xiàn)了縮表的情景,
通過讀從庫也可以保證業(yè)務(wù)的正常運作。
2.做數(shù)據(jù)的熱備
3.架構(gòu)的擴展,業(yè)務(wù)量越大。I/O訪問頻率過高,單機無法滿足,
此時做多庫的存儲,降低磁盤I/O 訪問的頻率,提高單個機器的I/0性能。
bin log基本概念
- binlog是一個二進制格式的文件,用于記錄用戶對數(shù)據(jù)庫更新的SQL語句信息,例如更改數(shù)據(jù)庫表和更改內(nèi)容的SQL語句都會記錄到binlog里,但是不會記錄SELECT和SHOW這類操作。
- binlog在MySQL的Server層實現(xiàn)(引擎共用)
- binlog為邏輯日志,記錄的是一條SQL語句的原始邏輯
- binlog不限制大小,追加寫入,不會覆蓋以前的日志.
- 默認(rèn)情況下,binlog日志是二進制格式的,不能使用查看文本工具的命令(比如,cat,vi等)查看,而使用mysqlbinlog解析查看。
bin log的作用
- 主從復(fù)制:在主庫中開啟Binlog功能,這樣主庫就可以把Binlog傳遞給從庫,從庫拿到Binlog后實現(xiàn)數(shù)據(jù)恢復(fù)達到主從數(shù)據(jù)一致性。
- 數(shù)據(jù)恢復(fù):通過mysqlbinlog工具來恢復(fù)數(shù)據(jù)。
MySQL的binlog有幾種日志格式?分別有什么區(qū)別?
binlog日志有三種模式
1)ROW(row-based replication, RBR):日志中會記錄每一行數(shù)據(jù)被修改的情況,然后在slave端對相同的數(shù)據(jù)進行修改。
- 優(yōu)點:能清楚記錄每一個行數(shù)據(jù)的修改細節(jié),能完全實現(xiàn)主從數(shù)據(jù)同步和數(shù)據(jù)的恢復(fù)。而且不會出現(xiàn)某些特定情況下存儲過程或function無法被正確復(fù)制的問題。
- 缺點:批量操作,會產(chǎn)生大量的日志,尤其是alter table會讓日志量暴漲。
2)STATMENT(statement-based replication, SBR):記錄每一條修改數(shù)據(jù)的SQL語句(批量修改時,記錄的不是單條SQL語句,而是批量修改的SQL語句事件),
slave在復(fù)制的時候SQL進程會解析成和原來master端執(zhí)行過的相同的SQL再次執(zhí)行。簡稱SQL語句復(fù)制。
- 優(yōu)點:日志量小,減少磁盤IO,提升存儲和恢復(fù)速度
- 缺點:在某些情況下會導(dǎo)致主從數(shù)據(jù)不一致,比如last_insert_id()、now()等函數(shù)。
3)MIXED(mixed-based replication, MBR):以上兩種模式的混合使用,一般會使用STATEMENT模式保存binlog,
對于STATEMENT模式無法復(fù)制的操作使用ROW模式保存binlog,MySQL會根據(jù)執(zhí)行的SQL語句選擇寫入模式。
企業(yè)場景如何選擇binlog的模式
- 如果生產(chǎn)中使用MySQL的特殊功能相對少(存儲過程、觸發(fā)器、函數(shù))。選擇默認(rèn)的語句模式,Statement。
- 如果生產(chǎn)中使用MySQL的特殊功能較多的,可以選擇Mixed模式。
- 如果生產(chǎn)中使用MySQL的特殊功能較多,又希望數(shù)據(jù)最大化一致,此時最好Row 模式;但是要注意,該模式的binlog日志量增長非常快.
怎么處理mysql的慢查詢?
1.開啟慢查詢?nèi)罩荆瑴?zhǔn)確定位到哪個sql語句出現(xiàn)了問題
2.分析sql語句,看看是否load了額外的數(shù)據(jù)。可能是查詢了多余的行并且拋棄掉了。可能是加載了
許多結(jié)果中并不需要的列。對語句進行分析及重寫。
3.分析語句的執(zhí)行計劃,然后獲得其使用索引的情況。之后修改語句或者修
改索引。使得語句中盡可能的命中索引
4.如果對語句的優(yōu)化已經(jīng)無法進行,可以考慮表中的數(shù)據(jù)量是否太大,如果
是的話,可以進行橫向或者縱向分表。
什么是mysql的主從復(fù)制?
mysql 主從復(fù)制時指數(shù)據(jù)可以從一個mysql數(shù)據(jù)庫服務(wù)器主節(jié)點復(fù)制帶哦
一個或多個從節(jié)點。mysql默認(rèn)采取異步的復(fù)制方式
(同步的話效率太低,是要提夠?qū)崟r查詢的支持)
這樣從節(jié)點的不用一直訪問主服務(wù)器的來跟新自己的數(shù)據(jù)。數(shù)據(jù)的更新可
以在遠程連接上,從節(jié)點可以復(fù)制主數(shù)據(jù)庫中的所有數(shù)據(jù)庫或者特定的數(shù)據(jù) 庫,或者特定的表。
什么是分庫分表?什么時候進行分庫分表?
什么是分庫分表
簡單來說,就是指通過某種特定的條件,將我們存放在同一個數(shù)據(jù)庫中的數(shù)據(jù)分散存放到多個數(shù)據(jù)庫(主機)上面,以達到分散單臺設(shè)備負(fù)載的效果。
- 分庫分表解決的問題
分庫分表的目的是為了解決由于數(shù)據(jù)量過大而導(dǎo)致數(shù)據(jù)庫性能降低的問題,將原來單體服務(wù)的數(shù)據(jù)庫進行拆分.將數(shù)據(jù)大表拆分成若干數(shù)據(jù)表組成,使得單一數(shù)據(jù)庫、單一數(shù)據(jù)表的數(shù)據(jù)量變小,從而達到提升數(shù)據(jù)庫性能的目的。 - 什么情況下需要分庫分表
- 單機存儲容量遇到瓶頸.
- 連接數(shù),處理能力達到上限.
注意:
分庫分表之前,要根據(jù)項目的實際情況 確定我們的數(shù)據(jù)量是不是夠大,并發(fā)量是不是夠大,來決定是否分庫分表.
數(shù)據(jù)量不夠就不要分表,單表數(shù)據(jù)量超過1000萬或100G的時候, 速度就會變慢(官方測試),
分庫分表包括: 垂直分庫、垂直分表、水平分庫、水平分表 四種方式。
垂直分庫
- 數(shù)據(jù)庫中不同的表對應(yīng)著不同的業(yè)務(wù),垂直切分是指按照業(yè)務(wù)的不同將表進行分類,分布到不同的數(shù)據(jù)庫上面
- 將數(shù)據(jù)庫部署在不同服務(wù)器上,從而達到多個服務(wù)器共同分?jǐn)倝毫Φ男Ч?/li>
垂直分表
表中字段太多且包含大字段的時候,在查詢時對數(shù)據(jù)庫的IO、內(nèi)存會受到影響,同時更新數(shù)據(jù)時,產(chǎn)生的binlog文件會很大,MySQL在主從同步時也會有延遲的風(fēng)險
- 將一個表按照字段分成多表,每個表存儲其中一部分字段。
- 對職位表進行垂直拆分, 將職位基本信息放在一張表, 將職位描述信息存放在另一張表
垂直拆分帶來的一些提升
- 解決業(yè)務(wù)層面的耦合,業(yè)務(wù)清晰
- 能對不同業(yè)務(wù)的數(shù)據(jù)進行分級管理、維護、監(jiān)控、擴展等
- 高并發(fā)場景下,垂直分庫一定程度的提高訪問性能
- 垂直拆分沒有徹底解決單表數(shù)據(jù)量過大的問題
水平分庫
- 將單張表的數(shù)據(jù)切分到多個服務(wù)器上去,每個服務(wù)器具有相應(yīng)的庫與表,只是表中數(shù)據(jù)集合不同。 水平分庫分表能夠有效的緩解單機和單庫的性能瓶頸和壓力,突破IO、連接數(shù)、硬件資源等的瓶頸.
- 簡單講就是根據(jù)表中的數(shù)據(jù)的邏輯關(guān)系,將同一個表中的數(shù)據(jù)按照某種條件拆分到多臺數(shù)據(jù)庫(主機)上面, 例如將訂單表 按照id是奇數(shù)還是偶數(shù), 分別存儲在不同的庫中。
水平分表 - 針對數(shù)據(jù)量巨大的單張表(比如訂單表),按照規(guī)則把一張表的數(shù)據(jù)切分到多張表里面去。 但是這些表還是在同一個庫中,所以庫級別的數(shù)據(jù)庫操作還是有IO瓶頸。
-
總結(jié)
- 垂直分表: 將一個表按照字段分成多表,每個表存儲其中一部分字段。
- 垂直分庫: 根據(jù)表的業(yè)務(wù)不同,分別存放在不同的庫中,這些庫分別部署在不同的服務(wù)器.
- 水平分庫: 把一張表的數(shù)據(jù)按照一定規(guī)則,分配到不同的數(shù)據(jù)庫,每一個庫只有這張表的部分?jǐn)?shù)據(jù).
- 水平分表: 把一張表的數(shù)據(jù)按照一定規(guī)則,分配到同一個數(shù)據(jù)庫的多張表中,每個表只有這個表的部分?jǐn)?shù)據(jù).
46.count(列名)、count(1)和 count(*)有什么區(qū)別?
進行統(tǒng)計操作時,count中的統(tǒng)計條件可以三種選擇:
EXPLAIN SELECT COUNT(*) FROM user;
EXPLAIN SELECT COUNT(列名) FROM user;
EXPLAIN SELECT COUNT(1) FROM user;
執(zhí)行效果上:
- count(*) 包括了所有的列,在統(tǒng)計時 不會忽略列值為null的數(shù)據(jù)。
- count(1) 用1表示代碼行,在統(tǒng)計時,不會忽略列值為null的數(shù)據(jù)。
- count(列名)在統(tǒng)計時,會忽略列值為空的數(shù)據(jù),就是說某個字段的值為null時不統(tǒng)計。
執(zhí)行效率上:
- InnoDB引擎:count(字段) < count(1) = count(*)
- InnoDB通過遍歷最小的可用二級索引來處理select count(*) 語句,除非索引或優(yōu)化器提示指示優(yōu)化器使用不同的索引。如果二級索引不存在,則通過掃描聚集索引來處理。
- InnoDB已同樣的方式處理count(1)和count(*)
- MyISAM引擎:count(字段) < count(1) <= count(*)
- MyISAM存儲了數(shù)據(jù)的準(zhǔn)確行數(shù),使用
count(*)會直接讀取該行數(shù), 只有當(dāng)?shù)谝涣卸x為NOT NULL時,count(1),才會執(zhí)行該操作,所以優(yōu)先選擇count(*)
- MyISAM存儲了數(shù)據(jù)的準(zhǔn)確行數(shù),使用
- count(列名) 會遍歷整個表,但不同的是,它會先獲取列,然后判斷是否為空,然后累加,因此count(列名)性能不如前兩者。
注意:count(*),這是SQL92 定義的標(biāo)準(zhǔn)統(tǒng)計行數(shù)的語法,跟數(shù)據(jù)庫無關(guān),與NULL也無關(guān)。而count(列名) 是統(tǒng)計列值數(shù)量,不計NULL,相同列值算一個。