2014-04-10 33 views
6

我有一個表,看起來像這樣:需要幫助瞭解MySQL的指標是如何工作的

CREATE TABLE `metric` (
    `metricid` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `host` varchar(50) NOT NULL, 
    `userid` int(10) unsigned DEFAULT NULL, 
    `lastmetricvalue` double DEFAULT NULL, 
    `receivedat` int(10) unsigned DEFAULT NULL, 
    `name` varchar(255) NOT NULL, 
    `sampleid` tinyint(3) unsigned NOT NULL, 
    `type` tinyint(3) unsigned NOT NULL DEFAULT '0', 
    `lastrawvalue` double NOT NULL, 
    `priority` tinyint(3) unsigned NOT NULL DEFAULT '0', 
    PRIMARY KEY (`metricid`), 
    UNIQUE KEY `unique-metric` (`userid`,`host`,`name`,`sampleid`) 
) ENGINE=InnoDB AUTO_INCREMENT=1000000221496 DEFAULT CHARSET=utf8 

它有177892行的那一刻,當我運行以下查詢:

select metricid, lastrawvalue, receivedat, name, sampleid 
FROM metric m 
WHERE m.userid = 8 
    AND (host, name, sampleid) IN (('localhost','0.4350799184758216cpu-3/cpu-nice',0), 
    ('localhost','0.4350799184758216cpu-3/cpu-system',0), 
    ('localhost','0.4350799184758216cpu-3/cpu-idle',0), 
    ('localhost','0.4350799184758216cpu-3/cpu-wait',0), 
    ('localhost','0.4350799184758216cpu-3/cpu-interrupt',0), 
    ('localhost','0.4350799184758216cpu-3/cpu-softirq',0), 
    ('localhost','0.4350799184758216cpu-3/cpu-steal',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-user',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-nice',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-system',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-idle',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-wait',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-interrupt',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-softirq',0), 
    ('localhost','0.4350799184758216cpu-4/cpu-steal',0), 
    ('localhost','_util/billing-bytes',0),('localhost','_util/billing-metrics',0)); 

它需要0.87秒返回結果,說明的是:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: m 
     type: ref 
possible_keys: unique-metric 
      key: unique-metric 
     key_len: 5 
      ref: const 
     rows: 85560 
     Extra: Using where 
1 row in set (0.00 sec) 

輪廓看起來是這樣的:

+--------------------------------+----------+ 
| Status       | Duration | 
+--------------------------------+----------+ 
| starting      | 0.000160 | 
| checking permissions   | 0.000010 | 
| Opening tables     | 0.000021 | 
| exit open_tables()    | 0.000008 | 
| System lock     | 0.000008 | 
| mysql_lock_tables(): unlocking | 0.000005 | 
| exit mysqld_lock_tables()  | 0.000007 | 
| init       | 0.000068 | 
| optimizing      | 0.000018 | 
| statistics      | 0.000091 | 
| preparing      | 0.000042 | 
| executing      | 0.000005 | 
| Sending data     | 0.870180 | 
| innobase_commit_low():trx_comm | 0.000012 | 
| Sending data     | 0.000111 | 
| end       | 0.000009 | 
| query end      | 0.000009 | 
| ha_commit_one_phase(-1)  | 0.000015 | 
| innobase_commit_low():trx_comm | 0.000004 | 
| ha_commit_one_phase(-1)  | 0.000005 | 
| query end      | 0.000005 | 
| closing tables     | 0.000012 | 
| freeing items     | 0.000562 | 
| logging slow query    | 0.000005 | 
| cleaning up     | 0.000005 | 
| sleeping      | 0.000006 | 
+--------------------------------+----------+ 

這對我來說似乎太高了。我試着第一次查詢的userid = 8 and (host, name, sampleid) IN部分取代至(userid, host, name, sampleid) IN這個查詢運行約0.5秒 - 快近2倍,僅供參考,這裏的查詢:

select metricid, lastrawvalue, receivedat, name, sampleid 
FROM metric m 
WHERE (userid, host, name, sampleid) IN ((8,'localhost','0.4350799184758216cpu-3/cpu-nice',0), 
    (8,'localhost','0.4350799184758216cpu-3/cpu-system',0), 
    (8,'localhost','0.4350799184758216cpu-3/cpu-idle',0), 
    (8,'localhost','0.4350799184758216cpu-3/cpu-wait',0), 
    (8,'localhost','0.4350799184758216cpu-3/cpu-interrupt',0), 
    (8,'localhost','0.4350799184758216cpu-3/cpu-softirq',0), 
    (8,'localhost','0.4350799184758216cpu-3/cpu-steal',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-user',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-nice',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-system',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-idle',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-wait',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-interrupt',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-softirq',0), 
    (8,'localhost','0.4350799184758216cpu-4/cpu-steal',0), 
    (8,'localhost','_util/billing-bytes',0), 
    (8,'localhost','_util/billing-metrics',0)); 

其解釋如下所示:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: m 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 171121 
     Extra: Using where 
1 row in set (0.00 sec) 

接下來,我已經更新了表中包含一個聯接的列:

alter table `metric` add `forindex` varchar(120) not null default ''; 
update metric set forindex = concat(userid,`host`,`name`,sampleid); 
alter table metric add index `forindex` (`forindex`); 

更新查詢只1串搜索有:

select metricid, lastrawvalue, receivedat, name, sampleid 
FROM metric m 
WHERE (forindex) IN (('8localhost0.4350799184758216cpu-3/cpu-nice0'), 
    ('8localhost0.4350799184758216cpu-3/cpu-system0'), 
    ('8localhost0.4350799184758216cpu-3/cpu-idle0'), 
    ('8localhost0.4350799184758216cpu-3/cpu-wait0'), 
    ('8localhost0.4350799184758216cpu-3/cpu-interrupt0'), 
    ('8localhost0.4350799184758216cpu-3/cpu-softirq0'), 
    ('8localhost0.4350799184758216cpu-3/cpu-steal0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-user0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-nice0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-system0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-idle0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-wait0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-interrupt0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-softirq0'), 
    ('8localhost0.4350799184758216cpu-4/cpu-steal0'), 
    ('8localhost_util/billing-bytes0'), 
    ('8localhost_util/billing-metrics0')); 

現在我在0.00秒內得到相同的結果!解釋是:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: m 
     type: range 
possible_keys: forindex 
      key: forindex 
     key_len: 362 
      ref: NULL 
     rows: 17 
     Extra: Using where 
1 row in set (0.00 sec) 

所以總結一下,這裏的結果:

  1. m.userid = X AND (host, name, sampleid) IN - 指數使用,85560行掃描,運行在0.9S
  2. (userid, host, name, sampleid) IN - 指數不使用,171121掃描的行數,以0.5s運行
  3. 其他列的複合索引替換爲級聯實用程序列上的索引 - 使用的索引,掃描的17行,運行於0s

爲什麼第二個查詢比第一個查詢運行得更快?爲什麼第三個查詢比其他查詢快得多?我應該保留這樣一個專欄,以便更快搜索?

MySQL的版本是: mysqld Ver 5.5.34-55 for Linux on x86_64 (Percona XtraDB Cluster (GPL), wsrep_25.9.r3928)

回答

3

指標通過儘可能縮小搜索幫助您的搜索字詞WHERE子句。您可以看到發生這種情況...

EXPLAIN的rows字段提供了估計查詢將檢查多少行以查找與您的查詢匹配的行。通過比較每個EXPLAIN報道rows,你可以看到你更好地優化查詢如何更好地爲:

 rows: 85560 -- first query 

    rows: 171121 -- second query examines 2x more rows, but it was probably 
        -- faster because the data was buffered after the first query 

    rows: 17 -- third query examines 5,000x fewer rows than first query 

您也將看到在顯示個人資料的詳細信息,如果您運行的是第三查詢「正在發送數據「對於更快的查詢速度要快得多。此進程狀態指示將行從存儲引擎複製到MySQL的SQL層需要多長時間。即使在進行內存到內存的拷貝時,對於成千上萬的行也需要一段時間。這就是爲什麼指數非常有益。

如需更多有用的解釋,請參閱我的演示文稿How to Design Indexes, Really

+0

我實際上已經用相同的時間結果多次運行第一個查詢,所以數據也被緩衝了。我最終使用了大量的'(x和x)或(x和x)'語句,但事實是,爲什麼不在((x1,x2),(x3,x4) ))工作? – Fluffy

+0

對於第二個查詢性能,是否需要查找85560記錄(從二級到聚簇索引)比僅僅通過聚簇索引掃描要慢? –

+0

@Fluffy,我不確定,它可能只是語法沒有優化。 –