Tôi có một truy vấn được sử dụng để lấy số liệu thống kê lưu lượng truy cập internet của một số địa chỉ IP nhất định.
Có các trường địa chỉ IP riêng cho hosts
và các khối IP được gọi assignments
. Dữ liệu được lưu trữ trong khoảng thời gian 5 phút.
Các kết quả truy vấn được nhóm trên cột thời gian và tổng số SUM trong và ngoài khoảng thời gian 5 phút này được sử dụng để vẽ đồ thị.
Bảng được gọi traffic
và chứa (vào cuối tháng) khoảng 21 triệu hồ sơ.
SHOW CREATE table traffic:
CREATE TABLE `traffic` (
`type` enum('v4_assignment','v4_host','v6_subnet','v6_assignment','v6_host') NOT NULL,
`type_id` int(11) unsigned NOT NULL,
`time` int(32) unsigned NOT NULL,
`bytesin` bigint(20) unsigned NOT NULL default '0',
`bytesout` bigint(20) unsigned NOT NULL default '0',
KEY `basic_select` (`type_id`,`time`,`type`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SELECT traffic.time, SUM(traffic.bytesin), SUM(traffic.bytesout) FROM traffic
WHERE (
( traffic.type = 'v4_assignment' AND type_id IN (231, between 20 to 100 ids,265)) OR
( traffic.type = 'v4_host' AND type_id IN (131, ... a lot of ids... ,1506)))
AND traffic.time >= 1343772000 AND traffic.time < 1346450399
GROUP BY traffic.time
ORDER BY traffic.time;
Sau đây là explain
đầu ra cho truy vấn trên:
+----+-------------+---------+-------+---------------+--------------+---------+------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+--------------+---------+------+--------+----------------------------------------------+
| 1 | SIMPLE | traffic | range | basic_select | basic_select | 8 | NULL | 891319 | Using where; Using temporary; Using filesort |
+----+-------------+---------+-------+---------------+--------------+---------+------+--------+----------------------------------------------+
show indexes from traffic;
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| traffic | 1 | basic_select | 1 | type_id | A | 13835 | NULL | NULL | | BTREE | |
| traffic | 1 | basic_select | 2 | time | A | 18470357 | NULL | NULL | | BTREE | |
| traffic | 1 | basic_select | 3 | type | A | 18470357 | NULL | NULL | | BTREE | |
+---------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
Truy vấn này mất từ 30 giây đến 30 phút để hoàn thành. Tôi hy vọng tôi có thể cải thiện mọi thứ bằng cách sử dụng các chỉ mục tốt hơn hoặc có thể sử dụng một truy vấn khác, nhưng tôi không thể tìm ra nó.
CẬP NHẬT:
Theo lời khuyên của các nhà bình luận hữu ích, tôi đã tạo khóa chính và thêm chỉ mục traffic_pk (time, type, type_id, id)
. Thật không may, hóa ra cardinality của chỉ mục mới này bằng / thấp hơn chỉ số ban đầu của tôi (basic_select) và MySQL vẫn sử dụng khóa gốc của tôi.
CẬP NHẬT 2:
Tôi đã bỏ chỉ mục ban đầu của mình basic_select
và bây giờ nó EXPLAIN
hiển thị rows
giá trị cao hơn , nhưng ít bước hơn trong các EXTRA
trường. Ngoài ra thời gian thực hiện truy vấn đã giảm xuống dưới một phút! (vẫn còn hơi chậm, nhưng là một cải tiến lớn!).
mysql> SHOW CREATE TABLE traffic_test \G;
*************************** 1. row ***************************
Table: traffic_test
Create Table: CREATE TABLE `traffic_test` (
`traffic_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` enum('v4_assignment','v4_host','v6_subnet','v6_assignment','v6_host') NOT NULL,
`type_id` int(11) unsigned NOT NULL,
`time` int(32) unsigned NOT NULL,
`bytesin` bigint(20) unsigned NOT NULL DEFAULT '0',
`bytesout` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`time`,`type`,`type_id`,`traffic_id`),
KEY `traffic_id_IDX` (`traffic_id`)
) ENGINE=InnoDB AUTO_INCREMENT=24545159 DEFAULT CHARSET=latin1
Các chỉ mục trên bảng:
mysql> SHOW INDEX FROM traffic;
+--------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| traffic_test | 0 | PRIMARY | 1 | time | A | 18 | NULL | NULL | | BTREE | |
| traffic_test | 0 | PRIMARY | 2 | type | A | 38412 | NULL | NULL | | BTREE | |
| traffic_test | 0 | PRIMARY | 3 | type_id | A | 24545609 | NULL | NULL | | BTREE | |
| traffic_test | 0 | PRIMARY | 4 | traffic_id | A | 24545609 | NULL | NULL | | BTREE | |
| traffic_test | 1 | traffic_id_IDX | 1 | traffic_id | A | 24545609 | NULL | NULL | | BTREE | |
+--------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
Ngoài ra tôi đã đơn giản hóa truy vấn bằng cách không sử dụng OR
:
SELECT SQL_NO_CACHE traffic.time, SUM(traffic.bytesin), SUM(traffic.bytesout)
FROM traffic
WHERE traffic.type LIKE 'v4_host' AND type_id IN (131,1974,1976,1514,1516,2767,2730,2731,2732,2733,2734,2769,2994,2709,1,4613,4614,4615,4616,326,1520,2652,1518,1521,1522,1523,1524,1525,2203,1515,1513,1467,1508,1973,1510,1975,1511,1475,1476,1468,1469,1470,1471,1472,1473,1500,1507,1478,1480,1481,1482,1483,1484,1485,1479,1486,1487,1488,1489,1490,1491,1495,1499,1494,2269,1474,1519,2204,2976,1922,1493,1492,1497,1496,1498,1501,1502,1503,1526,1509,1506)
AND traffic.time >= 1342181721
AND traffic.time < 1343391321
GROUP BY traffic.time ASC;
Thực thi cũ của truy vấn này:
3980 rows in set (6 min 15.27 sec)
Thời gian thực hiện mới:
3980 rows in set (24.80 sec)
GIẢI THÍCH đầu ra:
+----+-------------+---------+-------+---------------+---------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+------+----------+-------------+
| 1 | SIMPLE | traffic | range | PRIMARY | PRIMARY | 4 | NULL | 12272804 | Using where |
+----+-------------+---------+-------+---------------+---------+---------+------+----------+-------------+
Giá trị hàng vẫn còn khá cao. Tôi nghĩ rằng tôi có thể cải thiện điều này bằng cách chuyển đổi thứ tự type
và type_id
trong chỉ mục vì chỉ có 4 loại có thể và nhiều loại_ids nữa.
Đây có phải là một giả định chính xác?