2013-08-25 2 views
1
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+ 
| Field      | Type                   | Null | Key | Default | Extra   | 
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+ 
| type      | enum('Website','Facebook','Twitter','Linkedin','Youtube','SeatGeek','Yahoo') | NO | MUL | NULL |    | 
| name      | varchar(100)                 | YES | MUL | NULL |    | 
| processing_interface_id | bigint(20)                 | YES | MUL | NULL |    | 
| processing_interface_table | varchar(100)                 | YES | MUL | NULL |    | 
| create_time    | datetime                  | YES | MUL | NULL |    | 
| run_time     | datetime                  | YES | MUL | NULL |    | 
| completed_time    | datetime                  | YES | MUL | NULL |    | 
| reserved     | int(10)                  | YES | MUL | NULL |    | 
| params      | text                   | YES |  | NULL |    | 
| params_md5     | varchar(100)                 | YES | MUL | NULL |    | 
| priority     | int(10)                  | YES | MUL | NULL |    | 
| id       | bigint(20) unsigned               | NO | PRI | NULL | auto_increment | 
| status      | varchar(40)                 | NO | MUL | none |    | 
+----------------------------+------------------------------------------------------------------------------+------+-----+---------+----------------+ 

select * from remote_request use index (processing_order) where remote_request.status = 'none' and type = 'Facebook' and reserved = '0' order by priority desc limit 0, 40; 

이 테이블은 매우 많은 양의 쓰기 및 읽기를 수신합니다. 각각의 remote_request는 하나의 프로세스가되고, 요청의 유형과 요청에 따라 다른 remote_requests 0에서 5 사이의 아무 곳이나 생성 할 수 있습니다.MySQL 쿼리 최적화 다중 열 인덱스는 이러한 느린 문제를 해결합니까?

테이블은 현재 약 350 만 레코드에 앉아 있으며 사이트 자체에 부하가 많이 걸리고 동시에 50 개 이상의 인스턴스가 동시에 실행될 때 달팽이 속도로 이동합니다. (REST 요청은 확실하지 않은 경우를 대비해 테이블의 목적입니다.)

테이블이 커질수록 더 악화됩니다. 처리 된 요청을 매일 삭제할 수 있지만 궁극적으로는 문제가 해결되지 않습니다.

이 쿼리는 항상 매우 낮은 응답 비율을 유지해야합니다.

다음은 테이블의 현재 색인입니다.

+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table   | Non_unique | Key_name       | Seq_in_index | Column_name    | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| remote_request |   0 | PRIMARY       |   1 | id       | A   |  2403351 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | type_index      |   1 | type      | A   |   18 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | processing_interface_id_index |   1 | processing_interface_id | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | processing_interface_table_index |   1 | processing_interface_table | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | create_time_index    |   1 | create_time    | A   |  160223 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | run_time_index     |   1 | run_time     | A   |  343335 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | completed_time_index    |   1 | completed_time    | A   |  267039 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | reserved_index     |   1 | reserved     | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | params_md5_index     |   1 | params_md5     | A   |  2403351 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | priority_index     |   1 | priority     | A   |   716 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | status_index      |   1 | status      | A   |   18 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | name_index      |   1 | name      | A   |   18 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   1 | priority     | A   |   200 |  NULL | NULL | YES | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   2 | status      | A   |   200 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   3 | type      | A   |   200 |  NULL | NULL |  | BTREE  |   |    | 
| remote_request |   1 | processing_order     |   4 | reserved     | A   |   200 |  NULL | NULL | YES | BTREE  |   |    | 
+----------------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

어떤 생각을 어떻게 해결하나요? 우선 순위에 따라 자동으로 정렬하는 일종의 복잡한 색인을 만들 수 없으며 'Facebook'유형과 일치하는 처음 40 개를 취할 수 있습니까? 현재는 테이블의 500k 행 이상을 스캔하여 결과가 비효율적으로 반환됩니다.

내가 땜질 된 쿼리의 몇 가지 다른 버전은 다음과 같습니다

select * from remote_request use index (type_index,status_index,reserved_index,priority_index) where remote_request.status = 'none' and type = 'Facebook' and reserv       ed = '0' order by priority desc limit 0, 40 

우리가 얼마나 많은 종류의 요청이 입력에 따라 1000 행 아래에 스캔 행을 얻을 수 있다면 그것은 놀라운 것 표.

미리 감사드립니다. 이것은 가장 경험이 풍부한 MySQL 전문가를 제외하고는 진짜 호두 까기 인 것일 수 있습니다.

+0

데이터의 강도를 표시 할 수는 없지만 SQLfiddle 예제를 사용하면 문제를 더 쉽게 볼 수 있습니다. – skv

답변

1

4 열 색인의 열은 올바르지 만 순서는 잘못되었습니다.

인덱스를 사용하여 먼저 3 개의 열을 사용하여 일치하는 행을 검색합니다. 3 개의 동등 조건을 찾고 있으므로 인덱스가 일치하는 행 집합을 찾으면이 행의 순서는 기본적으로 처음 세 열과 관련됩니다. 그래서 넥타이를 해결하려면 네 번째 열에 정렬 할 열을 추가하십시오.

이렇게하면 ORDER BY은 아무 작업도 수행하지 않습니다. 쿼리가 색인에 저장된 순서대로 행을 읽을 수 있기 때문입니다. 처음 세 열의 순서에 너무 많은 의미가 아마이 아니다

CREATE INDEX processing_order2 ON remote_request 
(status, type, reserved, priority); 

AND과 함께 평등의 관점에서 모든있어 이후 :

그래서 나는 다음과 같은 인덱스를 만들 것입니다. 그러나 priority 열은 끝에 있습니다.

내 프레젠테이션 How to Design Indexes, Really을 읽고 싶을 수도 있습니다.

덧붙여 말하자면 올바른 인덱스를 가지고 있다면 USE INDEX()을 사용하지 않아도됩니다. MySQL의 옵티마이 저는 대부분 자동으로이 인덱스를 선택합니다. 그러나 USE INDEX()은 옵티마이 저가 작성한 새 인덱스를 고려하지 못하도록 차단할 수 있으므로 코드 유지 관리의 단점이됩니다.

+0

나는이 대답을 정말로 좋아한다. –

+0

이것은 600000 % 최적화와 같았습니다. 정말 고맙습니다. –

+0

도와 줘서 기쁩니다! 색인의 열이 중요한지 알 수 있습니다. 그리고 최고의 열을 예측하는 방법을 배우는 것이 그리 어렵지 않습니다. –

1

이것은 완전한 답변은 아니지만 코멘트 너무 깁니다 :

는 당신이 실제로 그 모든 인덱스에 찾고 있습니까? 일부를 제거하지 않으면. 추가 색인은 쓰기 속도를 늦 춥니 다.

둘째, 검색어에 EXPLAIN을 사용하고 색인을 지정하지 마십시오. MySQL이 옵션을 강요하는 것보다 처리하는 방법을 보라 (보통 옳은 일을한다).

마지막으로 정렬은 가장 큰 상처 일 수 있습니다. 정렬하지 않으면 아마 기록을 꽤 빨리 얻을 수 있습니다.

    1. 는 VIEW 생성 시도 (VIEWS와 같은 익숙하지가 있지만 작동하지 않을 수 있습니다)는 최고 40

      옵션을 반환 할 수 있습니다 전에 그것은 당신의 기준을 충족하는 모든 행을 검색하고 정렬 할 수있다 이 테이블을 더 작은 테이블로 분할하십시오. Sphinx 또는 Lucene과 같은 타사 도구를 사용하여 검색 할 특수 색인을 작성하십시오.

    2. (전에 스핑크스를 사용했습니다. http://sphinxsearch.com/에서 찾을 수 있습니다.)
    3. 또는 Map 기능을 사용하여 NoSQL 솔루션을 사용하십시오.

    편집 나는 VIEW를 사용하는 방법에 대한 약간을 읽고 난 당신이 그런 큰 테이블이 있기 때문에 귀하의 경우에 도움이 될 것입니다 생각하지 않습니다. 이 스레드의 답변보기 : Using MySQL views to increase performance

  • +0

    1) 많은 부분을 다시 계산해야하기 때문에 1)보기가 좋지 않습니다. 삽입하면 뷰를 강제로 재 계산합니까? 2) 작은 테이블은이 특별한 일을하지 않을 것입니다. 그러나 나는 타입에 따라 테이블을 분리 할 수 ​​있다고 생각합니다. 3) shinx는 과잉 보인다. 4) 아무 SQL도 아직 끝나지 않는 것 같습니다. 인덱스만큼, 다른 쿼리를 더 빨리 만들 수 있도록 85 %의 다른 쿼리를 사용하고 있으므로 제거하는 것은 실제로 옵션마다 아닙니다. 나는 응답을 좋아합니다. 그것의 명확한 사고. 나는 그것을 유형에 맞게 분해해야 할 수도 있습니다. –

    +0

    네 말이 맞아. 그 결과는 캐시 될 것이지만, 많은 글을 쓰면 당신을 해칠 수 있습니다. – Cfreak