MySQL相關

MySQL

SQL

  1. distinct 去重
  2. 起別名:AS 或者 空格
  3. 模糊查詢
    • like:%匹配任意字符(含0個)_匹配單個字符
    • between and:閉區間
    • in (value1, value2, ...):判斷是否位於列表
    • is null | is not null
  4. 排序查詢:order by field1 field2 asc|desc能夠每一列都按照不一樣的升序/降序進行排列,默認爲升序。除了字段以外,還可使用表達式、函數、別名進行排序。order by 通常放在最後,除了 limit 以外。
  5. 分組查詢:group by expression
    • select 分組函數,fields from tablename [where] group by 分組列表[having][order by]
    • select 後接的必須是分組函數、group by 後出現的字段
    • 分組前篩選,數據來源於原始表,使用 where 關鍵字,而且位於 group by 的前邊
    • 分組後篩選,數據爲分組後的結果集,使用 having 語句,而且位於 group by 的後邊
  6. 鏈接查詢
    • select 查詢列表 from t1 [鏈接類型] join t2 on 鏈接條件
    • 內鏈接: inner join
      • 等值鏈接
      • 非等值鏈接
      • 自鏈接:至關於等值鏈接,鏈接的表均爲同一張表
    • 外鏈接:
      • 用於查詢一個表中有,另外一個表中沒有的記錄
      • 外鏈接查詢結果爲主表中的全部記錄。若是從表中有與之匹配的,則顯示匹配值;沒有匹配的,顯示null。也就是說,外鏈接的查詢結果是內鏈接結果加上主表中有從表中沒有的記錄。
      • 左外鏈接:left [outer] join,左邊的爲主表
      • 右外鏈接: right [outer] join,右邊爲主表
      • 全外鏈接: full [outer] join
    • 交叉鏈接:
      • cross join
      • 笛卡爾乘積
  7. 子查詢:出如今其餘語句中的 select語句,稱爲子查詢或內查詢。
    • 標量子查詢:返回結果只有一行一列
    • 多行子查詢:返回多行
      • IN/NOT IN:等於/不等於列表中的任意一個(能夠替代 EXISTS)
      • ANY/SOME:和子查詢返回的某一個值比較
      • ALL:和子查詢返回的全部值比較
  8. 分頁查詢
    • limit [offset] size,offset 表示起始索引,從0開始,默認爲0,size 表示個數
  9. 聯合查詢
    • union 將多條查詢語句的結果合併成一個結果
    • 要求各個查詢語句的列數是一致的
    • 各個查詢語句每一列的類型和順序最好一致
    • union 關鍵字默認去重,使用 union all 包含全部結果
  10. 插入語句:
    • insert into table (field1,...) values(value1,...)支持插入多行
    • insert into table set field1=value1 , field2=value2,...只能插入一行
  11. 修改語句
    • update table set filed=value,... where...
  12. 刪除語句
    • delete from table where...刪除一或多行
    • truncate table tablename
    • delete 刪除後,插入數據,自增列從斷點開始;truncate 從1開始,且在事務中支持回滾
    • truncate 刪除沒有返回值,delete 有返回值,在事務中不支持回滾

整體來講,查詢語法以下:mysql

SELECT DISTINCT select_list
FROM left_table join_type
JOIN right_table 
ON join_condition
WHERE where_condition
GROUP BY group_by_list
HAVING having_condition
ORDER BY order_by_condition
LIMIT offset size
複製代碼

約束

  1. NOT NULL:非空
  2. DEFAULT:設置默認值
  3. PRIMARY KEY:設置主鍵
  4. UNIQUE: 惟一,能夠爲空
  5. FOREIGN KEY:外鍵,用於保證該字段的值必須來自主表的關聯列的值。在從表中添加外鍵約束,用於引用主表中某列的值

外鍵:算法

  • 要求在從表設置外鍵關係
  • 從表的外鍵列的類型和主表的關聯列的類型要求一致或兼容,名稱無要求
  • 主表的關聯列必須是一個 key (主鍵或者惟一)
  • 插入數據,先插入主表,後插入從表
  • 刪除數據,先刪除從表,再刪除主表

事務

事務(Transaction)是併發控制的基本單位。所謂的事務,它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。sql

ACID

  • 原子性(Atomicity):事務是不可分割的最小單元,全部操做要麼所有提交成功,要麼所有回滾失敗。
  • 一致性(Consistency):數據庫在事務執行先後保持一致性。
  • 隔離性(Isolation):事務所作的修改在最終提交前,對其餘事務不可見。
  • 持久性:事務一旦提交,所作修改會永遠保持到數據庫,系統崩潰也不能丟失。

其中,一致性保證了事務的執行結果是正確的。在無併發狀況下,原子性保證了一致性。在併發狀況下,原子性和隔離性保證了一致性。持久性用來應對數據庫崩潰。數據庫

併發一致性問題

  1. 丟失修改: 兩個事務都對一個數據進行修改,後者覆蓋了前者的修改。
  2. 讀髒數據: T1 修改數據,T2讀取了該數據後,T1又撤銷修改,T2讀到的是髒數據。
  3. 不可重複讀: T2讀取數據,T1修改了該數據後,T2再次讀取,兩次結果不一樣。
  4. 幻讀:T1讀取某個範圍的數據,T2在範圍中插入新數據,T1再次讀取該範圍的數據,兩次讀取的結果不一樣。

隔離級別

  • 未提交讀(read uncommitted):事務中的修改,即便沒有提交,對其餘事務也是可見的。
  • 提交讀(read committed):一個事務只能讀取已經提交的事務所作的修改。也就是事務修改提交前其餘事務不可見。能夠解決髒讀問題。
  • 可重複讀(repeatable read):保證同一事務中屢次讀取一樣數據的結果同樣。能夠解決髒讀和不可重複讀問題。
  • 可串行化(serializable):強制事務串行執行。

隱式事務與顯式事務

隱式事務:mysql 默認開啓了 autocommit 選項,會隱式提交事務。express

顯式事務:緩存

  1. 開啓事務:set autocommit = 0; start transaction;該語句可選。
  2. 事務中的sql語句(select, insert, update, delete)
  3. 結束事務:commit;提交 rollback;回滾

範式

第一範式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。安全

第二範式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些字段決定非關鍵字段的狀況),也即全部非關鍵字段都徹底依賴於任意一組候選關鍵字。bash

第三範式(3NF):在第二範式的基礎上,數據表中若是不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三範式。所謂傳遞函數依賴,指的是如 果存在"A → B → C"的決定關係,則C傳遞函數依賴於A。所以,知足第三範式的數據庫表應該不存在以下依賴關係: 關鍵字段 → 非關鍵字段 x → 非關鍵字段y服務器

視圖

視圖是一種虛擬的表,能夠和普通表同樣使用,行和列的數據來自定義視圖的查詢中使用的表,在使用視圖的時候動態生成,只保存 sql 邏輯,不保存查詢結果。能夠應用於多個地方用到一樣的查詢結果的情景。數據結構

優勢:

  • 能夠重用 sql 語句
  • 簡化複雜的 sql 操做
  • 保護數據,提升安全性

建立視圖: create view 視圖名 as 查詢語句

修改視圖: create or replace view 視圖名 as 查詢語句或者 alter view 視圖名 as 查詢語句

刪除視圖:drop view 視圖名

查看視圖:desc 視圖名show create view 視圖名

mysql 架構介紹

  1. 鏈接層:這一層是客戶端和鏈接服務,包含本地 socket 通訊和大多數基於 C/S 工具實現的相似 tcp/ip 通訊。用於完成鏈接處理、受權認證和安全方案。在該層上引入了線程池的概念。
  2. 服務層:完成核心服務功能。SQL接口、緩存查詢、SQL 分析和優化以及部份內置函數的執行。在該層,服務器會解析查詢並建立響應的內部解析樹,並對其完成響應的優化如肯定查詢表的順序,是否利用索引等,最好生成執行操做。若是是 select 語句,還會查詢內部緩存。
  3. 引擎層:負責數據的存儲和提取,服務器經過 API 與存儲引擎通訊。

索引

索引是一種特殊的文件,包含對數據表裏全部記錄的引用指針。

MySQL 官方定義:索引是幫助 MySQL 高效獲取數據的數據結構。在數據自己以外,數據庫還維護着一個知足特定查找算法的數據結構,這些數據結構以某種方式指向數據,這種數據結構就是索引。索引能夠理解爲已排序的快速查找數據結構。平時所說的索引,若是沒有特別指明,都是指的是 B+ 樹。

通常來講索引自己也很大,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲在磁盤上。

優勢:

  • 提升數據檢索的效率,下降數據庫的 IO 成本
  • 經過索引對數據進行排序,下降數據排序的成本,下降了 CPU 的消耗
  • 建立惟一性索引,保證數據庫表中每一行數據的惟一性。
  • 加速表與表之間的鏈接

缺點:

  • 佔用空間
  • 下降了更新表的數據,調整數據的同時,還會調整索引信息

Mysql存儲基本知識

Mysql基本存儲結構是頁,各個數據頁組成雙向鏈表,每一個數據頁中的記錄又能夠組成一個單向鏈表。查找時,先遍歷雙向鏈表,定位到所在的頁。每一個數據頁都會爲所存儲的記錄生成頁目錄,經過主鍵查找會在頁目錄使用二分法定位到對應的槽,從槽中遍歷找到指定記錄。非主鍵搜索,會依次遍歷單鏈表中的每條記錄。

SQL 執行順序:

SELECT DISTINCT select_list
FROM left_table join_type
JOIN right_table 
ON join_condition
WHERE where_condition
GROUP BY group_by_list
HAVING having_condition
ORDER BY order_by_condition
LIMIT offset size
複製代碼

mysql 處理的順序:

FROM left_table
ON join_condition
join_type JOIN right_table
WHERE where_condition
GROUP BY group_by_list
HAVING having_condition
SELECT
DISTINCT select_list
ORDER BY order_by_condition
LIMIT offset size
複製代碼

建立索引

  1. 普通索引:一個索引只包含一個列
  2. 惟一索引:索引列的值必須惟一,但容許有空值
  3. 複合索引:一個索引包含多個列
  4. 全文索引:對大文本進行索引。必須是MyISAM引擎的數據表
  • 建立: CREATE [UNIQUE] INDEX indexName ON table(columnlist); 或者 ALTER table ADD [UNIQUE] INDEX [indexname] ON (columnlist)
  • 刪除DROP INDEX [indexname] on table
  • 查看SHOW INDEX FROM table

B+樹索引

B+ Tree 是基於 B Tree 和葉子節點順序訪問指針進行實現,它具備 B Tree 的平衡性,而且經過順序訪問指針來提升區間查詢的性能。

當沒有索引時,咱們須要遍歷雙向鏈表來定位所在的頁,如今經過索引,能夠很快定位到所在的頁上。底層採用B+樹實現。B+樹是平衡樹的一種,若是對這棵樹進行增刪改,須要從新維持平衡,有額外的開銷。

hash索引

採用hash算法,把鍵值換成hash值,只須要一次hash算法就能夠當即定位,速度快。

侷限:

  • 沒法利用索引進行排序
  • 不支持最左匹配
  • 哈希碰撞問題,大量重複鍵值效率低
  • 不支持範圍查詢

非彙集索引和彙集索引

  • 彙集索引是以主鍵建立的,非彙集索引是以非主鍵建立的。
  • 彙集索引中鍵值的邏輯順序決定了表中相應行的物理順序,非彙集索引則是數據存儲在一個地方,索引存儲在另外一個地方,索引帶有指針指向數據的存儲位置。
  • 彙集索引在葉子節點存儲表中的數據,非彙集索引在葉子節點存儲的主鍵和索引列值
  • 使用非彙集索引查詢出數據,在到葉子上的主鍵查到想要查找的數據,也稱爲二級索引。
  • 非彙集索引能夠是多列的。
  • 覆蓋索引:要查詢出的列和索引是對應的,不用再查彙集索引
  • 使用場景選擇

兩種引擎索引的比較

MyISAM: B+Tree葉節點的data域存放的是數據記錄的地址。在索引檢索的時候,首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,則取出其 data 域的值,而後以 data 域的值爲地址讀取相應的數據記錄。這被稱爲「非聚簇索引」。

InnoDB: 其數據文件自己就是索引文件。相比MyISAM,索引文件和數據文件是分離的,其表數據文件自己就是按B+Tree組織的一個索引結構,樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引。這被稱爲「聚簇索引(或彙集索引)」。而其他的索引都做爲輔助索引,輔助索引的data域存儲相應記錄主鍵的值而不是地址,這也是和MyISAM不一樣的地方。在根據主索引搜索時,直接找到key所在的節點便可取出數據;在根據輔助索引查找時,則須要先取出主鍵的值,再走一遍主索引。 所以,在設計表的時候,不建議使用過長的字段做爲主鍵,也不建議使用非單調的字段做爲主鍵,這樣會形成主索引頻繁分裂。

建立索引考慮因素

  1. 主鍵自動建立惟一索引
  2. 頻繁做爲查詢條件的字段
  3. 查詢中與其餘表關聯的字段,外鍵關係創建索引
  4. 查詢中排序的字段經過索引訪問會提升排序速度
  5. 查詢中統計或者分組字段
  6. 高併發下傾向於建立組合索引而不是單鍵索引
  7. where 條件裏用不到的字段不建立索引
  8. 頻繁更新的字段不適合作索引
  9. 表記錄少時不須要創建索引
  10. 常常增刪改的表不要創建索引
  11. 數據重複且分佈均勻的表字段創建索引沒有太大實際效果

索引使用注意點

  1. 索引應創建在那些將用於JOIN,WHERE判斷和ORDER BY排序的字段上
  2. 最左匹配原則:聯合索引只能用於查找key是否存在,遇到範圍查詢就不能進一步匹配了,後序退化爲線性查找。若有索引(a, b, c, d),查詢條件a = 1 and b = 2 and c > 3 and d = 4,則會在每一個節點依次命中a、b、c,沒法命中d。(很簡單:索引命中只能是相等的狀況,不能是範圍匹配) 。
  3. 應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描
  4. 應儘可能避免在 where 子句中使用 != 或 <> 操做符,不然將引擎放棄使用索引而進行全表掃描
  5. 應儘可能避免在 where 子句中使用 or 來鏈接條件,若是一個字段有索引,一個字段沒有索引,將致使引擎放棄使用索引而進行全表掃描
  6. in 和 not in 也要慎用,不然會致使全表掃描。對於連續的數值,能用 between 就不要用 in 了
  7. 模糊查詢:like keyword% 索引有效,其餘無效
  8. 儘可能避免在where子句中對字段進行函數操做
  9. 不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引
  10. 複合索引應儘量的讓字段順序與索引順序相一致,且必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引

索引失效

左鏈接 left join 中,左表全都有,left join 用於肯定如何從右表搜索行,則右表創建索引,效率更好。右鏈接同理。

  1. 全值匹配
  2. 最佳左前綴
  3. 不在索引列上作任何操做:計算、函數、類型轉換
  4. 存儲引擎不能使用索引中範圍條件右邊的列
  5. 儘可能使用覆蓋索引,減小 select *
  6. 在使用不等於的時候沒法使用索引,致使全表掃描
  7. is null, is not null 不能使用索引
  8. like %xxxlike %xxx%沒法使用索引,只有通配符卸載最右才能使用索引。當使用like %xx%時,可使用覆蓋索引,會使用到索引,可是類型爲 range
  9. 字符串不加單引號,由於會作隱式類型轉換
  10. 少用 or,用它鏈接時索引失效

建議:

  1. 單值索引,儘可能選擇針對當前查詢過濾性更好的索引
  2. 選擇組合索引,當前查詢中過濾性最好的字段在索引字段順序中,位置越靠前越好
  3. 選擇組合索引時,儘可能選擇考研可以包含當前 query 中的 where 子句中更多字段的索引
  4. 儘量經過分析和調整查詢語句的寫法來達到選擇合適索引的目的。

索引性能分析:Explain

Explain 關鍵字用來模擬優化器執行 SQL 查詢語句,從而知道 MySQL 是如何處理 SQL 語句的,從而分析查詢語句或者表結構的性能瓶頸。

使用 explain + sql 語句能夠查看對應的 SQL 語句的執行計劃。

  1. id
    • 是 select 查詢的序列號,包含一組數字,表示查詢中執行 select 子句或者操做表的順序
    • 當 id 相同時,執行順序由上到下
    • 若是有子查詢,id 的序號會遞增, id 值越大優先級越高,越先被執行
  2. select_type
    • 表明查詢的類型,用於區別普通查詢、聯合查詢、子查詢等複雜查詢
    • simple: 表示是簡單的查詢,不包含子查詢或者 union
    • primary: 查詢中若是包含任何複雜的子部分,最外層查詢被標記爲 primary
    • subquery: 表示 select 或者 where子查詢
    • derived: 在 from 中的子查詢,mysql 會遞歸執行這些子查詢,把結果放在臨時表
    • union: 若第二個 select 出如今 union 以後,被標記爲 union,若 union 包含在 from 的子查詢中,外層被標記爲 derived
    • union result: 從 union 表獲取結果的 select
  3. table: 顯示的該行數據關於的表名
  4. type
    • 顯示查詢使用了何種類型
    • system: 表只有一行記錄
    • const: 表示經過索引一次就找到了,用於比較主鍵或者惟一索引。由於只匹配一行數據,因此很快。若是將主鍵放在 where 列表,mysql 就能將該查詢轉換爲一個常量。
    • eq_ref: 惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配,常見於主鍵或者惟一索引掃描
    • ref: 非惟一性索引掃描,返回匹配某個單獨值得全部行,本質上也是一種索引訪問,可是可能會找到多個符合條件的行
    • range: 只檢索給定範圍的行,使用一個索引來選擇行。通常用於範圍查詢(<,>,between, in),比全表掃描要更快,不用掃描所有索引。
    • index: 全表掃描,可是遍歷的是索引樹,而非數據文件
    • ALL:全表掃描,遍歷數據文件
  5. possible_keys:
    • 顯示可能應用在該表的索引,查詢涉及到的字段上若是存在索引,則該索引被列出,但不必定被查詢實際使用
  6. key:
    • 實際使用的索引,若是爲 NULL,則沒有使用索引
    • 查詢中若是使用了覆蓋索引,則該索引僅出如今 key 列表
  7. key_len
    • 表示索引中使用的字節數,能夠經過該列計算查詢中使用的索引的長度,不損失精確性的狀況,長度越短越好
    • 顯示的值是索引字段的最大可能長度,並不是實際使用長度
  8. ref
    • 顯示索引的哪一列被使用了
  9. rows
    • 根據表統計信息及索引選用狀況,大體估算出找到所需記錄所需讀取的行數
  10. extra
    • using filesort: 說明 mysql 會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取
    • using temporary: 使用了臨時表保存中間結果,在對結果排序時使用臨時表,常見於 order by 和 group by
    • using index: 表示相應的 select 操做中使用了覆蓋索引,避免訪問了表的數據行。
      • 若是同時出現了 using where 表示索引被用來執行索引鍵值的查找;不然表示用來讀取數據而非執行查找動做
      • 覆蓋索引,也稱索引覆蓋,就是指 select 的數據列只用從索引中就能取得,不用讀取數據行,也就是查詢列被所創建的索引覆蓋

鎖機制

鎖分類

  1. 按照鎖的粒度分爲表級鎖和行級鎖。表級鎖粒度大,資源消耗小,加鎖快,不會死鎖,可是併發度低。行級鎖會減小數據庫操做的衝突,併發度高,加鎖開銷大,會死鎖。
  2. 按照是否可寫分爲共享鎖(讀鎖S)和排他鎖(寫鎖X)

死鎖及避免

InnoDB的行級鎖是基於索引實現的,若是查詢語句未命中任何索引,那麼InnoDB會使用表級鎖。不一樣於MyISAM老是一次性得到所需的所有鎖,InnoDB的鎖是逐步得到的,當兩個事務都須要得到對方持有的鎖,致使雙方都在等待,這就產生了死鎖。 咱們能夠採起如下方式避免死鎖:

  • 經過表級鎖來減小死鎖產生的機率;
  • 多個程序儘可能約定以相同的順序訪問表(這也是解決併發理論中哲學家就餐問題的一種思路);
  • 同一個事務儘量作到一次鎖定所須要的全部資源。

兩個引擎使用的鎖

MyISAM採用表級鎖(table-level locking)。 InnoDB支持行級鎖(row-level locking)和表級鎖,默認爲行級鎖。

查詢緩存

開啓查詢緩存後在一樣的查詢條件以及數據狀況下,會直接在緩存中返回結果。這裏的查詢條件包括查詢自己、當前要查詢的數據庫、客戶端協議版本號等一些可能影響結果的信息。所以任何兩個查詢在任何字符上的不一樣都會致使緩存不命中。

緩存創建以後,Mysql的查詢緩存系統會跟蹤查詢中涉及的每張表,若是這些表(數據或結構)發生變化,那麼和這張表相關的全部緩存數據都將失效。

緩存雖然可以提高數據庫的查詢性能,可是緩存同時也帶來了額外的開銷,每次查詢後都要作一次緩存操做,失效後還要銷燬。 所以,開啓緩存查詢要謹慎,尤爲對於寫密集的應用來講更是如此。若是開啓,要注意合理控制緩存空間大小。

存儲引擎比較

InnoDB

InnoDB的最大特點就是支持了ACID兼容的事務(Transaction)功能。

是 MySQL 默認的事務型存儲引擎,只有在須要它不支持的特性時,才考慮使用其它存儲引擎。

實現了四個標準的隔離級別,默認級別是可重複讀(REPEATABLE READ)。在可重複讀隔離級別下,經過多版本併發控制(MVCC)+ 間隙鎖(Next-Key Locking)防止幻影讀。

特色:

  • 支持行鎖,採用MVCC來支持高併發,有可能死鎖
  • 支持事務
  • 支持外鍵
  • 支持崩潰後的安全恢復
  • 不支持全文索引

MyISAM

如今大多數時候咱們使用的都是InnoDB存儲引擎,可是在某些狀況下使用MyISAM更好,好比:MyISAM更適合讀密集的表,而InnoDB更適合寫密集的的表。 在數據庫作主從分離的狀況下,常常選擇MyISAM做爲主庫的存儲引擎。

  • 不支持行鎖(MyISAM只有表鎖),讀取時對須要讀到的全部表加鎖,寫入時則對錶加排他鎖;
  • 不支持事務
  • 不支持外鍵
  • 不支持崩潰後的安全恢復
  • 在表有讀取查詢的同時,支持往表中插入新紀錄
  • 支持BLOB和TEXT的前500個字符索引,支持全文索引
  • 支持延遲更新索引,極大地提高了寫入性能
  • 對於不會進行修改的表,支持 壓縮表 ,極大地減小了磁盤空間的佔用

比較

使用show engines查詢引擎。

對比項 MyISAM InnoDB
主鍵和外鍵 不支持 支持
事務 不支持 支持
表鎖 行鎖,適合高併發操做
緩存 只緩存索引,不緩存真實數據 緩存索引以及真實數據,對內存要求較高
表空間

慢查詢分析

查詢優化

小表驅動大表

小的數據集驅動大的數據集

select * from A where id in(select id from B)
等價於:
for select id from B
    for select * from A where A.id = B.id
複製代碼

當 B 表的數據集必須小於 A 表的數據集時,用 in 優於 exists。

select * from A where exists (select * from B where B.id = A.id)
等價於:
for select * from A
    for select * from B where B.id=A.id
複製代碼

當 A 表的數據集小於 B 表的數據集時,用 exists 優於 in。

select ... from table where exists (subquery)
複製代碼

該語法的理解爲:將主查詢的數據,放到子查詢作條件驗證,根據驗證結果(TRUE 或 FALSE)來決定主查詢的數據結果是否得以保留。

  • EXISTS(subquery) 只返回 TRUE 或 FALSE,所以子查詢中的 SELECT * 也能夠是 SELECT 1 或其餘,由於在實際執行時會忽略 SELECT 清單,所以沒有區別
  • EXISTS 子查詢的實際執行過程可能通過了優化而不是理解上的逐條對比
  • EXISTS 子查詢每每也能夠用條件表達式、其餘子查詢或者 JOIN 來替代

order by 優化

MySQL 支持兩種方式的排序, FileSort 和 Index。其中 Index 效率更高,使用 MySQL 掃描索引自己完成排序。

ORDER BY 知足兩種狀況時,會使用 Index 方式進行排序。 :

  • ORDER BY 語句使用索引最左前列
  • 使用 WHERE 子句和 ORDER BY 子句條件列組合知足索引最左前列

所以,要儘量在索引列上完成排序操做,遵守索引的最佳左前綴原則。

若是 ORDER BY 不在索引列上, filesort 有兩種算法:MySQL 啓動雙路排序和單路排序。

  • 雙路排序:兩次掃描磁盤,讀取行指針和 order by 列,進行排序,而後掃描已經排序的列表,按照列表中的值從新從列表中讀取對應的數據輸出。
  • 單路排序:MySQL 4.1 以後使用。從磁盤讀取查詢須要的全部列,按照 order by 列在 buffer 對它們進行排序,而後掃描排序後的列表進行輸出。會使用更多的空間,由於把每一行都保存在內存之中了。

因爲單路排序要取出全部數據,可能致使每次只能取 buffer 大小的數據,從而須要屢次 IO 操做。

提升 order by 的速度:

  1. 不要使用 select * 。由於使用 select * 會取出全部的列數據,更容易把 buffer 佔滿,從而致使屢次 I/O.
  2. 嘗試提升 sort_buffer_size
  3. 嘗試提升 max_length_for_sort_data

group by 優化

group by 實質是先排序後分組,遵守索引創建的最佳左前綴。

當沒法使用索引列時,嘗試增大sort_buffer_sizemax_length_for_sort_data

where 高於 having,能寫在 where 限定的條件就不要去 having 限定了。

分佈式相關

切分

水平切分

又稱爲 Sharding,將同一個表中的記錄拆分到多個結構相同的表中,將數據分佈到集羣的不一樣節點上,緩解單個數據庫的壓力。

通常水平查分根據表中的某一字段(通常是主鍵)取模,將一張表的數據拆分到多個表。採用 hash(key)%N 的方法。使用單獨一個數據庫來存儲映射關係。

分片的選擇時取決於最頻繁的查詢SQL的條件,若是某個表的數據有明顯的時間特徵,則一般適合使用時間範圍分片。

能夠將原來的鏈接分解爲多個單表查詢,而後在用戶程序中進行鏈接。

優勢:

  • 不存在單個庫大數據和高併發的性能瓶頸
  • 應用端改造少
  • 提升系統穩定性和負載能力

缺點:

  • 事務一致性難以解決
  • 跨節點Join性能差,邏輯複雜
  • 數據屢次擴展難度和維護量極大

不少大表對MySQL這種關係型數據庫的需求並不大,並不要求ACID,能夠考慮將這些表歉意到NoSQL,解決水平擴展問題。如日誌類、監控類、統計類數據,非結構化或若結構化數據,對事務要求不強的數據等。

垂直切分

將一張表按列切分紅多個表,將數據庫中標的密集程度部署到不一樣的庫中。如電商數據庫切分紅商品數據庫和用戶數據庫。當一張表的字段過多時考慮垂直拆分,一般將一張表的字段拆分爲主表和擴展表。

主從複製

主從複製是用來創建一個和主數據庫徹底同樣的數據庫環境,稱爲從數據庫。主數據庫通常是準實時的業務數據庫。

好處:

  1. 主數據庫服務器故障後,能夠切換到從數據庫繼續工做,避免數據丟失。
  2. 架構擴展,業務量愈來愈大,作多庫的存儲,下降磁盤I/O訪問的頻率,提升單個機器的I/O性能。
  3. 讀寫分離,是數據庫能支撐更大的併發。

原理:

  1. 主數據庫的更新事件被記錄到二進制日誌(bin-log)中
  2. 從庫鏈接到主庫
  3. 主庫建立一個binlog dump thread線程,把binlog內容發送到從庫
  4. 從庫啓動,建立I/O線程,讀取主庫傳過來的binlog內容並寫到relay log
  5. 從庫建立一個SQL線程,從relay log讀取內容,將更新內容寫入到從庫。

讀寫分離

基本原理是讓主數據庫處理增刪改操做,從數據庫處理查詢操做。數據庫複製被用來把事務性操做致使的變動同步到集羣中的從數據庫。

大多數業務每每讀多寫少,這時候數據庫的讀性能就會成爲性能瓶頸。

爲了解決讀的性能瓶頸,有多種解決方案。

  1. 使用緩存 讀寫分離經過多個讀庫,分攤了數據庫讀的壓力。經過緩存的使用,減小了數據庫讀的壓力。緩存的使用成本更低,開發更容易。可是,緩存若是掛掉,數據庫也會掛掉。讀寫分離能夠看作是緩存都解決不了時的一種解決方案。
  2. 水平切分 水平切分主要解決的是數據容量的瓶頸。例如訂單表,數據只增不減,歷史數據又必須留存,很是容易成爲性能的瓶頸。當單庫的容量成爲了瓶頸,但願提升數據庫的寫性能,下降單庫容量,就能夠採用水平切分。
相關文章
相關標籤/搜索