2014-04-10 14 views
6

Tôi có một bảng trông như thế này:Cần giúp đỡ để hiểu thế nào chỉ số mysql làm việc

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 

Nó có 177.892 hàng vào lúc này, và khi tôi chạy truy vấn sau đây:

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)); 

nó mất 0,87 giây để trả lại kết quả, giải thích là:

*************************** 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) 

cấu hình giống như sau:

+--------------------------------+----------+ 
| 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 | 
+--------------------------------+----------+ 

Cách này có vẻ quá cao đối với tôi. Tôi đã cố gắng để thay thế các userid = 8 and (host, name, sampleid) IN phần của truy vấn đầu tiên (userid, host, name, sampleid) IN và truy vấn này chạy khoảng 0.5s - gần 2 lần nhanh hơn, để tham khảo, đây là truy vấn:

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)); 

giải thích của nó trông như sau:

*************************** 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) 

Tiếp theo, tôi đã cập nhật bảng để chứa một cột tham gia duy nhất:

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`); 

Cập nhật các truy vấn để chỉ có 1 chuỗi tìm kiếm:

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')); 

Và bây giờ tôi nhận được kết quả tương tự trong 0,00 giây! Giải thích là:

*************************** 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) 

Vì vậy, để tóm tắt, đây là kết quả:

  1. m.userid = X AND (host, name, sampleid) IN - chỉ số được sử dụng, 85.560 dòng quét, chạy trong 0.9s
  2. (userid, host, name, sampleid) IN - index không được sử dụng, 171.121 các hàng được quét, chạy trong 0.5s
  3. cột bổ sung có chỉ mục phức hợp được thay thế bằng chỉ mục trên cột tiện ích nối - chỉ mục được sử dụng, 17 hàng được quét, chạy trong 0s

Tại sao truy vấn thứ hai chạy nhanh hơn lần đầu tiên? Và tại sao truy vấn thứ ba nhanh hơn nhiều so với phần còn lại? Tôi có nên giữ một cột như vậy với mục đích duy nhất là tìm kiếm nhanh hơn không?

phiên bản Mysql là: mysqld Ver 5.5.34-55 for Linux on x86_64 (Percona XtraDB Cluster (GPL), wsrep_25.9.r3928)

Trả lời

3

Chỉ số giúp thuật ngữ tìm kiếm của bạn trong mệnh đề WHERE bởi thu hẹp việc tìm kiếm càng nhiều càng tốt. Bạn có thể thấy điều này xảy ra ...

Trường rows của EXPLAIN đưa ra ước tính số lượng hàng mà truy vấn sẽ phải kiểm tra để tìm các hàng phù hợp với truy vấn của bạn.Bằng cách so sánh rows báo cáo trong mỗi GIẢI THÍCH, bạn có thể xem làm thế nào tốt hơn nhiều truy vấn tốt hơn được tối ưu hóa của bạn là:

 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 

Bạn cũng sẽ nhận thấy trong các chi tiết hiển thị hồ sơ nếu bạn chạy mà cho truy vấn thứ ba rằng "Đang gửi dữ liệu "nhanh hơn rất nhiều cho truy vấn nhanh hơn. Trạng thái tiến trình này cho biết mất bao lâu để sao chép các hàng từ công cụ lưu trữ lên đến lớp SQL của MySQL. Ngay cả khi thực hiện sao chép bộ nhớ sang bộ nhớ, việc này mất một khoảng thời gian cho hàng nghìn hàng. Đây là lý do tại sao các chỉ mục rất có lợi.

Để được giải thích hữu ích hơn, hãy xem bản trình bày của tôi How to Design Indexes, Really.

+0

Tôi đã thực sự chạy truy vấn đầu tiên nhiều lần với cùng một kết quả thời gian, do đó dữ liệu cũng được lưu vào bộ đệm. Tôi đã sử dụng rất nhiều câu lệnh '(x và x) hoặc (x và x)', nhưng vấn đề là, tại sao không 'ở đâu (a, b) trong ((x1, x2), (x3, x4))) 'làm việc? – Fluffy

+0

Đối với hiệu suất truy vấn thứ hai, có thể là phải tìm kiếm 85560 bản ghi (từ thứ cấp đến chỉ số nhóm) chậm hơn so với chỉ quét qua chỉ mục nhóm? –

+0

@Fluffy, tôi không chắc chắn, nó có thể chỉ đơn giản là cú pháp đó không được tối ưu hóa. –

Các vấn đề liên quan