Range查詢:用單獨的Index的一個或多個index值來檢索表的子集行數據,當然包含多個index。
1:一個index (單一部分)的range access 方法:(eg : 指的這種key (column1 ))
單獨的index,index值間隔可以方便的由對應的where子句的條件表示,所有我們稱值為range條件而不是間隔;
單獨index的range條件的定義:
1.1:對於btree和hash索引,index和一個常量值通過 =, <=>,in(),is null,或者 IS not null操作符做比較;
1.2:另外,對於Btree索引,index和一個常量值通過 <,>,<=,>=,between,!=,或者<>操作符做比較;
1.3: 對於所有類型的index,多范圍條件通過 or and關鍵字組合形式;
'常量值'在之前的描述中意味着:
2.1: 查詢字符串的常量形式;
2.2: const 或者system表的一列(也只有一列)的自連接(join);
2.3: 不相關子查詢的結果;
2.4: 有上面類型子表達式完全組成的任意表達式;
where子句范圍查找的例子:
SELECT * FROM t1 WHERE key_col > 1 AND key_col < 10; SELECT * FROM t1 WHERE key_col = 1 OR key_col IN (15,18,20); SELECT * FROM t1 WHERE key_col LIKE 'ab%' OR key_col BETWEEN 'bar' AND 'foo';
一些非常量值可能在傳播階段轉換為常量;
Mysql嘗試對於在where子句中的任何可能的index提取range condition,在提取過程中,不能構造的范圍條件被舍去,產生重疊的條件被組合,產生空范圍的條件被舍去。
如下:
SELECT * FROM t1 WHERE (key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR (key1 < 'bar' AND nonkey = 4) OR (key1 < 'uux' AND key1 > 'z');
key1為index, nonkey非index;
key1的提取過程如下:
1:從原始的where子句開始:
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR key1 LIKE '%b')) OR (key1 < 'bar' AND nonkey = 4) OR (key1 < 'uux' AND key1 > 'z')
2:舍去nokey = 4和key1 like ‘%d’,因為他們不能用作范圍scan,正確的舍去方法是用true代替她們,
(key1 < 'abc' AND (key1 LIKE 'abcde%' OR TRUE)) OR (key1 < 'bar' AND TRUE) OR (key1 < 'uux' AND key1 > 'z')
3: 以下條件總是true or false;
1:(key1 LIKE 'abcde%' OR TRUE)
is always true
2:(key1 < 'uux' AND key1 > 'z')
is always false
(key1 < 'abc' AND TRUE) OR (key1 < 'bar' AND TRUE) OR (FALSE)
4: 去掉不必要的true 和false條件:
(key1 < 'abc') OR (key1 < 'bar')
5:組合那些重疊的區間成一個:
(key1 < 'bar')
范圍條件的提取算法可以處理內嵌的and /or任意深度的構造,他的數去不依賴與他們出現在where子句中的順序;
2:多part index的范圍查詢:
index的多個部分的范圍條件是上面的擴展,被一個或幾個key元組來限制條件:
eg: 一個聯合索引定義:key1(key_part1,key_part2,key_part3),key元組以key order顯示如下:
key_part1 key_part2 key_part3 NULL 1 'abc' NULL 1 'xyz' NULL 2 'foo' 1 1 'abc' 1 1 'xyz' 1 2 'abc' 2 1 'aaa'
條件
定義的區間:key_part1
= 1
(1,-inf,-inf) <= (key_part1,key_part2,key_part3) < (1,+inf,+inf)
這區間包括第四,第五,第六元組。
相對,條件 key_part3
= 'abc'不能定義一個單獨的區間並且不能被區間scan方法使用(最左前綴index);
3:多值的區間優化:
以下col_name 是index 列:
col_name IN(val1, ..., valN) col_name = val1 OR ... OR col_name = valN
如果col_name 等於這些值中的任意一個返回true,
1:如果col_name 為unique index,則范圍的行評估為1,因為最多一個值只能對應一行;
2:否則,優化器估計范圍行數得使用index潛入和index的統計信息;
index潛入,優化器植入一個潛入在每個range的結尾並且用該范圍的行數來估計,eg:
,優化器植入兩個潛入在每個區間中來估計行數;index潛入提供精確的行估計,但是當表達式中的比較值越多,每個潛入對需要話費更多時間。用index統計信息缺乏精確但是較快。col_name
IN (10, 20, 30)
30727 rows in set (5.37 sec) mysql> explain select * from employees where first_name like 'm%' ; +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | employees | ALL | idx_fn_ln | NULL | NULL | NULL | 299290 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from employees where first_name like 'mart%' ; +----+-------------+-----------+-------+---------------+-----------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+-----------+---------+------+------+-----------------------+ | 1 | SIMPLE | employees | range | idx_fn_ln | idx_fn_ln | 16 | NULL | 1635 | Using index condition | +----+-------------+-----------+-------+---------------+-----------+---------+------+------+-----------------------+ 1 row in set (0.00 sec)
第一個條件查找從執行計划上看走的掃表(all),where條件得到的結果為所以數據行的1/10;第二條增加like條件的匹配精度,走的ICP range查找,得到的數據行大約是1/30,mysql
會根據查找的數據范圍(多少)決定走index range查找還是直接掃表(all)
mysql> desc select * from employees where first_name like 'ma%' and last_name like 'he%'; +----+-------------+-----------+-------+---------------+-----------+---------+------+-------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+-----------+---------+------+-------+-----------------------+ | 1 | SIMPLE | employees | range | idx_fn_ln | idx_fn_ln | 34 | NULL | 38174 | Using index condition | +----+-------------+-----------+-------+---------------+-----------+---------+------+-------+-----------------------+ 1 row in set (0.04 sec)
mysql> desc select * from employees where first_name like 'ma%' or last_name like 'he%'; +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | 1 | SIMPLE | employees | ALL | idx_fn_ln | NULL | NULL | NULL | 299290 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ 1 row in set (0.02 sec)
mysql> desc select * from employees where first_name in('mart','mori','moon'); +----+-------------+-----------+-------+---------------+-----------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------+-----------+---------+------+------+-----------------------+ | 1 | SIMPLE | employees | range | idx_fn_ln | idx_fn_ln | 16 | NULL | 710 | Using index condition | +----+-------------+-----------+-------+---------------+-----------+---------+------+------+-----------------------+ 1 row in set (0.02 sec)
mysql> explain select * from employees where emp_no = 11; +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables | +----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+ 1 row in set (0.01 sec)
Mysql發現where條件不可能成立 ,返回null