歡迎關注公衆號:【 愛編碼】
若是有須要後臺回覆 2019贈送 1T的學習資料哦!!
在這個快速發展的時代,時間變得
愈來愈重要,也流逝得很是得快,有些人長大了,有些人卻變老了。稍不留神,2019已通過完了三分之一。回首這四個月收穫什麼,懂得了什麼?歡迎留言分享給我喲。mysql
**言歸正傳:
MySQL的查詢怎麼才能更快,更合理?除了加索引還有什麼能夠學習的呢?**linux
要想更好地學習某樣東西,從其原理和運做方式入手更容易掌握。道理大家都懂,我就不廢話了。sql
下圖是MySQL查詢執行流程圖:segmentfault
3.服務端進行SQL解析、預處理、再由優化器生成對應的執行計劃。
4.MySQL根據優化器生成的執行計劃,調用存儲引擎的API來執行查詢。
5.將結果返回給客戶端。緩存
對於MySQL,最簡單的衡量查詢開銷的三個指標以下:性能優化
沒有哪一個指標可以完美地衡量查詢的開銷,但它們大體反映了MySQL在內部執行查詢時須要訪問多少數據,並能夠大概推算出查詢運行的時間。服務器
查詢慢的緣由基本都是:咱們的不合理操做致使查詢的多餘數據太多了。
常見緣由有如下:函數
1.查詢不須要的記錄。
2.多表關聯時返回所有列
3.老是取出所有列
最簡單且見效最快的方式就是給你的條件加索引(主鍵索引,普通索引,惟一索引等)。注:索引是要另開闢一塊空間存儲的,因此不能不要錢滴都加索引。性能
MySQL的子查詢實現是很是糟糕的。好比下面的學習
SELECT * FROM book WHERE book_id IN (SELECT book_id FROM author WHERE author_id = 1)
MySQL對IN()列表中的選項有專門的優化策略,通常會認爲MySQL會先執行子查詢返回全部包含author_id 爲1的book_id。
或許你想MySQL的運行時這樣子的:
SELECT GROUP_CONCAT(book_id) FROM author WHERE author_id = 1 SELECT * FROM book WHERE book_id IN (1,21,3,45,656,766,213,123)
可是,MySQL會將相關的外層表壓到子查詢中的,就是下面的樣子:
SELECT * FROM book WHERE EXISTS (SELECT * FROM author WHERE author_id = 1 AND book.book_id = author.book_id)
緣由:由於子查詢須要book_id ,因此MySQL認爲沒法先執行這個子查詢,而是先對book 進行全表掃描,而後再根據book_id進行子查詢。具體能夠EXPLAIN該SQL進行分析。
建議:
1.使用左外鏈接(LEFT OUTER JOIN)代替子查詢。
SELECT * from book LEFT OUTER JOIN author USING(book_id) WHERE author.author_id = 1
影響因素:還有數據表放的位置等,具體應用場景就只能你本身explain該語句對比哪一種性能比較好點。
2.確保ON或者USING子句的列上有索引
在建立索引的時候就要考慮到關聯的順序。
若是但願UNION的各個子句能根據LIMIT只取部分結果集,或者但願可以先排好序再合併結果集的話。
第一個例子:會將author 表和user 表兩個表都存放到一個臨時表中,再從臨時表中取出前20條。
(SELECT first_name FROM author ORDER BY last_name) UNION ALL (SELECT first_name FROM user ORDER BY last_name) LIMIT 20
對比上面的這樣子,就有很大的改善了。
(SELECT first_name FROM author ORDER BY last_name LIMIT 20) UNION ALL (SELECT first_name FROM user ORDER BY last_name LIMIT 20) LIMIT 20
好比:
求最小值
第一種方案:
SELECT MIN(id) FROM article WHERE author = 'zero'
第二種方案:
SELECT id FROM article USE INDEX(PRIMARY) WHERE author = 'zero' LIMIT 1
和第一種方案的對比,效果實際上是同樣的,可是它們的性能略有不一樣,具體還請本身具體場景分析,擇優選擇。
好比若是想統計文章id大於25的數量,能夠以下:
EXPLAIN SELECT COUNT(*) FROM article WHERE id >25
另一種思路:能夠先查詢文章總數,減去小於等於25的數量。僅僅提供思路,具體效果仍是你具體狀況,本身比較,擇優選擇。
EXPLAIN SELECT (SELECT COUNT(*) FROM article) - COUNT(*) FROM article WHERE id <=25
題外話:
若是須要區分不一樣顏色的商品數量時,能夠以下作法:
seelct count(color = 'blue' OR NULL) as blue,COUNT(color = 'red' OR NULL) AS RED FROM items
它們的優化最有效的方法就是用索引來。
可是GROUP BY有時候用得不對,索引是會失效的。
好比:把兩個單獨的索引合併成一個組合索引,即把where條件字段的索引和group by的分組字段索引組合成一個。
解決方法:參考這篇函數索引
下面這條查詢,很是常見。
select film_id,description from film order by title limit 50,5;
可是若是這個表很大的時候,那麼這個50變成100654這樣子的話,這裏MySQL就要掃描100654+5條數據,而後丟棄100654條,僅僅去最後5條。
一種思路:
select film_id,description from film inner join (select film_id from film order by title limit 50,5) as lim USING(film_id);
該思路是經過延遲關聯將大大提高查詢效率,它讓MySQL掃描儘量少的頁面。獲取須要訪問的記錄後,再更加關聯列會原表查詢所須要的全部列。以上並不必定符合你,具體還需explain對比擇優使用。
小結:
整體來講都是圍繞着儘可能少全表掃描,儘可能使用索引進行優化。
最後每每是要本身在實際場景多用explain分析是否有更好的sql解決方案。
1.隱式轉換致使索引失效.
這一點應當引發重視.也是開發中常常會犯的錯誤. 因爲表的字段tu_mdn定義爲varchar2(20),但在查詢時把該字段做爲number類型以where條件傳給Oracle,這樣會致使索引失效.
錯誤的例子:select * from test where tu_mdn=13333333333; 正確的例子:select * from test where tu_mdn='13333333333';
2. 對索引列進行運算致使索引失效
所指的對索引列進行運算*包括(+,-,,/,! 等)
錯誤的例子:select * from test where id-1=9; 正確的例子:select * from test where id=10;
3. 使用內部函數致使索引失效.
對於這樣狀況應當建立基於函數的索引.
// 錯誤的例子: select * from test where round(id)=10; //說明,此時id的索引已經不起做用了 //正確的例子:首先創建函數索引 create index test_id_fbi_idx on test(round(id)); //而後 select * from test where round(id)=10;
4. 不要將空的變量值直接與比較運算符(符號)比較。
若是變量可能爲空,應使用 IS NULL 或 IS NOT NULL 進行比較,或者使用 ISNULL 函數。
5. 不要在 SQL 代碼中使用雙引號。
由於字符常量使用單引號。若是沒有必要限定對象名稱,可使用(非 ANSI SQL 標準)括號將名稱括起來。
6. 如下使用會使索引失效,應避免使用
a. 使用 <> 、not in 、not exist、!=
b. like "%_" 百分號在前(可採用在創建索引時用reverse(columnName)這種方法處理)
c. 單獨引用複合索引裏非第一位置的索引列.應老是使用索引的第一個列,若是索引是創建在多個列上, 只有在它的第一個列被where子句引用時,優化器纔會選擇使用該索引。
d. 字符型字段爲數字時在where條件裏不添加引號.
e. 當變量採用的是times變量,而表的字段採用的是date變量時.或相反狀況。
暫時統計到這麼多,若是有更多的之後再補充。
EXPLAIN是用來分析SQL執行狀況分析的
EXPLAIN 命令的輸出內容大體以下:
mysql> explain select * from user_info where id = 2\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: user_info partitions: NULL type: const possible_keys: PRIMARY key: PRIMARY key_len: 8 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)
各列的含義以下:
- id: SELECT 查詢的標識符. 每一個 SELECT 都會自動分配一個惟一的標識符.
- select_type: SELECT 查詢的類型.
- table: 查詢的是哪一個表
- partitions: 匹配的分區
- type: join 類型
- possible_keys: 這次查詢中可能選用的索引
- key: 這次查詢中確切使用到的索引.
- ref: 哪一個字段或常數與 key 一塊兒被使用
- rows: 顯示此查詢一共掃描了多少行. 這個是一個估計值.
- filtered: 表示此查詢條件所過濾的數據的百分比
- extra: 額外的信息
更詳細的能夠參考這篇【性能優化神器 Explain 使用分析】或者【高性能MySQL】
查詢優化目的就是爲了快速獲得結果,因此每當寫完SQL應該思考如下幾點:
若是對 Java、大數據感興趣請長按二維碼關注一波,我會努力帶給大家價值。以爲對你哪怕有一丁點幫助的請幫忙點個贊或者轉發哦。
關注公衆號【愛編碼】,回覆2019有相關資料哦。