인덱스 날짜 시간 열을 사용하는 MySQL 성능 문제


15

나는 지금 약 1 시간 동안 다음 문제를 해결하려고했지만 여전히 더 이상 얻지 못했습니다.

좋아, 나는 테이블 (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 |                |
+---------+-------------+------+-----+-------------------+----------------+

색인을 신경 쓰지 마십시오. 솔루션을 찾으려고 노력하고 있습니다. 자, 여기 내 질문이 있습니다.

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;

테이블은 들어오는 웹 요청에 대한 정보를 저장하므로 다소 큰 데이터베이스입니다.

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

id 열이 내가 가진 유일한 식별자 이기 때문에 기본 키를 설정하는 더 좋은 방법은 없습니다 . 위에서 언급 한 쿼리를 실행하는 데 약 0.6-1.6 초가 걸립니다.

어느 인덱스가 영리할까요? 색인 날짜 가 "나쁜"카디널리티를 제공하므로 MySQL이 사용하지 않을 것이라고 생각했습니다. 가능한 값이 약 20 가지 밖에 없으므로 http 도 좋지 않습니다.

도와 주셔서 감사합니다!

업데이트 1 ypercube가 제안한대로 (http, date) 에 색인을 추가했습니다 .

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

그의 쿼리를 사용했지만 똑같이 나빴습니다. 추가 된 색인 :

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

그리고 설명

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

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)

mysql 버전을 추가 할 수 있습니까? 그리고 테이블 엔진은 무엇입니까? (myisam 또는 innodb)
— ypercubeᵀᴹ

MyISAM 및 5.1.73-게시물의 모든 세부 사항.
— Robin Heller

http열이 Null을 허용 하는 것과 관련이있을 수도 있습니다 . 시간이 있으면 내일 조사 할게요
— ypercubeᵀᴹ

http 열이 nullable과 관련이있을 수도 있습니다. 시간이 있으면 내일 조사 할게요 동일한 테이블을 생성하고 (로 제외 http NOT NULL) 모든 데이터를 복사하여 (물론 http NULL을 갖는 행 제외) 테스트 할 수 있습니다 .
— ypercubeᵀᴹ

NOT NULL로 변경하면 (테이블을 만들 때별로 신경 쓰지 않았지만) 쿼리 (내 쿼리)의 성능이 약 ~ 1 초-1.6 초로 향상되었습니다. 지금까지 노력해 주셔서 감사합니다.
— Robin Heller

답변:


10

세 가지 제안이 있습니다

제안 # 1 : 쿼리 다시 작성

다음과 같이 쿼리를 다시 작성해야합니다.

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

또는

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는 등호의 양쪽에 기능이 없어야합니다. 등호 왼쪽에 날짜가 있으면 Query Optimizer가 색인을보다 쉽게 ​​사용할 수 있습니다.

제안 # 2 :지지 지표

나는 또한 다른 색인을 제안 할 것입니다

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

date항목이 모두 색인에서 연속적이므로이 순서의 열을 제안합니다 . 그런 다음 쿼리는의 http간격을 건너 뛰지 않고 단순히 값을 수집 합니다 http.

제안 # 3 : 더 큰 키 버퍼 (선택 사항)

MyISAM은 인덱스 캐싱 만 사용합니다. 쿼리가 .MYD파일을 건드리지 않아야하므로 약간 더 큰 MyISAM 키 버퍼를 사용해야합니다.

256M으로 설정하려면

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

그런 다음 my.cnf

[mysqld]
key_buffer_size = 256M

MySQL을 다시 시작할 필요가 없습니다

시도 해봐 !!!


나는 당신이 나에게 한 질문을 시도했다. # 1은 다른 제안이나 내 자신만큼이나 성능이 좋았으며, 두 번째는 실제로 더 나빴습니다. 지지 지수와 같은 것-성능을 약 75 % 떨어 뜨립니다. 이제 더 큰 키 버퍼를 사용해 보겠습니다. 어쨌든 감사합니다!
— Robin Heller

더 큰 키 버퍼로 문제를 해결하지는 않았지만 귀하의 답변을 수락했지만 더 나은 성능을 보였습니다. 주어진 모든 것의 가장 좋은 해결책이므로 이것을 닫습니다. 감사합니다!
— Robin Heller

제안 # 2가 작동하려면 쿼리에 "USE INDEX"또는 "FORCE INDEX"를 추가해야 할 수 있습니다. 최소한 인덱스를 생성 한 후 쿼리 속도를 높이기 위해해야 ​​할 일입니다.
— Johano Fierra

-2

날짜 열 유형을 정수로 변경하십시오. 날짜를 정수로 Unix 날짜로 저장하십시오. 타임 스탬프 int보다 훨씬 큽니다. 당신은 그것에서 약간의 강타를 얻을 것입니다.


2
농담 해? 모두 INT와는 TIMESTAMP4 바이트가 필요합니다.
— ypercubeᵀᴹ

2
날짜 또는 타임 스탬프를 정수로 저장하면 모든 날짜 / 시간 함수가 손실된다는 것을 언급하지 마십시오.
— ypercubeᵀᴹ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.