Vấn đề về hiệu năng của MySQL khi sử dụng cột datetime được lập chỉ mục


14

Tôi đã cố gắng giải quyết vấn đề sau khoảng một giờ và vẫn không giải quyết được gì thêm.

Được rồi, tôi có một bảng (MyISAM):

+---------+-------------+------+-----+-------------------+----------------+
| Field   | Type        | Null | Key | Default           | Extra          |
+---------+-------------+------+-----+-------------------+----------------+
| id      | int(11)     | NO   | PRI | NULL              | auto_increment |
| http    | smallint(3) | YES  | MUL | 200               |                |
| elapsed | float(6,3)  | NO   |     | NULL              |                |
| cached  | tinyint(1)  | YES  |     | NULL              |                |
| ip      | int(11)     | NO   |     | NULL              |                |
| date    | timestamp   | NO   | MUL | CURRENT_TIMESTAMP |                |
+---------+-------------+------+-----+-------------------+----------------+

Xin đừng bận tâm đến các chỉ số, tôi đã chơi xung quanh để cố gắng tìm một giải pháp. Bây giờ, đây là truy vấn của tôi.

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE DATE(date) >= cast(date_sub(date(NOW()),interval 24 hour) as datetime)
GROUP BY http
ORDER BY count;

bảng đang lưu trữ thông tin về các yêu cầu web đến vì vậy nó là một cơ sở dữ liệu khá lớn.

+-----------+
| count(id) |
+-----------+
|    782412 |
+-----------+

lưu ý rằng không có cách nào tốt hơn để đặt khóa chính vì cột id sẽ là định danh duy nhất tôi có. Truy vấn được đề cập ở trên mất khoảng 0,6-1,6 giây để chạy.

Chỉ số nào sẽ thông minh? Tôi hình dung rằng ngày lập chỉ mục sẽ mang lại cho tôi tính chính xác "xấu" và do đó MySQL sẽ không sử dụng nó. http cũng là một lựa chọn tồi vì chỉ có khoảng 20 giá trị khác nhau có thể.

Cảm ơn sự giúp đỡ của bạn!

Cập nhật 1 Tôi đã thêm một chỉ mục vào (http, ngày) như ypercube đề xuất:

mysql> CREATE INDEX httpDate ON reqs (http, date);

và sử dụng truy vấn của mình, nhưng nó thực hiện không kém. Chỉ số được thêm vào:

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| reqs  |          0 | PRIMARY  |            1 | id          | A         |      798869 |     NULL | NULL   |      | BTREE      |         |
| reqs  |          1 | httpDate |            1 | http        | A         |          19 |     NULL | NULL   | YES  | BTREE      |         |
| reqs  |          1 | httpDate |            2 | date        | A         |       99858 |     NULL | NULL   |      | BTREE      |         |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

GIẢI THÍCH

+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key      | key_len | ref  | rows  | Extra                                                     |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
|  1 | PRIMARY            | r     | range | NULL          | httpDate | 3       | NULL |    20 | Using index for group-by; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | ri    | ref   | httpDate      | httpDate | 3       | func | 41768 | Using where; Using index                                  |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+

Phiên bản máy chủ MySQL:

mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+---------------------+
| Variable_name           | Value               |
+-------------------------+---------------------+
| protocol_version        | 10                  |
| version                 | 5.1.73              |
| version_comment         | Source distribution |
| version_compile_machine | x86_64              |
| version_compile_os      | redhat-linux-gnu    |
+-------------------------+---------------------+
5 rows in set (0.00 sec)

Bạn cũng có thể thêm phiên bản mysql và công cụ của bảng là gì? (myisam hoặc innodb)
ypercubeᵀᴹ

MyISAM và 5.1.73 - tất cả các chi tiết hiện có trong bài.
Robin Heller

Tôi sợ nó có thể phải làm với httpcột là nullable. Tôi sẽ điều tra vào ngày mai, nếu tôi tìm thấy thời gian.
ypercubeᵀᴹ

Tôi sợ nó có thể phải làm với cột http là nullable. Tôi sẽ điều tra vào ngày mai, nếu tôi tìm thấy thời gian. Bạn có thể kiểm tra bằng cách tạo một bảng giống hệt (ngoại trừ http NOT NULL) và sao chép tất cả dữ liệu vào bảng đó (ngoại trừ các hàng có http NULL tất nhiên.)
ypercubeᵀᴹ

Thay đổi nó thành KHÔNG NULL (điều này hoàn toàn có thể, tôi không bận tâm lắm khi tạo bảng) đã tăng hiệu suất lên khoảng ~ 1s - 1.6 giây cho truy vấn (truy vấn của tôi). Cảm ơn cho nỗ lực của bạn cho đến bây giờ.
Robin Heller

Câu trả lời:


10

Tôi có ba gợi ý

SUGGESTION # 1: Viết lại truy vấn

Bạn nên viết lại truy vấn như sau

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
GROUP BY http
ORDER BY count;

hoặc là

SELECT * FROM
(
    SELECT http,
    COUNT( http )  AS count 
    FROM reqs
    WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
    GROUP BY http
) A ORDER BY count;

WHERE không nên có chức năng ở cả hai phía của dấu bằng. Có ngày ở phía bên trái của dấu bằng giúp Trình tối ưu hóa truy vấn dễ dàng hơn khi sử dụng chỉ mục chống lại nó.

SUGGESTION # 2: Chỉ số hỗ trợ

Tôi cũng sẽ đề xuất một chỉ số khác

ALTER TABLE reqs ADD INDEX date_http_ndx (date,http); -- not (http,date) 

Tôi đề nghị thứ tự các cột này bởi vì date tất cả các mục sẽ nằm liền kề trong chỉ mục. Sau đó, truy vấn chỉ cần thu thập httpcác giá trị mà không bỏ qua các khoảng trống http.

SUGGESTION # 3: Bộ đệm chính lớn hơn (Tùy chọn)

MyISAM chỉ sử dụng bộ đệm ẩn chỉ mục. Vì truy vấn không nên chạm vào .MYDtệp, bạn nên sử dụng Bộ đệm khóa MyISAM lớn hơn một chút.

Để đặt thành 256M

SET @newsize = 1024 * 1024 * 256;
SET GLOBAL key_buffer_size = @newsize;

Sau đó, đặt nó vào my.cnf

[mysqld]
key_buffer_size = 256M

Khởi động lại MySQL không bắt buộc

Hãy thử một lần !!!


Tôi đã thử các truy vấn bạn đưa cho tôi. # 1 thực hiện tốt như đề xuất khác hoặc của riêng tôi, lần thứ hai thực sự hoạt động kém hơn. Điều tương tự đối với Chỉ số hỗ trợ - làm cho hiệu suất giảm khoảng 75 phần trăm. Bây giờ tôi sẽ thử bộ đệm lớn hơn, cảm ơn bạn!
Robin Heller

Tôi đã chấp nhận câu trả lời của bạn mặc dù nó không khắc phục được vấn đề, với bộ đệm phím lớn hơn tuy nhiên nó hoạt động tốt hơn một chút. Kết thúc điều này vì nó là giải pháp tốt nhất trong tất cả. Cảm ơn bạn!
Robin Heller

Để Đề xuất số 2 hoạt động, có thể cần phải thêm "SỬ DỤNG INDEX" hoặc "FORCE INDEX" trong truy vấn, ít nhất đó là những gì tôi phải làm để tăng tốc truy vấn của mình sau khi tạo chỉ mục như thế.
Johano Fierra

-2

Thay đổi loại cột ngày của bạn thành một số nguyên. Lưu trữ ngày dưới dạng một ngày Unix trong số nguyên. Dấu thời gian lớn hơn nhiều so với int. Bạn sẽ nhận được một số tiếng nổ từ đó.


2
Bạn đang giỡn hả? Cả hai INTTIMESTAMPcần 4 byte.
ypercubeᵀᴹ

2
Không đề cập đến việc bạn mất tất cả các hàm datetime khi bạn đang lưu trữ ngày hoặc dấu thời gian dưới dạng số nguyên.
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.