天天看點

mysql index and search improve MySQL索引和查詢優化

MySQL索引和查詢優化

對于任何DBMS,索引都是進行優化的最主要的因素。對于少量的資料,沒有合适的索引影響不是很大,但是,當随着資料量的增加,性能會急劇下降。

如果對多列進行索引(組合索引),列的順序非常重要,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等于某值。

索引是快速搜尋的關鍵。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條記錄。

索引分單列索引群組合索引。單列索引,即一個索引隻包含單個列,一個表可以有多個單列索引,但這不是組合索引。組合索引,即一個索包含多個列。

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索引類型:唯一索引

它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種建立方式:

建立索引

  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

mysql index and search improve MySQL索引和查詢優化
最左字首原理與相關優化

高效使用索引的首要條件是知道什麼樣的查詢會使用到索引,這個問題和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 index and search improve MySQL索引和查詢優化

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

  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或以上)

mysql index and search improve MySQL索引和查詢優化
開啟profile
1    mysql> set profiling=1;
2    Query OK, 0 rows affected (0.00 sec)
eg:
1    mysql> select * from test_1;
2    mysql> show profiles;
3    +----------+------------+----------------------+
4    | Query_ID | Duration   | Query                |
5    +----------+------------+----------------------+
6    |        1 | 0.84718100 | select * from test_1 |
7    +----------+------------+----------------------+
8    1 row in set (0.00 sec)      

繼續閱讀