인덱스 날짜 시간 열을 사용하는 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.