MySQL數據庫快問快答

前言

今天樓主給你們列一下關於數據庫幾個常見問題的要點,若是你們對其中的問題感興趣,能夠自行擴展研究。前端

1. UNION ALL 與 UNION 的區別

  • UNION和UNION ALL關鍵字都是將兩個結果集合併爲一個。mysql

  • UNION在進行表連接後會篩選掉重複的記錄,因此在表連接後會對所產生的結果集進行排序運算,刪除重複的記錄再返回結果。sql

  • 而UNION ALL只是簡單的將兩個結果合併後就返回。數據庫

  • 因爲UNION須要排序去重,因此 UNION ALL 的效率比 UNION 好不少。segmentfault

2. TRUNCATE 與 DELETE 區別

  • TRUNCATE 是DDL語句,而 DELETE 是DML語句。
  • TRUNCATE 是先把整張表drop調,而後重建該表。而 DELETE 是一行一行的刪除,因此 TRUNCATE 的速度確定比 DELETE 速度快。
  • TRUNCATE 不能夠回滾,DELETE 能夠。
  • TRUNCATE 執行結果只是返回0 rows affected,能夠解釋爲沒有返回結果。
  • TRUNCATE 會重置水平線(自增加列起始位),DELETE 不會。
  • TRUNCATE 只能清理整張表,DELETE 能夠按照條件刪除。
  • 通常情景下,TRUNCATE性能比DELETE好一點。

3. TIMESTAMP 與 DATETIME 的區別

相同點緩存

  • TIMESTAMP 列的顯示格式與 DATETIME 列相同。顯示列寬固定在19字符,而且格式爲YYYY-MM-DD HH:MM:SS

不一樣點性能

  • TIMESTAMP
    • 4個字節存儲,時間範圍:1970-01-01 08:00:01~2038-01-19 11:14:07
    • 值以UTC格式保存,涉及時區轉化,存儲時對當前的時區進行轉換,檢索時再轉換回當前的時區。
  • DATETIME
    • 8個字節存儲,時間範圍:1000-10-01 00:00:00~9999-12-31 23:59:59
    • 實際格式存儲,與時區無關。

4. 什麼是聯合索引

兩個或更多個列上的索引被稱做聯合索引,聯合索引又叫複合索引。mysql索引

5. 爲何要使用聯合索引

  • 減小開銷:建一個聯合索引(col1,col2,col3),實際至關於建了(col1),(col1,col2),(col1,col2,col3)三個索引。減小磁盤空間的開銷。
  • 覆蓋索引:對聯合索引(col1,col2,col3),若是有以下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那麼MySQL能夠直接經過遍歷索引取得數據,而無需回表,這減小了不少的隨機io操做。覆蓋索引是主要的提高性能的優化手段之一。
  • 效率高:索引列越多,經過索引篩選出的數據越少。有1000W條數據的表,有以下sql select from table where col1=1 and col2=2 and col3=3,假設假設每一個條件能夠篩選出10%的數據,若是隻有單值索引,那麼經過該索引能篩選出1000W*10%=100w條數據,而後再回表從100w條數據中找到符合col2=2 and col3= 3的數據,而後再排序,再分頁;若是是聯合索引,經過索引篩選出1000w*10%*10%*10%=1w,效率獲得明顯提高。

6. MySQL 聯合索引最左匹配原則

  • 在 MySQL 創建聯合索引時會遵循最左前綴匹配的原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配。
  • MySQL 會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
  • = 和 in 能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式。

7. 什麼是彙集和非彙集索引

  • 彙集索引就是以主鍵建立的索引。
  • 非彙集索引就是以非主鍵建立的索引。

8. 什麼是覆蓋索引

  • 覆蓋索引(covering index)指一個查詢語句的執行只用從索引頁中就可以取得(若是不是彙集索引,葉子節點存儲的是主鍵+列值,最終仍是要回表,也就是要經過主鍵再查找一次),避免了查到索引後,再作回表操做,減小I/O提升效率。
  • 能夠結合第10個問題更容易理解。

9. 什麼是前綴索引

前綴索引就是對文本的前幾個字符(具體是幾個字符在建立索引時指定)建立索引,這樣建立起來的索引更小。可是MySQL不能在ORDER BY或GROUP BY中使用前綴索引,也不能把它們用做覆蓋索引。優化

建立前綴索引的語法:spa

ALTER TABLE table_name ADD
KEY(column_name(prefix_length))
複製代碼

10. InnoDB 與 MyISAM 索引存儲結構的區別

  • MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。
  • 而在InnoDB中,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引,因此必須有主鍵,若是沒有顯示定義,自動爲生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整型。
  • InnoDB的輔助索引(Secondary Index,也就是非主鍵索引)存儲的只是主鍵列和索引列,若是主鍵定義的比較大,其餘索引也將很大。
  • MyISAM引擎使用B+Tree做爲索引結構,索引文件葉節點的data域存放的是數據記錄的地址,指向數據文件中對應的值,每一個節點只有該索引列的值。
  • MyISAM主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,輔助索引能夠重複,(因爲MyISAM輔助索引在葉子節點上存儲的是數據記錄的地址,和主鍵索引同樣,因此不須要再遍歷一次主鍵索引)。

簡單的說:

  1. 主索引的區別:InnoDB的數據文件自己就是索引文件。而MyISAM的索引和數據是分開的。

  2. 輔助索引的區別:InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。而MyISAM的輔助索引和主索引沒有多大區別。

11. 爲何儘可能選擇單調遞增數值類型的主鍵

  • InnoDB中數據記錄自己被存於主索引(B+樹)的葉子節點上。這就要求同一個葉子節點內(大小爲一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,所以每當有一條新的記錄插入時,MySQL會根據其主鍵將其插入適當的結點和位置,若是頁面達到裝載因子(InnoDB默認爲15/16),則開闢一個新的頁。

  • 若是使用自增主鍵,那麼每次插入新的記錄,記錄就會順序添加到當前索引結點的後續位置,當一頁寫滿,就會自動開闢一個新的頁,這樣就會造成一個緊湊的索引結構,近似順序填滿。因爲每次插入時也不須要移動已有數據,所以效率很高,也不會增長不少開銷在維護索引上。

  • 若是使用非自增主鍵,因爲每次插入主鍵的值近似於隨機,所以每次新紀錄都要被插入到現有索引頁的中間某個位置,此時MySQL不得不爲了將新記錄查到合適位置而移動元素,甚至目標頁可能已經被回寫到磁盤上而從緩存中清掉,此時又要從磁盤上讀回來,這增長了不少開銷,同時頻繁的移動、分頁操做形成了大量的碎片,獲得了不夠緊湊的索引結構,後續不得不經過 OPTIMIZE TABLE 來重建表並優化填充頁面。

簡單的說:

索引樹只能定位到某一頁,每一頁內的插入仍是須要經過比較、移動插入的。因此有序主鍵能夠提高插入效率。

12. 建表時,int 後面的長度的意義

int佔多少個字節,已是固定的了,長度表明了顯示的最大寬度。若是不夠會用0在左邊填充,但必須搭配zerofill使用。也就是說,int的長度並不影響數據的存儲精度,長度只和顯示有關。

13. SHOW INDEX 結果字段表明什麼意思

  • Table

    • 表名。
  • Non_unique

    • 0:該索引不含重複值。
    • 1:該索引可含有重複值。
  • Key_name

    • 索引名稱,若是是註解索引,名稱老是爲PRIMARY
  • Seq_in_index

    • 該列在索引中的序號,從 1 開始。例如:存在聯合索引 idx_a_b_c (a,b,c),則a的Seq_in_index=1,b=2,c=3。
  • Column_name

    • 列名。
  • Collation

    • 索引的排列順序:A(ascending),D (descending),NULL (not sorted)。
  • Cardinality

    • 一個衡量該索引的惟一程度的值,可使用ANALYZE TABLE(INNODB) 或者 myisamchk -a(MyISAM)更新該值。
    • 若是表記錄太少,該字段的意義不大。通常狀況下,該值越大,索引效率越高。
  • Sub_part

    • 對於前綴索引,用於索引的字符個數。若是整個字段都加上了索引,則顯示爲NULL
  • Null

    • YES:該列容許NULL值。
    • '':該列不容許NULL值。
  • Index_type

    • 索引類型,包括(BTREE, FULLTEXT, HASH, RTREE)。

14. 如何解決like'%字符串%'時索引失效?

  • LIKE問題:like 以通配符開頭 ('%abc...'),mysql索引失效會變成全表掃描的操做。
    • 罪魁禍首是%,不是LIKELIKE 條件是 type = range 級別
    • %xxx%:全表掃描
    • %xxx:全表掃描
    • xxx%:range
  • 解決辦法
    • 使用覆蓋索引,能夠由 ALL 變爲INDEX,爲啥呢?覆蓋索引以後就能使用使用索引進行全表掃描。這裏要注意一下,使用符合索引的時候,命中一個字段就能夠,不用所有命中。

15. MySQL高效分頁

  • 存在SQL:SELECT * FROM ttl_product_info ORDER BY id LIMIT N,M。其中 LIMIT N,M 存在的問題最大:取出N+M行,丟棄前N行,返回 N ~ N+M 行的記錄,若是N值很是大,效率極差(表記錄1500w,N=10000000,M=30 須要9秒)。
  • 解決辦法:SQL:SELECT id FROM ttl_product_info WHERE id > N LIMIT M,id 列是索引列,id > N屬於 range 級別,效率天然高,而後從位置開始取30條記錄,效率極高(表記錄1500w,N=10000000,M=30,須要0.9毫秒)。
  • 固然想要實現上述效果的前提是:
    1. id是惟一索引,並且單調遞增。
    2. N 的值是上一次查詢的記錄的最後一條id,(須要前端保存一下,不能直接用傳統的方法得到)
    3. 不支持跨頁查詢,只能按照第1,2,3,4頁這樣查詢逐頁查詢。

總結

爲了保持文章結構的完整性,這裏強行加上一段總結。。。

參考文章:

相關文章
相關標籤/搜索