1. 程式人生 > >MySQL資料庫for面試

MySQL資料庫for面試

本篇涉及到的問題:MySQL引擎;  什麼是基本表、檢視、遊標;  char和varchar的區別及使用場景;  MySQL中,索引、主鍵、唯一索引、聯合索引的區別,對資料庫的讀寫效能的影響;  為資料庫表建立索引的原則、目的及對DBS的負面影響;  MySQL語句優化;

MySQL引擎

    資料庫儲存引擎是資料庫底層軟體組織,資料庫管理系統(DBMS)使用資料引擎進行建立、查詢、更新和刪除資料。不同的儲存引擎提供不同的儲存機制、索引技巧、鎖定水平等功能,使用不同的儲存引擎,還可以獲得特定的功能。現在許多不同的資料庫管理系統都支援多種不同的資料引擎。

     MySQL的核心就是儲存引擎

。與MySQL一起提供的各種儲存引擎在設計時考慮了不同的使用情況。為了更有效地使用外掛式儲存體系結構,最好了解各種儲存引擎的優點和缺點。

  1.  MyISAM:預設的MySQL外掛式儲存引擎,它是在Web、資料倉儲和其他應用環境下最常使用的儲存引擎之一。注意,通過更改STORAGE_ENGINE配置變數,能夠方便地更改MySQL伺服器的預設儲存引擎。
  2.  InnoDB:用於事務處理應用程式,具有眾多特性,包括ACID事務支援。
  3.  BDB:可替代InnoDB的事務引擎,支援COMMIT、ROLLBACK和其他事務特性。
  4.  Memory:將所有資料儲存在RAM中,在需要快速查詢引用和其他類似資料的環境下,可提供極快的訪問。
  5.  Merge:允許MySQL DBA或開發人員將一系列等同的MyISAM表以邏輯方式組合在一起,並作為1個物件引用它們。對於諸如資料倉儲等VLDB環境十分適合。
  6.  Archive:為大量很少引用的歷史、歸檔、或安全審計資訊的儲存和檢索提供了完美的解決方案。
  7. Federated:能夠將多個分離的MySQL伺服器連結起來,從多個物理伺服器建立一個邏輯資料庫。十分適合於分散式環境或資料集市環境。
  8. Cluster/NDB:MySQL的簇式資料庫引擎,尤其適合於具有高效能查詢要求的應用程式,這類查詢需求還要求具有最高的正常工作時間和可用性。
  9. Other:其他儲存引擎包括CSV(引用由逗號隔開的用作資料庫表的檔案),Blackhole(用於臨時禁止對資料庫的應用程式輸入),以及Example引擎(可為快速建立定製的外掛式儲存引擎提供幫助)。

對於整個伺服器或方案,並不一定要使用相同的儲存引擎,可以為方案中的每個表使用不同的儲存引擎。

下面詳細介紹InnoDB引擎和MyISAM引擎:

Innodb引擎提供了對資料庫ACID事務的支援,並且實現了SQL標準的四種隔離級別。該引擎還提供了行級鎖和外來鍵約束,它的設計目標是處理大容量資料庫系統,它本身其實就是基於MySQL後臺的完整資料庫系統,MySQL執行時InnoDB會在記憶體中建立緩衝池,用於緩衝資料和索引。但是該引擎不支援FULLTEXT型別的索引,而且它沒有儲存表的行數,當SELECT COUNT(*) FROM TABLE時需要掃描全表。當需要使用資料庫事務時,該引擎當然是首選。由於鎖的粒度更小,寫操作不會鎖定全表,所以在併發較高時,使用Innodb引擎會提升效率。但是使用行級鎖也不是絕對的,如果在執行一個SQL語句時MySQL不能確定要掃描的範圍,InnoDB表同樣會鎖全表。

MyIASM引擎是MySQL預設的引擎,但是它沒有提供對資料庫事務的支援,也不支援行級鎖和外來鍵,因此當INSERT(插入)或UPDATE(更新)資料時即寫操作需要鎖定整個表,效率便會低一些。不過和InnoDB不同,MyIASM中儲存了表的行數,於是SELECT COUNT(*) FROM TABLE時只需要直接讀取已經儲存好的值而不需要進行全表掃描。如果表的讀操作遠遠多於寫操作且不需要資料庫事務的支援,那麼MyIASM也是很好的選擇。

兩者主要區別:

1、MyIASM是非事務安全的,而InnoDB是事務安全的

2、MyIASM鎖的粒度是表級的,而InnoDB支援行級鎖

3、MyIASM支援全文型別索引,而InnoDB不支援全文索引

4、MyIASM相對簡單,效率上要優於InnoDB,小型應用可以考慮使用MyIASM

5、MyIASM表儲存成檔案形式,跨平臺使用更加方便

應用場景:

1、MyIASM管理非事務表,提供高速儲存和檢索以及全文搜尋能力,如果再應用中執行大量select操作,應該選擇MyIASM。

2、InnoDB用於事務處理,具有ACID事務支援等特性,如果在應用中執行大量insert和update操作,應該選擇InnoDB。

兩種引擎所使用的索引的資料結構(都是B+樹)

    MyIASM引擎,B+樹的資料結構中儲存的內容實際上是實際資料的地址值。也就是說它的索引和實際資料是分開的,只不過使用索引指向了實際資料。這種索引的模式被稱為非聚集索引

    Innodb引擎的索引的資料結構也是B+樹,只不過資料結構中儲存的都是實際的資料,這種索引有被稱為聚集索引

什麼是基本表、檢視、遊標

    基本表是本身獨立存在的表,在 SQL 中一個關係就對應一個表。 是一個虛表  

    檢視是從一個或幾個基本表匯出的表。檢視本身不獨立儲存在資料庫中,所以檢視是一種虛表。而具有和物理表相同的功能,可以對檢視進行增,改,查,操作。另外,對檢視的修改不影響基本表,相比多表查詢,它使得我們獲取資料更容易。

    遊標是對查詢出來的結果集作為一個單元來有效的處理。遊標可以定在該單元中的特定行,從結果集的當前行檢索一行或多行。可以對結果集當前行做修改。一般不使用遊標,但是需要逐條處理資料的時候,遊標顯得十分重要。

char和varchar的區別及使用場景

    char是一種固定長度的型別,varchar則是一種可變長度的型別,它們的區別是:  

    char(M)型別的資料列裡,每個值都佔用M個位元組,如果某個長度小於M,MySQL就會在它的右邊用空格字元補足(在檢索操作中那些填補出來的空格字元將被去掉)。在varchar(M)型別的資料列裡,每個值只佔用剛好夠用的位元組再加上一個用來記錄其長度的位元組(即總長度為L+1位元組)。 

varchar得適用場景

    ☆字串列得最大長度比平均長度大很多     ☆字串很少被更新,容易產生儲存碎片   ☆使用多位元組字符集儲存字串。

char的使用場景:

    ☆儲存具有近似得長度(md5值,身份證,手機號)    ☆長度比較短小得字串(因為varchar需要額外空間記錄字串長度)

    ☆更適合經常更新的字串,更新時不會出現頁分裂得情況,避免出現儲存碎片,獲得更好的io效能。

MySQL中,索引、主鍵、唯一索引、聯合索引的區別,對資料庫的讀寫效能的影響

   索引是一種特殊的檔案(InnoDB資料庫表上的索引是表空間的一個組成部分),它們包含著資料庫表裡所有記錄的引用指標。

   普通索引的唯一任務是加快對資料的訪問速度,有KEY或INDEX關鍵字定義。普通索引允許被索引的資料列包含重複的值,如果能確定某個資料列將只包含彼此各不相同的值,在為這個資料列建立索引的時候就應該用關鍵字UNIQUE把它定義成一個唯一索引,唯一索引保證資料記錄的唯一性。

    主鍵是一種特殊的唯一索引,在一張表中只能定義一個主鍵索引,主鍵用於唯一標識一條記錄,使用關鍵字PRIMARY KEY建立。

    索引可以覆蓋多個數據列,比如INDEX(columnA,columnB)索引,這就是聯合索引

索引對資料庫的讀寫效能的影響索引可以極大的提高資料的查詢速度,但是會降低資料的插入、刪除和更新表的速度,因為在執行寫操作的時候,還要操作索引檔案。

為資料庫表建立索引的原則、目的及對DBS的負面影響

★ 建立索引的原則:

     ☆在最頻繁使用的、用以縮小查詢範圍的欄位上建立索引   ☆在頻繁使用的,用以排序的欄位上建立索引

     注:這兩種情況最好不要建立索引:一是對於查詢中很少涉及的列或者重複值比較多的列,不宜建立索引;二是對於一些特殊的資料型別,不宜建立索引,比如文字欄位(text)等。

◆ 建立索引的目的:

   ◇快速訪問資料表中的特定資訊,提高檢索速度    ◇建立唯一性索引,保證資料庫表中每一行資料的唯一性

   ◇加速表和表之間的連線    ◇使用分組和排序子句進行資料檢索時,可以顯著減少查詢中分組和排序的時間

●索引對資料庫系統的負面影響:     ○ 建立索引和維護索引需要耗費時間,這個時間隨著資料量的增加而增加;

    ○ 索引需要佔用物理空間,不光是表需要佔用資料空間,每個索引也需要佔用物理空間  ;

    ○ 當對錶進行增、刪、改、的時候索引也要動態維護,這樣就降低了資料的維護速度。

MySQL語句優化

▲對查詢進行優化,儘量避免全表掃描,首先考慮在where及order by涉及的列上建立索引。

▲應儘量避免在where子句中使用!=或<>操作符,否則引擎將放棄使用索引而進行全表掃描。

▲應儘量避免在where子句中進行null值的判斷,否則引擎將放棄使用索引而進行全表掃描。例:select id from t where num is null;  可以在num上設定預設值為0,確保num列中沒有null值,然後可以這樣查詢:select id from t where num=0;

▲應儘量避免在 where 子句中使用 or 來連線條件,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num=10 or num=20;可以這樣查詢:select id from t where num=10  union all  select id from t where num=20

▲模糊查詢以%開頭的查詢也將導致全表掃描,例:select id from t where name like '%abc%'。

▲in 和 not in 也要慎用,否則會導致全表掃描,如:select id from t where num in(1,2,3);對於連續的數值,能用 between 就不要用 in 了:select id from t where num between 1 and 3;

▲如果在 where 子句中使用引數,也會導致全表掃描。因為SQL只有在執行時才會解析區域性變數,但優化程式不能將訪問計劃的選擇推遲到執行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:      select id from t where [email protected]; 可以改為強制查詢使用索引: select id from t with(index(索引名)) where [email protected]

▲應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描。如:      select id from t where num/2=100;   應改為:   select id from t where num=100*2;

▲應儘量避免在where子句中對欄位進行函式操作,這將導致引擎放棄使用索引而進行全表掃描。如:   select id from t where substring(name,1,3)='abc' ;   --name以abc開頭的id   select id from t where datediff(day,createdate,'2005-11-30')=0;   --'2005-11-30'生成的id   應改為:   select id from t where name like 'abc%';   select id from t where createdate>='2005-11-30' and createdate<'2005-12-1';

▲不要在 where 子句中的“=”【左邊】進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引。

▲在使用索引欄位作為條件時,如果該索引是【複合索引】,那麼必須使用到該索引中的【第一個欄位】作為條件時才能保證系統使用該索引,否則該索引將不會被使用。並且應【儘可能】的讓欄位順序與索引順序相一致。(欄位順序也可以不與索引順序一致,但是一定要包含【第一個欄位】。)

▲不要寫一些沒有意義的查詢,如需要生成一個空表結構:     select col1,col2 into #t from t where 1=0; 這類程式碼不會返回任何結果集,但是會消耗系統資源的,應改成:create table #t(...);

▲很多時候用 exists 代替 in 是一個好的選擇:select num from a where num in(select num from b);       替換成select num from a where exists(select 1 from b where num=a.num);

▲並不是所有索引對查詢都有效,SQL是根據表中資料來進行查詢優化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

▲索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

▲應儘可能的避免更新 clustered 索引資料列,因為 clustered 索引資料列的順序就是表記錄的物理儲存順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。

▲儘量使用數字型欄位,若只含數值資訊的欄位儘量不要設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。這是因為引擎在處理查詢和連線時會逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。

▲儘可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位儲存空間小,可以節省儲存空間,其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。

▲.任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。

▲儘量使用表變數來代替臨時表。如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。

▲避免頻繁建立和刪除臨時表,以減少系統表資源的消耗。

▲.如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

▲臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,最好使用匯出表。

▲儘量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。

▲使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

▲與臨時表一樣,遊標並不是不可使用。對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

▲在所有的儲存過程和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。無需在執行儲存過程和觸發器的每個語句後向客戶端傳送 DONE_IN_PROC 訊息。

▲儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。

▲儘量避免大事務操作,提高系統併發能力。

select Count (*)和Select Count(1)以及Select Count(column)區別:     一般情況下,Select Count (*)和Select Count(1)兩著返回結果是一樣的。     假如表沒有主鍵(Primary key), 那麼count(1)比count(*)快;如果有主鍵的話,那主鍵作為count的條件時候count(主鍵)最快; 如果表中只有一個欄位的話那count(*)就是最快的。count(*) 跟 count(1) 的結果一樣,都包括對NULL的統計,而count(column) 是不包括NULL的統計 。

索引列上計算引起的索引失效及優化措施以及注意事項:     建立索引、優化查詢以便達到更好的查詢優化效果。但實際上,MySQL有時並不按我們設計的那樣執行查詢。MySQL是根據統計資訊來生成執行計劃的,這就涉及索引及索引的刷選率,表資料量,還有一些額外的因素。    Each table index is queried, and the best index is used unless the optimizer believes that it is more efficient to use a table scan. At one time, a scan was used based on whether the best index spanned more than 30% of the table, but a fixed percentage no longer determines the choice between using an index or a scan. The optimizer now is more complex and bases its estimate on additional factors such as table size, number of rows, and I/O block size.     簡而言之,當MySQL認為符合條件的記錄在30%以上,它就不會再使用索引因為mysql認為走索引的代價比不用索引代價大,所以優化器選擇了自己認為代價最小的方式。事實也的確如此,是MYSQL認為記錄是30%以上,而不是實際MYSQL去查完再決定的。都查完了,還用什麼索引啊!MYSQL會先估算,然後決定是否使用索引。

MySQL無法使用索引的情況總結:

(1)欄位使用函式,將無法使用索引;

(2)Join 語句中 Join 條件欄位型別不一致的時候 MySQL 無法使用索引;

(3)複合索引的情況下,如果查詢條件不包含索引列的最左邊部分,即不滿足最左字首原則,則不會使用索引;

(4)如果mysql估計使用索引掃描比全表掃描更慢,則不使用索引。(掃描資料超過30%,都會走全表)

(5)以%開頭的like查詢;

(6)資料型別出現隱式轉換的時候也不會使用索引,特別是當列型別是字串,那麼一定記得在where條件中把字串常量值用引號引起來,否則即便這個列上有索引,MySQL也不會用到,因為MySQL預設把輸入的常量值進行轉換以後才進行檢索;

(7)用or分割開的條件,如果 or前的條件中的列有索引,而後面的列中沒有索引,那麼涉及的索引都不會被用到。