MySQL索引和查詢優化

對於任何DBMS,索引都是進行優化的最主要的因素。對於少許的數據,沒有合適的索引影響不是很大,可是,當隨着數據量的增長,性能會急劇降低。html


若是對多列進行索引(組合索引),列的順序很是重要,MySQL僅能對索引最左邊的前綴進行有效的查找。mysql

例如:
假 設存在組合索引it1c1c2(c1,c2),查詢語句select * from t1 where c1=1 and c2=2可以使用該索引。查詢語句select * from t1 where c1=1也可以使用該索引。可是,查詢語句select * from t1 where c2=2不可以使用該索引,由於沒有組合索引的引導列,即,要想使用c2列進行查找,必需出現c1等於某值。sql

 

 

索引是快速搜索的關鍵。MySQL索引的創建對於MySQL的高效運行是很重要的。數據庫

 

下面介紹幾種常見的MySQL索引類型:數據庫設計

在數據庫表中,對字段創建索引能夠大大提升查詢速度。假如咱們建立了一個 mytable表:函數

  1. CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL ); 

咱們隨機向裏面插入了10000條記錄,其中有一條:5555, admin。性能

在查找username="admin"的記錄優化

  1. SELECT * FROM mytable WHERE username='admin'; 

時,若是在username上已經創建了索引,MySQL無須任何掃描,即準確可找到該記錄。相反,MySQL會掃描全部記錄,即要查詢10000條記錄。spa

索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表能夠有多個單列索引,但這不是組合索引。組合索引,即一個索包含多個列。設計

MySQL索引類型包括:

(1)普通索引

這是最基本的索引,它沒有任何限制。它有如下幾種建立方式:

建立索引

  1. CREATE INDEX indexName ON mytable(username(length)); 

若是是CHAR,VARCHAR類型,length能夠小於字段實際長度;若是是BLOB和TEXT類型,必須指定 length,下同。

修改表結構

  1. ALTER mytable ADD INDEX [indexName] ON (username(length)) 

建立表的時候直接指定

  1. CREATE TABLE mytable( ID INT NOT NULL, 
    username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) ); 

刪除索引的語法:

  1. DROP INDEX [indexName] ON mytable

(2)MySQL索引類型:惟一索引

它與前面的普通索引相似,不一樣的就是:索引列的值必須惟一,但容許有空值(設計時候除非有必要,通常不要設爲null,能夠設空字符串等)。若是是組合索引,則列值的組合必須惟一。它有如下幾種建立方式:

建立索引

  1. CREATE UNIQUE INDEX indexName ON mytable(username(length)) 

修改表結構

  1. ALTER mytable ADD UNIQUE [indexName] ON (username(length)) 

建立表的時候直接指定

  1. CREATE TABLE mytable( ID INT NOT NULL, 
    username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) ); 

(3)MySQL索引類型:主鍵索引

它是一種特殊的惟一索引,不容許有空值通常是在建表的時候同時建立主鍵索引:

  1. CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) ); 

固然也能夠用 ALTER 命令。記住:一個表只能有一個主鍵。

(4)組合索引

爲了形象地對比單列索引和組合索引,爲表添加多個字段:

  1. CREATE TABLE mytable( ID INT NOT NULL, username 
    VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL ); 

爲了進一步榨取MySQL的效率,就要考慮創建組合索引。就是將 name, city, age建到一個索引裏:

  1. ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age); 

建表時,usernname長度爲 16,這裏用 10。這是由於通常狀況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減小索引文件的大小,提升INSERT的更新速度。

若是分別在 usernname,city,age上創建單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不同,遠遠低於咱們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認爲彷佛是最有效率的單列索引。

 

創建這樣的組合索引,實際上是至關於分別創建了下面三組組合索引:

  1. usernname , city, age usernname , city usernname

以上的相關內容就是對MySQL索引類型的部份內容的介紹,望你能有所收穫。

 


 

使用索引的注意事項

使用索引時,有如下一些技巧和注意事項:

索引不會包含有NULL值的列

只要列中包含有NULL值都將不會被包含在MySQL索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。因此咱們在數據庫設計時不要讓字段的默認值爲NULL。

使用短索引

對串列進行索引,若是可能應該指定一個前綴長度。例如,若是有一個CHAR(255)的列,若是在前10個或20個字符內,多數值是唯一的,那麼就不要對整個列進行索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和I/O操做。

索引列排序

MySQL查詢只使用一個索引,所以若是where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引。

like語句操做

通常狀況下不鼓勵使用like操做,若是非使用不可,如何使用也是一個問題。like 「%aaa%」 不會使用MySQL索引而like 「aaa%」可使用索引。

不要在列上進行運算

  1. select * from users where YEAR(adddate)<2007;  

將在每一個行上進行運算,這將致使索引失效而進行全表掃描,所以咱們能夠改爲

  1. select * from users where adddate<‘2007-01-01’;  

不使用NOT IN和<>操做

 


 

索引優化  http://blog.codinglabs.org/articles/theory-of-mysql-index.html

 

最左前綴原理與相關優化

高效使用索引的首要條件是知道什麼樣的查詢會使用到索引,這個問題和B+Tree中的「最左前綴原理」有關,下面經過例子說明最左前綴原理。

這裏先說一下聯合索引的概念。在上文中,咱們都是假設索引只引用了單個的列,實際上,MySQL中的索引能夠以必定順序引用多個列,這種索引叫作聯合索引,通常的,一個聯合索引是一個有序元組<a1, a2, …, an>,其中各個元素均爲數據表的一列,實際上要嚴格定義索引須要用到關係代數,可是這裏我不想討論太多關係代數的話題,由於那樣會顯得很枯燥,因此這裏就再也不作嚴格定義。另外,單列索引能夠當作聯合索引元素數爲1的特例。

以employees.titles表爲例,下面先查看其上都有哪些索引:

SHOW INDEX FROM employees.titles;
+--------+------------+----------+--------------+-------------+-----------+-------------+------+------------+
| Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Null | Index_type |
+--------+------------+----------+--------------+-------------+-----------+-------------+------+------------+
| titles |          0 | PRIMARY  |            1 | emp_no      | A         |        NULL |      | BTREE      |
| titles |          0 | PRIMARY  |            2 | title       | A         |        NULL |      | BTREE      |
| titles |          0 | PRIMARY  |            3 | from_date   | A         |      443308 |      | BTREE      |
| titles |          1 | emp_no   |            1 | emp_no      | A         |      443308 |      | BTREE      |
+--------+------------+----------+--------------+-------------+-----------+-------------+------+------------+

從結果中能夠到titles表的主索引爲<emp_no, title, from_date>,還有一個輔助索引<emp_no>。爲了不多個索引使事情變複雜(MySQL的SQL優化器在多索引時行爲比較複雜),這裏咱們將輔助索引drop掉:

ALTER TABLE employees.titles DROP INDEX emp_no;

這樣就能夠專心分析索引PRIMARY的行爲了。
狀況一:全列匹配。 EXPLAIN
SELECT * FROM employees.titles WHERE emp_no='10001' AND title='Senior Engineer' AND from_date='1986-06-26'; +----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+ | 1 | SIMPLE | titles | const | PRIMARY | PRIMARY | 59 | const,const,const | 1 | | +----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+ 很明顯,當按照索引中全部列進行精確匹配(這裏精確匹配指「=」或「IN」匹配)時,索引能夠被用到。這裏有一點須要注意,理論上索引對順序是敏感的,可是因爲MySQL的查詢優化器會自動調整where子句的條件順序以使用適合的索引,例如咱們將where中的條件順序顛倒: EXPLAIN SELECT * FROM employees.titles WHERE from_date='1986-06-26' AND emp_no='10001' AND title='Senior Engineer'; +----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+ | 1 | SIMPLE | titles | const | PRIMARY | PRIMARY | 59 | const,const,const | 1 | | +----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+ 效果是同樣的。 狀況二:最左前綴匹配。 EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001'; +----+-------------+--------+------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | titles | ref | PRIMARY | PRIMARY | 4 | const | 1 | | +----+-------------+--------+------+---------------+---------+---------+-------+------+-------+ 當查詢條件精確匹配索引的左邊連續一個或幾個列時,如<emp_no><emp_no, title>,因此能夠被用到,可是隻能用到一部分,即條件所組成的最左前綴。上面的查詢從分析結果看用到了PRIMARY索引,可是key_len爲4,說明只用到了索引的第一列前綴。
狀況三:查詢條件用到了索引中列的精確匹配,可是中間某個條件未提供。 EXPLAIN
SELECT * FROM employees.titles WHERE emp_no='10001' AND from_date='1986-06-26'; +----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+ | 1 | SIMPLE | titles | ref | PRIMARY | PRIMARY | 4 | const | 1 | Using where | +----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+ 此時索引使用狀況和狀況二相同,由於title未提供,因此查詢只用到了索引的第一列,然後面的from_date雖然也在索引中,可是因爲title不存在而沒法和左前綴鏈接,所以須要對結果進行掃描過濾from_date(這裏因爲emp_no惟一,因此不存在掃描)。若是想讓from_date也使用索引而不是where過濾,能夠增長一個輔助索引<emp_no, from_date>,此時上面的查詢會使用這個索引。除此以外,還可使用一種稱之爲「隔離列」的優化方法,將emp_no與from_date之間的「坑」填上。 首先咱們看下title一共有幾種不一樣的值: SELECT DISTINCT(title) FROM employees.titles; +--------------------+ | title | +--------------------+ | Senior Engineer | | Staff | | Engineer | | Senior Staff | | Assistant Engineer | | Technique Leader | | Manager | +--------------------+ 只有7種。在這種成爲「坑」的列值比較少的狀況下,能夠考慮用「IN」來填補這個「坑」從而造成最左前綴: EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001' AND title IN ('Senior Engineer', 'Staff', 'Engineer', 'Senior Staff', 'Assistant Engineer', 'Technique Leader', 'Manager') AND from_date='1986-06-26'; +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | titles | range | PRIMARY | PRIMARY | 59 | NULL | 7 | Using where | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 此次key_len爲59,說明索引被用全了,可是從type和rows看出IN實際上執行了一個range查詢,這裏檢查了7個key。看下兩種查詢的性能比較: SHOW PROFILES; +----------+------------+-------------------------------------------------------------------------------+ | Query_ID | Duration | Query | +----------+------------+-------------------------------------------------------------------------------+ | 10 | 0.00058000 | SELECT * FROM employees.titles WHERE emp_no='10001' AND from_date='1986-06-26'| | 11 | 0.00052500 | SELECT * FROM employees.titles WHERE emp_no='10001' AND title IN ... | +----------+------------+-------------------------------------------------------------------------------+ 「填坑」後性能提高了一點。若是通過emp_no篩選後餘下不少數據,則後者性能優點會更加明顯。固然,若是title的值不少,用填坑就不合適了,必須創建輔助索引。 狀況四:查詢條件沒有指定索引第一列。 EXPLAIN SELECT * FROM employees.titles WHERE from_date='1986-06-26'; +----+-------------+--------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | titles | ALL | NULL | NULL | NULL | NULL | 443308 | Using where | +----+-------------+--------+------+---------------+------+---------+------+--------+-------------+ 因爲不是最左前綴,索引這樣的查詢顯然用不到索引。 狀況五:匹配某列的前綴字符串。 EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001' AND title LIKE 'Senior%'; +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | titles | range | PRIMARY | PRIMARY | 56 | NULL | 1 | Using where | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 此時能夠用到索引,可是若是通配符不是隻出如今末尾,則沒法使用索引。(原文表述有誤,若是通配符%不出如今開頭,則能夠用到索引,但根據具體狀況不一樣可能只會用其中一個前綴) 狀況六:範圍查詢。 EXPLAIN SELECT * FROM employees.titles WHERE emp_no < '10010' and title='Senior Engineer'; +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | titles | range | PRIMARY | PRIMARY | 4 | NULL | 16 | Using where | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 範圍列能夠用到索引(必須是最左前綴),可是範圍列後面的列沒法用到索引。同時,索引最多用於一個範圍列,所以若是查詢條件中有兩個範圍列則沒法全用到索引。 EXPLAIN SELECT * FROM employees.titles WHERE emp_no < '10010' AND title='Senior Engineer' AND from_date BETWEEN '1986-01-01' AND '1986-12-31'; +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | titles | range | PRIMARY | PRIMARY | 4 | NULL | 16 | Using where | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 能夠看到索引對第二個範圍索引無能爲力。這裏特別要說明MySQL一個有意思的地方,那就是僅用explain可能沒法區分範圍索引和多值匹配,由於在type中這二者都顯示爲range。同時,用了「between」並不意味着就是範圍查詢,例以下面的查詢: EXPLAIN SELECT * FROM employees.titles WHERE emp_no BETWEEN '10001' AND '10010' AND title='Senior Engineer' AND from_date BETWEEN '1986-01-01' AND '1986-12-31'; +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | titles | range | PRIMARY | PRIMARY | 59 | NULL | 16 | Using where | +----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 看起來是用了兩個範圍查詢,但做用於emp_no上的「BETWEEN」實際上至關於「IN」,也就是說emp_no實際是多值精確匹配。能夠看到這個查詢用到了索引所有三個列。所以在MySQL中要謹慎地區分多值匹配和範圍匹配,不然會對MySQL的行爲產生困惑。 狀況七:查詢條件中含有函數或表達式。 很不幸,若是查詢條件中含有函數或表達式,則MySQL不會爲這列使用索引(雖然某些在數學意義上可使用)。例如: EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001' AND left(title, 6)='Senior'; +----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+ | 1 | SIMPLE | titles | ref | PRIMARY | PRIMARY | 4 | const | 1 | Using where | +----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+ 雖然這個查詢和狀況五中功能相同,可是因爲使用了函數left,則沒法爲title列應用索引,而狀況五中用LIKE則能夠。再如: EXPLAIN SELECT * FROM employees.titles WHERE emp_no - 1='10000'; +----+-------------+--------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | titles | ALL | NULL | NULL | NULL | NULL | 443308 | Using where | +----+-------------+--------+------+---------------+------+---------+------+--------+-------------+ 顯然這個查詢等價於查詢emp_no爲10001的函數,可是因爲查詢條件是一個表達式,MySQL沒法爲其使用索引。看來MySQL尚未智能到自動優化常量表達式的程度,所以在寫查詢語句時儘可能避免表達式出如今查詢中,而是先手工私下代數運算,轉換爲無表達式的查詢語句。 索引選擇性與前綴索引 既然索引能夠加快查詢速度,那麼是否是隻要是查詢語句須要,就建上索引?答案是否認的。由於索引雖然加快了查詢速度,但索引也是有代價的:索引文件自己要消耗存儲空間,同時索引會加劇插入、刪除和修改記錄時的負擔,另外,MySQL在運行時也要消耗資源維護索引,所以索引並非越多越好。通常兩種狀況下不建議建索引。 第一種狀況是表記錄比較少,例如一兩千條甚至只有幾百條記錄的表,不必建索引,讓查詢作全表掃描就行了。至於多少條記錄纔算多,這個我的有我的的見解,我我的的經驗是以2000做爲分界線,記錄數不超過 2000能夠考慮不建索引,超過2000條能夠酌情考慮索引。 另外一種不建議建索引的狀況是索引的選擇性較低。所謂索引的選擇性(Selectivity),是指不重複的索引值(也叫基數,Cardinality)與表記錄數(#T)的比值: Index Selectivity = Cardinality / #T 顯然選擇性的取值範圍爲(0, 1],選擇性越高的索引價值越大,這是由B+Tree的性質決定的。例如,上文用到的employees.titles表,若是title字段常常被單獨查詢,是否須要建索引,咱們看一下它的選擇性: SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles; +-------------+ | Selectivity | +-------------+ | 0.0000 | +-------------+ title的選擇性不足0.0001(精確值爲0.00001579),因此實在沒有什麼必要爲其單獨建索引。 有一種與索引選擇性有關的索引優化策略叫作前綴索引,就是用列的前綴代替整個列做爲索引key,當前綴長度合適時,能夠作到既使得前綴索引的選擇性接近全列索引,同時由於索引key變短而減小了索引文件的大小和維護開銷。下面以employees.employees表爲例介紹前綴索引的選擇和使用。 從圖12能夠看到employees表只有一個索引<emp_no>,那麼若是咱們想按名字搜索一我的,就只能全表掃描了: EXPLAIN SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido'; +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | employees | ALL | NULL | NULL | NULL | NULL | 300024 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ 若是頻繁按名字搜索員工,這樣顯然效率很低,所以咱們能夠考慮建索引。有兩種選擇,建<first_name><first_name, last_name>,看下兩個索引的選擇性: SELECT count(DISTINCT(first_name))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ | 0.0042 | +-------------+ SELECT count(DISTINCT(concat(first_name, last_name)))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ | 0.9313 | +-------------+ <first_name>顯然選擇性過低,<first_name, last_name>選擇性很好,可是first_name和last_name加起來長度爲30,有沒有兼顧長度和選擇性的辦法?能夠考慮用first_name和last_name的前幾個字符創建索引,例如<first_name, left(last_name, 3)>,看看其選擇性: SELECT count(DISTINCT(concat(first_name, left(last_name, 3))))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ | 0.7879 | +-------------+ 選擇性還不錯,但離0.9313仍是有點距離,那麼把last_name前綴加到4: SELECT count(DISTINCT(concat(first_name, left(last_name, 4))))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ | 0.9007 | +-------------+ 這時選擇性已經很理想了,而這個索引的長度只有18,比<first_name, last_name>短了接近一半,咱們把這個前綴索引 建上: ALTER TABLE employees.employees ADD INDEX `first_name_last_name4` (first_name, last_name(4)); 此時再執行一遍按名字查詢,比較分析一下與建索引前的結果: SHOW PROFILES; +----------+------------+---------------------------------------------------------------------------------+ | Query_ID | Duration | Query | +----------+------------+---------------------------------------------------------------------------------+ | 87 | 0.11941700 | SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido' | | 90 | 0.00092400 | SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido' | +----------+------------+---------------------------------------------------------------------------------+ 性能的提高是顯著的,查詢速度提升了120多倍。 前綴索引兼顧索引大小和查詢速度,可是其缺點是不能用於ORDER BY和GROUP BY操做,也不能用於Covering index(即當索引自己包含查詢所需所有數據時,再也不訪問數據文件自己)。

 

 

補充該節中的"範圍查詢"說明:

  Mysql對於範圍查詢range分的優化爲單字段優化和多元素優化:

單元素索引範圍條件的定義以下:
 
·         對於BTREE和HASH索引,當使用=、<=>、 IN IS NULL 或者 IS NOT NULL 操做符時,關鍵元素與常量值的比較關係對應一個範圍條件,即const範圍。
 
·         對於BTREE索引,當使用>、<、>=、<=、 BETWEEN 、!=或者<>,或者 LIKE 'pattern' (其中 'pattern' 不以通配符開始)操做符時,關鍵元素與常量值的比較關係對應一個範圍條件。
 
·         對於全部類型的索引,多個範圍條件結合 OR AND 則產生一個範圍條件。
 
前面描述的「常量值」係指:
 
·         查詢字符串中的常量
 
·         同一聯接中的const或system表中的列
 
·         無關聯子查詢的結果
 
·         徹底從前面類型的子表達式組成的表達式

 

多元素索引的範圍條件:
 
      1. ----------------
      對於BTREE索引,區間能夠對結合 AND 的條件有用,其中每一個條件用一個常量值經過=、<=>、 IS NULL 、>、<、>=、<=、!=、<>、 BETWEEN 或者 LIKE 'pattern' (其中 'pattern' 不以通配符開頭)比較一個關鍵元素。區間能夠足夠長以肯定一個包含全部匹配條件(或若是使用<>或!=,爲兩個區間)的記錄的單一的關鍵元組。例如,對於條件:
      key_part1 = 'foo' AND key_part2 >= 10 AND key_part3 > 10
 
     2. -----------
     對於HASH索引,可使用包含相同值的每一個區間。
     key_part1 cmp const1 AND key_part2 cmp const2
     AND ... AND key_partN cmp constN;
 
     這裏,const1,const2,...爲常量,cmp是=、<=>或者 IS NULL 比較操做符之一,條件包括全部索引部分。(也就是說,有N 個條件,每個對應N-元素索引的每一個部分)。   
 
     3.  ----------
     若是包含區間內的一系列記錄的條件結合使用 OR ,則造成包括一系列包含在區間並集的記錄的一個條件。若是條件結合使用了 AND ,則造成包括一系列包含在區間交集內的記錄的一個條件。例如,對於兩部分索引的條件:
  (key_part1 = 1 AND key_part2 < 2) OR (key_part1 > 5)
 
     區間爲:
     (1, -inf) < (key_part1, key_part2) < (1, 2)
     (5, -inf) < (key_part1, key_part2)   

 

  

 

 


Mysql檢索時間查詢 (版本要求: 5.0.37或以上)

 

開啓profile
   mysql> set profiling=1;
   Query OK, 0 rows affected (0.00 sec)
eg:
   mysql> select * from test_1;
   mysql> show profiles;
   +----------+------------+----------------------+
   | Query_ID | Duration   | Query                |
   +----------+------------+----------------------+
   |        1 | 0.84718100 | select * from test_1 |
   +----------+------------+----------------------+
   1 row in set (0.00 sec)

 

 

轉自:http://www.cnblogs.com/mailingfeng/archive/2012/09/26/2704344.html

相關文章
相關標籤/搜索