mysql的使用過(guò)成中渠欺,SELECT的使用是非常頻繁的,那么理解SELECT的查詢操作就顯得非常重要莱革。
對(duì)于查詢處理峻堰,可將其分為邏輯查詢處理和物理查詢處理。邏輯查詢處理表示執(zhí)行查詢應(yīng)該產(chǎn)生什么樣的結(jié)果盅视,而物理查詢代表mysql數(shù)據(jù)庫(kù)是如何得到該結(jié)果的捐名。兩種查詢的方法可能完全不同,但是得到的結(jié)果是相同的闹击。
1.邏輯查詢處理
SQL的邏輯查詢處理的順序如下:
(7)? ? SELECT
(8)?????DISTINCT?
(1)?????FROM?
(3)??????JOIN?
(2)?????ON?
(4)?????WHERE?
(5)?????GROUP?BY?
(6)?????HAVING?
(9)?????ORDER?BY?
(10)????LIMIT?
我們老具體分析查詢處理的各個(gè)階段:
FORM: 對(duì)FROM的左邊的表和右邊的表計(jì)算笛卡爾積镶蹋。產(chǎn)生虛表VT1
ON: 對(duì)虛表VT1進(jìn)行ON篩選,只有那些符合的行才會(huì)被記錄在虛表VT2中赏半。
JOIN: 如果指定了OUTER JOIN(比如left join贺归、 right join),那么保留表中未匹配的行就會(huì)作為外部行添加到虛擬表VT2中断箫,產(chǎn)生虛擬表VT3, rug from子句中包含兩個(gè)以上的表的話拂酣,那么就會(huì)對(duì)上一個(gè)join連接產(chǎn)生的結(jié)果VT3和下一個(gè)表重復(fù)執(zhí)行步驟1~3這三個(gè)步驟,一直到處理完所有的表為止仲义。
WHERE: 對(duì)虛擬表VT3進(jìn)行WHERE條件過(guò)濾婶熬。只有符合的記錄才會(huì)被插入到虛擬表VT4中。
GROUP BY: 根據(jù)group by子句中的列埃撵,對(duì)VT4中的記錄進(jìn)行分組操作赵颅,產(chǎn)生VT5.
CUBE | ROLLUP: 對(duì)表VT5進(jìn)行cube或者rollup操作,產(chǎn)生表VT6.
HAVING: 對(duì)虛擬表VT6應(yīng)用having過(guò)濾暂刘,只有符合的記錄才會(huì)被 插入到虛擬表VT7中饺谬。
SELECT: 執(zhí)行select操作,選擇指定的列谣拣,插入到虛擬表VT8中募寨。
DISTINCT: 對(duì)VT8中的記錄進(jìn)行去重。產(chǎn)生虛擬表VT9.
ORDER BY: 將虛擬表VT9中的記錄按照進(jìn)行排序操作森缠,產(chǎn)生虛擬表VT10.
LIMIT:取出指定行的記錄绪商,產(chǎn)生虛擬表VT11, 并將結(jié)果返回。
2.物理查詢處理
雖然SQL的邏輯查詢是根據(jù)上述進(jìn)行查詢辅鲸,但是數(shù)據(jù)庫(kù)也許并不會(huì)完全按照邏輯查詢處理的方式來(lái)進(jìn)行查詢格郁。MYSQL數(shù)據(jù)庫(kù)有兩個(gè)組件Parser(分析SQL語(yǔ)句)和Optimizer(優(yōu)化)。
從官方手冊(cè)上看独悴,可以理解為例书,MySQL采用了基于開銷的優(yōu)化器,以確定處理查詢的最解方式刻炒,也就是說(shuō)執(zhí)行查詢之前决采,都會(huì)先選擇一條自以為最優(yōu)的方案,然后執(zhí)行這個(gè)方案來(lái)獲取結(jié)果坟奥。在很多情況下树瞭,MySQL能夠計(jì)算最佳的可能查詢計(jì)劃拇厢,但在某些情況下,MySQL沒有關(guān)于數(shù)據(jù)的足夠信息晒喷,或者是提供太多的相關(guān)數(shù)據(jù)信息孝偎,估測(cè)就不那么友好了。
1.本人認(rèn)為解析器解析后的執(zhí)行順序是有寫變化凉敲,首先討論沒有創(chuàng)建索引的情況衣盾,having和group by的順序應(yīng)該在select之后:
FROM clause
WHERE clause
SELECT clause
GROUP BY clause
HAVING clause
ORDER BY clause
為什么這樣說(shuō)呢,因?yàn)閙ysql中允許在having和group by語(yǔ)句中使用別名(alias)爷抓,但where語(yǔ)句中是不能直接使用select語(yǔ)句中的別名的势决,我們來(lái)看一個(gè)例子:
mysql> select * from formatting;
+---------+------------+-------+--------+-----+
| orderid | orderdate? | empid | custid | qty |
+---------+------------+-------+--------+-----+
|? ? ? 1 | 2010-01-02 |? ? 3 | A? ? ? |? 10 |
|? ? ? 2 | 2010-04-02 |? ? 2 | B? ? ? |? 20 |
|? ? ? 3 | 2010-05-02 |? ? 1 | A? ? ? |? 30 |
|? ? ? 4 | 2010-07-02 |? ? 3 | D? ? ? |? 40 |
|? ? ? 5 | 2011-01-02 |? ? 4 | A? ? ? |? 20 |
|? ? ? 6 | 2011-01-02 |? ? 3 | B? ? ? |? 30 |
|? ? ? 7 | 2011-01-02 |? ? 1 | C? ? ? |? 40 |
|? ? ? 8 | 2009-01-02 |? ? 2 | A? ? ? |? 10 |
|? ? ? 9 | 2009-01-02 |? ? 3 | B? ? ? |? 20 |
+---------+------------+-------+--------+-----+
9 rows in set (0.00 sec)
在where中使用別名,數(shù)據(jù)庫(kù)返回error說(shuō)找不到where中的id列蓝撇,說(shuō)明數(shù)據(jù)庫(kù)還沒有解析select果复。
mysql> select custid as id,count(orderid) as cnt from formatting where id='A';
ERROR 1054 (42S22): Unknown column 'id' in 'where clause'
但是在group by和having中使用別名mysql可以成功解析。
mysql> select custid as id,count(orderid) as cnt from formatting group by id having cnt>2;
+----+-----+
| id | cnt |
+----+-----+
| A? |? 4 |
| B? |? 3 |
+----+-----+
2 rows in set (0.00 sec)
2.存在索引的情況下渤昌,優(yōu)化器優(yōu)先使用條件用到索引且最優(yōu)的方案据悔,通過(guò)例子來(lái)看。
? ? 當(dāng)sql條件有多個(gè)索引可以選擇耘沼,且存在索引能唯一定位結(jié)果時(shí)极颓,mysql優(yōu)化器將直接使用效率最高的索引執(zhí)行。
當(dāng)結(jié)果是某個(gè)集合時(shí)群嗤,mysql優(yōu)化器將使用merge索引的方式提高查詢效率菠隆,并且雖然我的where順序是更少數(shù)值的在后面,但mysql優(yōu)化器會(huì)自動(dòng)修正順序狂秘,先查找empid的索引骇径。
從這里可以看出索引的建立對(duì)于sql的優(yōu)化是有一定關(guān)鍵作用的。但不是所有的優(yōu)化器使用的都是最優(yōu)的方式者春,可以具體方案具體分析破衔。