MySQL InnoDB 데이터베이스는 선택에 달려있다


10

서버에서 MySQL 구성을 수정하려고합니다. 우리 앱의 특징은 많은 데이터가 단일 테이블 (현재 3 억 행 이상)에 저장되어 있다는 것입니다. 이 테이블은 종종 인서트에 사용됩니다 (항상 제공됩니다).

몇 초 이상 걸리는 테이블에서 선택 쿼리를 실행하면 모든 삽입 (정확하게 커밋)이 테이블 액세스를 기다리고 있으며 앱이 응답하지 않습니다.

내가 아는 한 InnoDB는 select가 실행될 때 테이블을 잠그지 않습니다. 그러면 왜 차단 차단 테이블이 사용됩니까?

나는 innotop으로 이유를 찾으려고 노력했지만 결과를 해석하는 방법과 검색 위치를 잘 모르겠습니다. 필요한 정보를 알려 주시면 여기에 게시하겠습니다.

+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+
| Id  | User    | Host      | db     | Command | Time | State          | Info                                                                                                                              |
+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+
|   1 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   2 | root    | localhost | dbname | Query   |   30 | NULL           | COMMIT                                                                                                                            | 
|   4 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   5 | root    | localhost | dbname | Query   |   29 | NULL           | COMMIT                                                                                                                            | 
|   6 | root    | localhost | dbname | Query   |   25 | NULL           | COMMIT                                                                                                                            | 
|   7 | root    | localhost | dbname | Query   |    0 | NULL           | show full processlist                                                                                                             | 
|  13 | user    | localhost | dbname | Query   |   25 | NULL           | COMMIT                                                                                                                            | 
|  38 | user    | localhost | dbname | Sleep   |    0 |                | NULL                                                                                                                              | 
|  39 | user    | localhost | dbname | Sleep   | 9017 |                | NULL                                                                                                                              | 
|  40 | user    | localhost | dbname | Query   |   33 | Sorting result | SELECT * FROM `large_table` WHERE (`large_table`.`hotspot_id` = 3000064)  ORDER BY discovered_at LIMIT 799000, 1000 | 
|  60 | user    | localhost | dbname | Sleep   | 1033 |                | NULL                                                                                                                              | 
|  83 | root    | localhost | dbname | Sleep   | 3728 |                | NULL                                                                                                                              | 
| 112 | root    | localhost | NULL   | Sleep   |    6 |                | NULL                                                                                                                              | 
+-----+---------+-----------+--------+---------+------+----------------+-----------------------------------------------------------------------------------------------------------------------------------+


=====================================
110824 12:24:24 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 19 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 1521117, signal count 1471216
Mutex spin waits 0, rounds 20647617, OS waits 239914
RW-shared spins 2119697, OS waits 1037149; RW-excl spins 505734, OS waits 218177
------------
TRANSACTIONS
------------
Trx id counter 0 412917332
Purge done for trx's n:o < 0 412917135 undo n:o < 0 0
History list length 48
Total number of lock structs in row lock hash table 5
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 28363, OS thread id 1092766032
MySQL thread id 83, query id 3249941 localhost root
---TRANSACTION 0 412901582, not started, process no 28363, OS thread id 1144449360
MySQL thread id 60, query id 3677008 localhost user
---TRANSACTION 0 412917189, not started, process no 28363, OS thread id 1144314192
MySQL thread id 43, query id 3905773 localhost root
---TRANSACTION 0 412534255, not started, process no 28363, OS thread id 1092630864
MySQL thread id 39, query id 14279 localhost user
---TRANSACTION 0 412917331, not started, process no 28363, OS thread id 1144179024
MySQL thread id 38, query id 3908045 localhost user
---TRANSACTION 0 412917201, not started, process no 28363, OS thread id 1092495696
MySQL thread id 13, query id 3908257 localhost user
---TRANSACTION 0 412538821, not started, process no 28363, OS thread id 1092360528
MySQL thread id 7, query id 3908258 localhost root
show engine innodb status
---TRANSACTION 0 412917330, ACTIVE 6 sec, process no 28363, OS thread id 1144043856
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 2, query id 3907373 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917331, sees < 0 412917131
---TRANSACTION 0 412917328, ACTIVE 6 sec, process no 28363, OS thread id 1092225360
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 6, query id 3907345 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917329, sees < 0 412917131
---TRANSACTION 0 412917326, ACTIVE 6 sec, process no 28363, OS thread id 1091955024
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 4, query id 3907335 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917327, sees < 0 412917131
---TRANSACTION 0 412917324, ACTIVE 6 sec, process no 28363, OS thread id 1092090192
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 5, query id 3907328 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917325, sees < 0 412917131
---TRANSACTION 0 412917321, ACTIVE (PREPARED) 7 sec, process no 28363, OS thread id 1143908688 preparing
2 lock struct(s), heap size 368, undo log entries 1
MySQL thread id 1, query id 3907125 localhost root
COMMIT
Trx read view will not see trx with id >= 0 412917322, sees < 0 412917131
---TRANSACTION 0 412917131, ACTIVE 20 sec, process no 28363, OS thread id 1074075984, thread declared inside InnoDB 111
mysql tables in use 1, locked 0
MySQL thread id 40, query id 3904958 localhost user Sorting result
SELECT * FROM `large_table` WHERE (`large_table`.`hotspot_id` = 3000064)  ORDER BY discovered_at LIMIT 848000, 1000
Trx read view will not see trx with id >= 0 412917132, sees < 0 412917132
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 1; buffer pool: 0
3510225 OS file reads, 284998 OS file writes, 202897 OS fsyncs
1.05 reads/s, 21299 avg bytes/read, 8.10 writes/s, 7.58 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 275, free list len 13392, seg size 13668,
489950 inserts, 491830 merged recs, 10986 merges
Hash table size 8850487, used cells 8127172, node heap has 32697 buffer(s)
71914.53 hash searches/s, 8701.91 non-hash searches/s
---
LOG
---
Log sequence number 157 3331524445
Log flushed up to   157 3331521939
Last checkpoint at  157 3326072846
1 pending log writes, 0 pending chkp writes
199025 log i/o's done, 7.53 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4788954432; in additional pool allocated 1048576
Buffer pool size   262144
Free buffers       0
Database pages     229447
Modified db pages  1439
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 7453325, created 14887, written 118658
1.37 reads/s, 0.11 creates/s, 0.53 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
7 read views open inside InnoDB
Main thread process no. 28363, id 1091684688, state: flushing log
Number of rows inserted 1093064, updated 249134, deleted 1405, read 1115880534
7.89 inserts/s, 2.47 updates/s, 0.05 deletes/s, 80953.21 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

편집하다:

이것을 명확히 해 주셔서 감사합니다.

이제 질문을 두 가지 경우로 나눠야합니다.

  1. 이 단일 테이블을 잠그면 전체 앱이 '중지'되는 것이 정상입니까? 다른 테이블에 대한 쿼리에 대해 DB가 응답하지 않아야합니까? 버퍼가 너무 낮게 설정되어 있습니까?

  2. 이 테이블을 MyISAM으로 전환하면 도움이됩니까? 이 테이블에서 거래가 전혀 필요하지 않습니다. 그런 상황에서 다른 잠금 장치가 없습니까 (긴 선택 + 많은 빠른 삽입물)?

EDIT2 :

삽입 쿼리는 다음과 같습니다.

INSERT INTO `large_table` (`device_address`, `hotspot_id`, `minute`, `created_at`, `updated_at`, `discovered_with_hci`, `hour`, `rssi`, `day`, `device_class`, `discovered_at`) VALUES('10:40:03:90:10:40', 3000008, 1, '2011-08-22 05:01:08', '2011-08-22 05:01:08', -1, 5, -79, '2011-08-22 05:01:01', '0', '2011-08-22 05:01:01')

이것이 인덱스가 정의 된 것입니다.

+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table       | Non_unique | Key_name                                     | Seq_in_index | Column_name         | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| large_table |          0 | PRIMARY                                      |            1 | id                  | A         |    92396334 |     NULL | NULL   |      | BTREE      |         | 
| large_table |          1 | index_large_table_on_discovered_with_hci     |            1 | discovered_with_hci | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_hotspot_id              |            1 | hotspot_id          | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            1 | day                 | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            2 | hour                | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_day_and_hour_and_minute |            3 | minute              | A         |      537187 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_created_at              |            1 | created_at          | A         |     8399666 |     NULL | NULL   | YES  | BTREE      |         | 
| large_table |          1 | index_large_table_on_rssi                    |            1 | rssi                | A         |          18 |     NULL | NULL   | YES  | BTREE      |         | 
+-------------+------------+----------------------------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+

편집 3 :

이러한 쿼리 중에 전체 응용 프로그램이 응답하지 않는 이유는 무엇입니까? 'large_table'에만 영향을 미쳐서는 안됩니까?

어쩌면 mysql 설정에 문제가 있습니까? 서버는 16GB RAM이 장착 된 4 코어 Xeon 2GHz입니다. MySQL + Rails 앱을 실행합니다

내 구성 매개 변수 :

skip-external-locking
key_buffer              = 64M
max_allowed_packet      = 16M
thread_stack            = 128K
thread_cache_size       = 8
query_cache_size        = 32M
tmp_table_size          = 64M
max_heap_table_size     = 64M
table_cache             = 256
read_rnd_buffer_size    = 512K
sort_buffer_size        = 2M

myisam-recover          = BACKUP
max_connections         = 200

query_cache_limit       = 1M

long_query_time = 200

max_binlog_size         = 100M

innodb_buffer_pool_size = 4G
safe-updates
max_join_size=100000000

Mysqltuner 스크립트는 다음을 제안합니다.

long_query_time (<= 10)
innodb_buffer_pool_size (>= 62G)

의 출력을 추가하십시오 show engine innodb status;.
quanta

innotop에서는 L을 쳐서 자물쇠를 볼 수 있습니다. 앱은 어떻게 연결을 설정합니까? JDBC? 어떤 defaultTransactionIsolation 레벨을 사용하고 있습니까?
HTTP500

RoR 응용 프로그램이므로 MySQL의 기본값이라고 생각합니다 (SQL 쿼리로 어떻게 확인할 수 있습니까?). 이 선택이 실행되는 동안 innotop에 잠금이 표시되지 않습니다.
kaczor1984

@ kaczor1984 다음을 수행하여 기본 격리 수준을 확인할 수 있습니다. 'tx_isolation'과 같은 show 변수; 질문. 기본값은 REPEATABLE READ입니다. MVCC는 REPEATABLE READ 및 READ COMMITTED에서만 작동합니다. 문제의 해결책이 무엇인지 확실하지 않지만 RolandoMySQLDBA의 답변은 유익했습니다.
HTTP500

Process ID 40
RolandoMySQLDBA

답변:


15

프로세스 목록과 'show engine innodb status'를주의 깊게 살펴보십시오. 당신은 무엇을보고 있습니까 ???

프로세스 ID 1,2,4,5,6,13은 모두 COMMIT를 실행하려고합니다.

누가 모든 것을 들고 있습니까 ??? 프로세스 ID 40이 large_table에 대해 쿼리를 실행 중입니다.

프로세스 ID 40이 33 초 동안 실행되었습니다. 프로세스 ID 1,2,4,5,6,13이 33 초 미만으로 실행되었습니다. 프로세스 ID 40이 무언가를 처리하고 있습니다. 보류는 무엇입니까 ???

우선, 쿼리는 MVCC 를 통해 large_table의 클러스터형 인덱스 를 두드리고 있습니다.

프로세스 ID 1,2,4,5,6,13에는 트랜잭션 격리를 보호하는 MVCC 데이터가있는 행이 있습니다. 프로세스 ID 40에는 데이터 행을 통해 행진하는 쿼리가 있습니다. hotspot_id 필드에 인덱스가있는 경우 해당 키 + 클러스터 된 인덱스의 실제 행에 대한 키는 내부 잠금을 수행해야합니다. (참고 : InnoDB의 고유하지 않은 모든 인덱스는 의도적으로 키 (인덱스하려는 열)와 클러스터 된 인덱스 키를 모두 가지고 있습니다). 이 독특한 시나리오는 본질적으로 멈출 수없는 힘이 움직일 수없는 물체를 만나는 것입니다.

본질적으로, COMMIT는 large_table에 대해 변경 사항을 적용하기에 안전 할 때까지 기다려야합니다. 귀하의 상황은 독특하지 않으며 일회성 또는 드문 현상이 아닙니다.

실제로 DBA StackExchange에서 이와 같은 세 가지 질문에 대답했습니다. 동일한 문제와 관련된 동일한 사람 이 질문을 제출했습니다 . 내 대답은 해결책이 아니었지만 질문 제출자가 자신의 상황을 처리하는 방법에 대한 자신의 결론을 내리는 데 도움이되었습니다.

이 답변 외에도 SELECTs와 관련하여 InnoDB의 교착 상태에 대한 다른 사람의 질문에 대답했습니다 .

이 주제에 대한 나의 과거 게시물이 당신에게 무슨 일이 일어나고 있는지 명확히하기를 바랍니다.

업데이트 2011-08-25 08:10 EDT

프로세스 ID 40의 쿼리는 다음과 같습니다.

SELECT * FROM `large_table`
WHERE (`large_table`.`hotspot_id` = 3000064)
ORDER BY discovered_at LIMIT 799000, 1000;

두 가지 관찰 :

  • 'SELECT *'를하고 있습니다. 모든 열을 가져와야합니까? 특정 열만 필요한 경우 1000 행의 임시 테이블이 실제로 필요한 것보다 클 수 있으므로 레이블을 지정해야합니다.

  • WHERE 및 ORDER BY 절은 일반적으로 성능 문제를 없애거나 테이블 디자인을 빛나게합니다. 데이터를 수집하기 전에 키 수집 속도를 높이는 메커니즘을 만들어야합니다.

이 두 가지 관찰에 비추어, 두 가지 주요 변경 사항이 있습니다.

주요 변경 # 1 : 쿼리 리팩토링

쿼리를 다시 디자인하여

  1. 키는 색인에서 수집됩니다
  2. 1000 개만 수집
  3. 메인 테이블에 다시 합류

다음은이 세 가지를 수행하는 새로운 쿼리입니다.

SELECT large_table.* FROM
large_table INNER JOIN
(
    SELECT hotspot_id,discovered_at
    FROM large_table
    WHERE hotspot_id = 3000064
    ORDER BY discovered_at
    LIMIT 799000,1000
) large_table_keys
USING (hotspot_id,discovered_at);

하위 쿼리 large_table_keys는 필요한 1000 개의 키를 수집합니다. 하위 쿼리의 결과는 INNER JOINed to large_table입니다. 지금까지 전체 행 대신 키가 검색됩니다. 여전히 799,000 행을 읽습니다. 그 열쇠를 얻는 더 좋은 방법이 있습니다.

주요 변경 # 2 : 리팩토링 된 쿼리를 지원하는 인덱스 생성

리팩토링 된 쿼리에는 하나의 하위 쿼리 만 있기 때문에 하나의 인덱스 만 만들면됩니다. 그 색인은 다음과 같습니다.

ALTER TABLE large_table ADD INDEX hotspot_discovered_ndx (hotspot_id,discovered_at);

왜이 특정 색인입니까? WHERE 절을보십시오. hotspot_id는 정적 값입니다. 이렇게하면 모든 hotspot_id가 색인에서 순차적 목록을 형성합니다. 이제 ORDER BY 절을보십시오. discover_at 컬럼은 아마도 DATETIME 또는 TIMESTAMP 필드 일 것입니다.

이것이 색인에 나타나는 자연 순서는 다음과 같습니다.

  • 인덱스는 hostpot_ids 목록을 제공합니다
  • 각 hotspot_id에는 정렬 된 found_at 필드 목록이 있습니다.

이 색인을 작성하면 임시 테이블의 내부 정렬을 수행하지 않아도됩니다.

이 두 가지 주요 변경 사항을 적용하면 실행 시간에 차이가 있습니다.

시도 해봐 !!!

업데이트 2011-08-25 08:15 EDT

나는 당신의 색인을 보았습니다. 여전히 제안한 색인을 작성해야합니다.


작동 방식에 대한 큰 설명을 주셔서 감사합니다. 그런 상황을 피하는 방법을 알 수 없습니다. 삽입물은 색인을 수정해야하며 select는 hotspot_id 및 discover_at에서 색인을 사용해야합니다. MyISAM으로 전환하는 나의 '아이디어'에 답할 수 있다면 기쁠 것입니다.
kaczor1984

실제로 MyISAM을 사용하면 MyISAM의 각 INSERT, UPDATE 및 DELETE가 전체 테이블 잠금을 트리거하기 때문에 상황이 악화 될 수 있습니다. LOW_PRIORITY INSERT 또는 INSERT DELAYED를 사용하더라도 전체 테이블 잠금이 계속 발생합니다. 스토리지 엔진에 관계없이 이러한 장애물을 중심으로 쿼리를 조정할 수 있으므로 쿼리 자체를 탐색해야합니다. 최소한 새로운 알고리즘이 필요할 수도 있습니다. 몇 분 안에 쿼리를 살펴 보겠습니다.
RolandoMySQLDBA

첫 번째 게시물을 업데이트하여이 테이블에서 쿼리 및 인덱스 삽입을 볼 수 있습니다.
kaczor1984

Process ID 40
RolandoMySQLDBA

4
당신은 당신의 긴 mysql 답변에 대한 남성 영웅입니다
Mike

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.