好湿?好紧?好多水好爽自慰,久久久噜久噜久久综合,成人做爰A片免费看黄冈,机机对机机30分钟无遮挡

主頁 > 知識庫 > MySQL SQL優化教程之in和range查詢

MySQL SQL優化教程之in和range查詢

熱門標簽:天智外呼系統 福州呼叫中心外呼系統哪家好 房產智能外呼系統品牌 云南語音外呼系統平臺 沃克斯電梯外呼線路圖 400電話鄭州申請 地圖標注被騙三百怎么辦 常州電銷外呼系統一般多少錢 北京人工外呼系統價錢

首先我們來說下in()這種方式的查詢。在《高性能MySQL》里面提及用in這種方式可以有效的替代一定的range查詢,提升查詢效率,因為在一條索引里面,range字段后面的部分是不生效的。使用in這種方式其實MySQL優化器是轉化成了n*m種組合方式來進行查詢,最終將返回值合并,有點類似union但是更高效。同時它存在這一些問題:

老版本的MySQL在IN()組合條件過多的時候會發生很多問題。查詢優化可能需要花很多時間,并消耗大量內存。新版本MySQL在組合數超過一定的數量就不進行計劃評估了,這可能導致MySQL不能很好的利用索引。

這里的“一定數量”在MySQL5.6.5以及以后的版本中是由eq_range_index_dive_limit這個參數控制(感謝@葉金榮同學的指點)。默認設置是10,一直到5.7以后的版本默認會修改成200,當然我們是可以手動設置的。我們看下5.6手冊中的說明:

The eq_range_index_dive_limit system variable enables you to configure the number of values at which the optimizer switches from one row estimation strategy to the other. To disable use of statistics and always use index dives, set eq_range_index_dive_limit to 0. To permit use of index dives for comparisons of up to N equality ranges, set eq_range_index_dive_limit to N + 1.
eq_range_index_dive_limit is available as of MySQL 5.6.5. Before 5.6.5, the optimizer uses index dives, which is equivalent to eq_range_index_dive_limit=0.

也就是說:

1. eq_range_index_dive_limit = 0 只能使用index dive
2. 0 eq_range_index_dive_limit = N 使用index statistics
3. eq_range_index_dive_limit > N 只能使用index dive

index dive與index statistics是MySQL優化器對開銷代價的估算方法,前者統計速度慢但是能得到精準的值,后者統計速度快但是數據未必精準。

the optimizer can estimate the row count for each range using dives into the index or index statistics.

在MySQL5.7版本中將默認值從10修改成200目的是為了盡可能的保證范圍等值運算(IN())執行計劃盡量精準,因為IN()list的數量很多時候都是超過10的。

說在前面

今天文章的主題有兩個:

  1. range查詢與索引使用
  2. eq_range_index_dive_limit的說明

range查詢與索引使用

SQL如下:

SELECT * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') 
ORDER BY dateline DESC LIMIT 10;

索引如下:

+----------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| pre_forum_post |     0 | PRIMARY   |      1 | tid     | A     |    NULL |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     0 | PRIMARY   |      2 | position  | A     |  25521392 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     0 | pid     |      1 | pid     | A     |  25521392 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | fid     |      1 | fid     | A     |    1490 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | displayorder |      1 | tid     | A     |   880048 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | displayorder |      2 | invisible  | A     |   945236 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | displayorder |      3 | dateline  | A     |  25521392 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | first    |      1 | tid     | A     |   880048 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | first    |      2 | first    | A     |   1215304 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | new_auth   |      1 | authorid  | A     |   1963184 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | new_auth   |      2 | invisible  | A     |   1963184 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | new_auth   |      3 | tid     | A     |  12760696 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | idx_dt    |      1 | dateline  | A     |  25521392 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | mul_test   |      1 | tid     | A     |   880048 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | mul_test   |      2 | invisible  | A     |   945236 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | mul_test   |      3 | dateline  | A     |  25521392 |   NULL | NULL  |   | BTREE   |     |        | 
| pre_forum_post |     1 | mul_test   |      4 | pid     | A     |  25521392 |   NULL | NULL  |   | BTREE   |     |        | 
+----------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

看下執行計劃:

root@localhost 16:08:27 [ultrax]> explain SELECT * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') 
  -> ORDER BY dateline DESC LIMIT 10;
+----+-------------+----------------+-------+-------------------------------------------+--------------+---------+------+------+---------------------------------------+
| id | select_type | table     | type | possible_keys               | key     | key_len | ref | rows | Extra                 |
+----+-------------+----------------+-------+-------------------------------------------+--------------+---------+------+------+---------------------------------------+
| 1 | SIMPLE   | pre_forum_post | range | PRIMARY,displayorder,first,mul_test,idx_1 | displayorder | 4    | NULL |  54 | Using index condition; Using filesort | 
+----+-------------+----------------+-------+-------------------------------------------+--------------+---------+------+------+---------------------------------------+
1 row in set (0.00 sec)

MySQL優化器認為這是一個range查詢,那么(tid,invisible,dateline)這條索引中,dateline字段肯定用不上了,也就是說這個SQL最后的排序肯定會生成一個臨時結果集,然后再結果集里面完成排序,而不是直接在索引中直接完成排序動作,于是我們嘗試增加了一條索引。

root@localhost 16:09:06 [ultrax]> alter table pre_forum_post add index idx_1 (tid,dateline);  
Query OK, 20374596 rows affected, 0 warning (600.23 sec)
Records: 0 Duplicates: 0 Warnings: 0
root@localhost 16:20:22 [ultrax]> explain SELECT * FROM pre_forum_post force index (idx_1) WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10;
+----+-------------+----------------+------+---------------+-------+---------+-------+--------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows  | Extra    |
+----+-------------+----------------+------+---------------+-------+---------+-------+--------+-------------+
| 1 | SIMPLE   | pre_forum_post | ref | idx_1     | idx_1 | 3    | const | 120646 | Using where | 
+----+-------------+----------------+------+---------------+-------+---------+-------+--------+-------------+
1 row in set (0.00 sec)
root@localhost 16:22:06 [ultrax]> SELECT sql_no_cache * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10;
...
10 rows in set (0.40 sec)
root@localhost 16:23:55 [ultrax]> SELECT sql_no_cache * FROM pre_forum_post force index (idx_1) WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10;
...
10 rows in set (0.00 sec)

實驗證明效果是極好的,其實不難理解,上面我們就說了in()在MySQL優化器里面是以多種組合方式來檢索數據的,如果加了一個排序或者分組那勢必只能在臨時結果集上操作,也就是說索引里面即使包含了排序或者分組的字段依然是沒用的。唯一不滿的是MySQL優化器的選擇依然不夠靠譜。

總結下:在MySQL查詢里面使用in(),除了要注意in()list的數量以及eq_range_index_dive_limit的值以外(具體見下),還要注意如果SQL包含排序/分組/去重等等就需要注意索引的使用。

eq_range_index_dive_limit的說明

還是上面的案例,為什么idx_1無法直接使用?需要使用hint強制只用這個索引呢?這里我們首先看下eq_range_index_dive_limit的值。

root@localhost 22:38:05 [ultrax]> show variables like 'eq_range_index_dive_limit';
+---------------------------+-------+
| Variable_name       | Value |
+---------------------------+-------+
| eq_range_index_dive_limit | 2   | 
+---------------------------+-------+
1 row in set (0.00 sec)

根據我們上面說的這種情況0 eq_range_index_dive_limit = N使用index statistics,那么接下來我們用OPTIMIZER_TRACE來一看究竟。

{
 "index": "displayorder",
 "ranges": [
  "7932552 = tid = 7932552 AND -2 = invisible = -2",
  "7932552 = tid = 7932552 AND 0 = invisible = 0"
 ],
 "index_dives_for_eq_ranges": false,
 "rowid_ordered": false,
 "using_mrr": false,
 "index_only": false,
 "rows": 54,
 "cost": 66.81,
 "chosen": true
}
// index dive為false,最終chosen是true
...
{
 "index": "idx_1",
 "ranges": [
  "7932552 = tid = 7932552"
 ],
 "index_dives_for_eq_ranges": true,
 "rowid_ordered": false,
 "using_mrr": false,
 "index_only": false,
 "rows": 120646,
 "cost": 144776,
 "chosen": false,
 "cause": "cost"
}

我們可以看到displayorder索引的cost是66.81,而idx_1的cost是120646,而最終MySQL優化器選擇了displayorder這條索引。那么如果我們把eq_range_index_dive_limit設置>N是不是應該就會使用index dive計算方式,得到更準確的執行計劃呢?

root@localhost 22:52:52 [ultrax]> set eq_range_index_dive_limit = 3;
Query OK, 0 rows affected (0.00 sec)
root@localhost 22:55:38 [ultrax]> explain SELECT * FROM pre_forum_post WHERE tid=7932552 AND `invisible` IN('0','-2') ORDER BY dateline DESC LIMIT 10;
+----+-------------+----------------+------+-------------------------------------------+-------+---------+-------+--------+-------------+
| id | select_type | table     | type | possible_keys               | key  | key_len | ref  | rows  | Extra    |
+----+-------------+----------------+------+-------------------------------------------+-------+---------+-------+--------+-------------+
| 1 | SIMPLE   | pre_forum_post | ref | PRIMARY,displayorder,first,mul_test,idx_1 | idx_1 | 3    | const | 120646 | Using where | 
+----+-------------+----------------+------+-------------------------------------------+-------+---------+-------+--------+-------------+
1 row in set (0.00 sec)

optimize_trace結果如下

{
 "index": "displayorder",
 "ranges": [
  "7932552 = tid = 7932552 AND -2 = invisible = -2",
  "7932552 = tid = 7932552 AND 0 = invisible = 0"
 ],
 "index_dives_for_eq_ranges": true,
 "rowid_ordered": false,
 "using_mrr": false,
 "index_only": false,
 "rows": 188193,
 "cost": 225834,
 "chosen": true
}
...
{
 "index": "idx_1",
 "ranges": [
  "7932552 = tid = 7932552"
 ],
 "index_dives_for_eq_ranges": true,
 "rowid_ordered": false,
 "using_mrr": false,
 "index_only": false,
 "rows": 120646,
 "cost": 144776,
 "chosen": true
}
...
 "cost_for_plan": 144775,
 "rows_for_plan": 120646,
 "chosen": true
// 在備選索引選擇中兩條索引都被選擇,在最后的邏輯優化中選在了代價最小的索引也就是idx_1

以上就是在等值范圍查詢中eq_range_index_dive_limit的值怎么影響MySQL優化器計算開銷,從而影響索引的選擇。另外我們可以通過profiling來看看優化器的統計耗時:

index dive

+----------------------+----------+
| Status        | Duration |
+----------------------+----------+
| starting       | 0.000048 | 
| checking permissions | 0.000004 | 
| Opening tables    | 0.000015 | 
| init         | 0.000044 | 
| System lock     | 0.000009 | 
| optimizing      | 0.000014 | 
| statistics      | 0.032089 | 
| preparing      | 0.000022 | 
| Sorting result    | 0.000003 | 
| executing      | 0.000003 | 
| Sending data     | 0.000101 | 
| end         | 0.000004 | 
| query end      | 0.000002 | 
| closing tables    | 0.000009 | 
| freeing items    | 0.000013 | 
| cleaning up     | 0.000012 | 
+----------------------+----------+

index statistics

+----------------------+----------+
| Status        | Duration |
+----------------------+----------+
| starting       | 0.000045 | 
| checking permissions | 0.000003 | 
| Opening tables    | 0.000014 | 
| init         | 0.000040 | 
| System lock     | 0.000008 | 
| optimizing      | 0.000014 | 
| statistics      | 0.000086 | 
| preparing      | 0.000016 | 
| Sorting result    | 0.000002 | 
| executing      | 0.000002 | 
| Sending data     | 0.000016 | 
| Creating sort index | 0.412123 | 
| end         | 0.000012 | 
| query end      | 0.000004 | 
| closing tables    | 0.000013 | 
| freeing items    | 0.000023 | 
| cleaning up     | 0.000015 | 
+----------------------+----------+

可以看到當eq_range_index_dive_limit加大使用index dive時,優化器統計耗時明顯比ndex statistics方式來的長,但最終它使用了作出了更合理的執行計劃。統計耗時0.032089s vs .000086s,但是SQL執行耗時卻是約0.03s vs 0.41s。

附:如何使用optimize_trace

set optimizer_trace='enabled=on'; 
select * from information_schema.optimizer_trace\G
// 注:optimizer_trace建議只在session模式下開啟調試即可

參考資料

http://dev.mysql.com/doc/refman/5.6/en/range-optimization.html

http://imysql.com/2014/08/05/a-fake-bug-with-eq-range-index-dive-limit.shtml

http://blog.163.com/li_hx/blog/static/18399141320147521735442/

到此這篇關于MySQL SQL優化教程之in和range查詢的文章就介紹到這了,更多相關MySQL SQL優化之in和range查詢內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • MySQL查詢in操作 查詢結果按in集合順序顯示
  • 解決MySQL中IN子查詢會導致無法使用索引問題
  • mysql in語句子查詢效率慢的優化技巧示例
  • MySQL中使用or、in與union all在查詢命令下的效率對比
  • Mysql子查詢IN中使用LIMIT應用示例
  • MySQL查詢條件中in會用到索引嗎
  • 詳解 Mysql查詢結果順序按 in() 中ID 的順序排列
  • 淺談mysql的子查詢聯合與in的效率
  • MySQL之select in 子查詢優化的實現

標簽:拉薩 黔東 鹽城 徐州 沈陽 沈陽 移動 珠海

巨人網絡通訊聲明:本文標題《MySQL SQL優化教程之in和range查詢》,本文關鍵詞  MySQL,SQL,優化,教程,之,和,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《MySQL SQL優化教程之in和range查詢》相關的同類信息!
  • 本頁收集關于MySQL SQL優化教程之in和range查詢的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 天堂草在线观看国产AV| 日本98xxxxxxxxx| 精品国产乱码久久久久久樱花| 国产AV激情视频在线观看图片| 91久久精品在这里色伊人6882| 色涩王国| 少妇厨房与子伦厨房的互动方式| 欧美激情狂野欧美精品| 久久免费资源| a级片免费观看| 豪妇饱满的乳峰喷奶水| 性色av一区二区三区极品直播| 男人猛进女人身体视频| 久久久婷婷亚洲5月97色| 巨年少根与艳妇1一6| 国产精品高潮呻吟久久vr乱吗| 午夜激情视频免费| 一级@片| 日韩在线观看一区| 国产成人精品免费观看A片 | 狼人狠狠干| 吃奶摸下激烈视频AV国产精品| 亚洲精品无码av无码专区一本| 春闺梦里人免费观看| 日本大尺度a级床戏| 给清水文男主们开荤nph| 久久久久久精品免费免费看片| 嗯灬啊灬老师别揉我奶了| 欧美性活生活视频| 夜色爽爽| 囗交啪啪48式姿势图片| 99精产国品一二三产区区免费| 与同桌在教室里弄h| 成年女人男人免费视频播放| 人c交zzz000xxx| 关之琳一级A片| 992tv香蕉128tv在线观看| 韩国一级淫片视频免费播放| 爽好多水快深点小说| 欧美黄色| 亚洲骚片|