web-dev-qa-db-ja.com

MySQL InnoDBデータベースが選択で「ハング」する

サーバーの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
============================

編集:

これを明らかにしてくれてありがとう。

だから私は今私の質問を2つのケースに分割する必要があります。

  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 App

私の設定パラメータ:

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)
10
kaczor1984

解決しました!

主な問題はquery_cacheでした。 http://bugs.mysql.com/bug.php?id=21074

それを無効にした後、「フリーズ」は消えました。

3
kaczor1984

プロセスリストと「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 [〜#〜] を使用しています。

プロセスID 1、2、4、5、6、13内には、トランザクションの分離を保護するMVCCデータを持つ行があります。プロセスID 40には、データの行を行進するクエリがあります。フィールドhotspot_idにインデックスがある場合、そのキー+クラスタ化インデックスからの実際の行へのキーは、内部ロックを実行する必要があります。 (注:設計上、InnoDBのすべての非一意のインデックスは、キー(インデックスを作成するために意図した列)+クラスタ化インデックスキーの両方を保持します)。このユニークなシナリオは、本質的に、止められない力が動かせないオブジェクトに出会うことです。

本質的に、COMMITは、large_tableに対して変更を安全に適用できるようになるまで待機する必要があります。あなたの状況は独特ではなく、一回限りではなく、まれな現象ではありません。

実際、DBA StackExchangeでこのような3つの質問に答えました。質問は、同じ問題に関連する 同じ人 によって提出されました。私の回答は解決策ではありませんでしたが、質問の提出者が自分の状況に対処する方法について自分で結論を出すのに役立ちました。

これらの回答に加えて、 SELECTに関するInnoDBのデッドロックに関する別の人の質問に回答しました

この問題に関する私の過去の投稿が、あなたに何が起こっていたかを明確にしてくれることを願っています。

UPDATE 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;

2つの観察:

  • 「SELECT *」を実行していますが、すべての列をフェッチする必要がありますか?特定の列だけが必要な場合は、1000行の一時テーブルが実際に必要なサイズよりも大きくなる可能性があるため、ラベルを付ける必要があります。

  • WHERE句とORDER BY句は、通常、パフォーマンスの問題を解消するか、テーブルデザインを輝かせます。データを収集する前に、キーの収集を高速化するメカニズムを作成する必要があります。

これら2つの観察に照らして、次の2つの大きな変更を行う必要があります。

MAJOR CHANGE#1:クエリをリファクタリングします

クエリを再設計して、

  1. キーはインデックスから収集されます
  2. 1000またはそれらが収集されます
  3. メインテーブルに戻って参加しました

これらはこれら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個のキーを収集します。次に、サブクエリの結果がlarge_tableにINNER JOINされます。これまでのところ、行全体ではなくキーが取得されます。それでも、まだ799,000行を読み取ることができます。これらのキーを取得するより良い方法があります。

主な変更#2:リファクタリングされたクエリをサポートするインデックスを作成します

リファクタリングされたクエリは1つのサブクエリのみを特徴とするため、1つのインデックスを作成するだけで済みます。ここにそのインデックスがあります:

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

なぜこの特定のインデックスなのか? WHERE句を見てください。 hotspot_idは静的な値です。これにより、すべてのhotspot_idがインデックス内の順次リストを形成します。次に、ORDER BY句を見てください。 detected_at列は、おそらくDATETIMEまたはTIMESTAMPフィールドです。

これがインデックスで提示する自然な順序は次のとおりです。

  • インデックスはhostpot_idsのリストを特徴としています
  • 各hotspot_idには、discovered_atフィールドの順序付きリストがあります

このインデックスを作成すると、一時テーブルの内部ソートを行う必要もなくなります。

これらの2つの大きな変更を配置してください。実行時間が異なります。

試してみる !!!

UPDATE 2011-08-25 08:15 EDT

私はあなたのインデックスを見ました。私が提案したインデックスを作成する必要があります。

15
RolandoMySQLDBA