web-dev-qa-db-ja.com

「更新」状態のときにクエリが頻繁に遅くなる

頻繁に更新する2つのテーブルがあります。1つは直接UPDATE ..で、もう1つはINSERT .. ON DUPLICATE KEY UPDATE ...です。通常、これらのクエリは瞬時ですが、0.1秒から1秒以上かかり、その後数秒間再び瞬時になる場合があります。秒。

もう1つの注意点として、2つのMySQLサーバー(同じプライベートネットワーク内)があります。すべての選択クエリ(1つまたは2つを除く)はスレーブで実行され、ここに表示される挿入はもちろんマスターで実行されます。速度の低下は、データベースに大きな負荷がかかっているときに最も顕著になります。最後に、xtradbを使用しています(効果があるかどうかを確認するため)が、MySQL 5.5 InnoDBだけで同じ動作が発生しました。

-- CustomData
+-----------+---------+------+-----+---------+-------+
| Field     | Type    | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+-------+
| Server    | int(11) | NO   | PRI | NULL    |       |
| Plugin    | int(11) | NO   | PRI | NULL    |       |
| ColumnID  | int(11) | NO   | PRI | NULL    |       |
| DataPoint | int(11) | NO   |     | NULL    |       |
| Updated   | int(11) | NO   | MUL | NULL    |       |
+-----------+---------+------+-----+---------+-------+

例いくつかのクエリの:

mysql> insert into CustomData (Server, Plugin, ColumnID, DataPoint, Updated) VALUES ( 52707, 1, 1, 0, 1327093596) on duplicate key update DataPoint = 0 , Updated = 1327093596 ;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into CustomData (Server, Plugin, ColumnID, DataPoint, Updated) VALUES ( 52707, 1, 1, 0, 1327093596) on duplicate key update DataPoint = 0 , Updated = 1327093596 ;
Query OK, 0 rows affected (0.12 sec)

mysql> insert into CustomData (Server, Plugin, ColumnID, DataPoint, Updated) VALUES ( 52707, 1, 1, 0, 1327093596) on duplicate key update DataPoint = 0 , Updated = 1327093596 ;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into CustomData (Server, Plugin, ColumnID, DataPoint, Updated) VALUES ( 52707, 1, 1, 0, 1327093596) on duplicate key update DataPoint = 0 , Updated = 1327093596 ;
Query OK, 0 rows affected (0.00 sec)

説明する

mysql> explain select * from CustomData where Server = 52707 and Plugin = 1 and ColumnID = 1 ;
+----+-------------+------------+-------+---------------+---------+---------+-------------------+------+-------+
| id | select_type | table      | type  | possible_keys | key     | key_len | ref               | rows | Extra |
+----+-------------+------------+-------+---------------+---------+---------+-------------------+------+-------+
|  1 | SIMPLE      | CustomData | const | PRIMARY,Cron  | PRIMARY | 12      | const,const,const |    1 |       |
+----+-------------+------------+-------+---------------+---------+---------+-------------------+------+-------+

プロファイラー(0.12秒クエリ用)

mysql> show profile for query 56 ;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000062 |
| checking permissions | 0.000005 |
| Opening tables       | 0.000016 |
| System lock          | 0.000007 |
| init                 | 0.000011 |
| update               | 0.129531 |
| end                  | 0.000005 |
| query end            | 0.000012 |
| closing tables       | 0.000008 |
| freeing items        | 0.000017 |
| logging slow query   | 0.000001 |
| cleaning up          | 0.000036 |
+----------------------+----------+

他のすべての問題のあるクエリは非常に似ています。 show processlist;に長時間実行されているクエリはありません。

エンジンのINNODBステータスを表示(リンクを2つ以上投稿するには10担当者が必要なので)-Pastebin .com/raw.php?i = tdtZeTCJ

最後に注意したいのは、この例では、ワーカーは同じ行ではなく、一意の行に対してのみINSERT .. ON DUPLICATE KEYを実行するということです(したがって、各クエリは異なる行に対するものです)。

前もって感謝します!

編集:

私のデータはすべて、インデックス付きで約3Gです。バッファプールのサイズは最初は2Gでしたが、4Gも試しました。

my.cnf-

[mysqld]
datadir = /data/mysql
socket = /var/run/mysqld/mysqld.sock
user = mysql
bind-address = 10.10.1.7

log-slow-queries = mysql-slow.log
long_query_time = 5
log-queries-not-using-indexes

# Replication
server-id        = 1

# master
log-bin          = /var/log/mysql/mysql-bin.log
expire-logs-days = 10
binlog-do-db     = metrics
max_binlog_size  = 104857600
binlog_format    = MIXED

# slave
# replicate-do-db  = metrics
# read_only        = 1

# /Replication

skip-external-locking
sysdate-is-now

performance_schema

log-error=/var/log/mysql.log

default-storage-engine          = InnoDB

innodb_file_per_table           = 1
innodb_file_format              = barracuda

innodb_buffer_pool_size          = 4G
innodb_additional_mem_pool_size  = 10M
innodb_log_buffer_size           = 8M
innodb_flush_log_at_trx_commit   = 0
innodb_lock_wait_timeout         = 50
innodb_fast_shutdown             = 1
innodb_flush_method              = O_DIRECT
transaction_isolation            = READ-COMMITTED

max_connections                 = 4092
connect_timeout                 = 86400
wait_timeout                    = 86400
interactive_timeout             = 86400
max_allowed_packet              = 64M

open_files_limit                = 2048
table_cache                     = 2048
net_buffer_length               = 8K
query_cache_type                = 1
query_cache_size                = 16M
thread_cache                    = 100
thread_stack                    = 512K
tmpdir                          = /dev/shm
tmp_table_size                  = 64M

key_buffer_size                 = 64M
sort_buffer_size                = 512K
net_buffer_length               = 8K
read_buffer_size                = 256K
read_rnd_buffer_size            = 512K
myisam_sort_buffer_size         = 8M

[mysqldump]
quick
max_allowed_packet              = 16M
[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size                 = 20M
sort_buffer_size                = 20M
read_buffer                     = 2M
write_buffer                    = 2M

[mysqlhotcopy]
interactive-timeout

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

EDIT2

innotop-

12

ギャップロックについて読んだ-PKが3列であるという事実と、READ-COMMITTEDを使用しているという事実を無視して、Plugin列とColumnID列をギャップロックしている可能性はあるかとにかくそれはいけませんか? innotopに見られるように、これらのいくつかは非常に近いため、これが当てはまる場合、多くのロックが発生します。

mysql> show indexes from CustomData;
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table      | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| CustomData |          0 | PRIMARY  |            1 | Server      | A         |     1073724 |     NULL | NULL   |      | BTREE      |         |               |
| CustomData |          0 | PRIMARY  |            2 | Plugin      | A         |     1879017 |     NULL | NULL   |      | BTREE      |         |               |
| CustomData |          0 | PRIMARY  |            3 | ColumnID    | A         |     7516069 |     NULL | NULL   |      | BTREE      |         |               |
| CustomData |          1 | Cron     |            1 | Plugin      | A         |          20 |     NULL | NULL   |      | BTREE      |         |               |
| CustomData |          1 | Cron     |            2 | ColumnID    | A         |          20 |     NULL | NULL   |      | BTREE      |         |               |
| CustomData |          1 | Cron     |            3 | Updated     | A         |     7516069 |     NULL | NULL   |      | BTREE      |         |               |
| CustomData |          1 | Updated  |            1 | Updated     | A         |     2505356 |     NULL | NULL   |      | BTREE      |         |               |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

Cronキーは30分ごとにのみ使用され、現在は有効化されていません(起動された場合)。

7
virulent

InnoDB設定でいくつかの調整を行う必要があります

調整#1:より大きなInnoDB REDOログ

私はinnodb_log_file_sizeが表示されないため、デフォルトの5Mであると想定しています。 innodb_buffer_pool_size =は4Gであるため、1G REDOログが必要です。

調整#2:InnoDBがすべてのCPUを使用するようにする

そのままでは、InnoDBはすべてのCPUを使用するわけではありません。 InnoDB LEFT UNCONFIGUREDが古いバージョンでより速く機能する方法について、私はずっと前に投稿しました。 InnoDBのマルチコアエンゲージメントについても投稿しました。

これらのことを言った上で、以下の調整を行います

cp /etc/my.cnf /etc/my.cnf_old

この設定を/etc/my.cnfに追加します

[mysqld]
innodb_log_file_size = 1G
innodb_io_capacity = 20000
innodb_read_io_threads = 5000
innodb_write_io_threads = 5000

次に、これらの手順を実行します

service mysql stop
mv /var/log/mysql/ib_logfile0 /var/log/mysql/ib_logfile0_old 
mv /var/log/mysql/ib_logfile1 /var/log/mysql/ib_logfile1_old
service mysql start

現在、すべてのコアがInnoDBを支援し、トランザクションを分離する余地がはるかにあります

試してみる !!!

4
RolandoMySQLDBA

RAMはどれくらいですか? innodb_buffer_pool_sizeはavailable RAMの約70%でなければなりません。

SELECTをどのくらいの頻度で行っていますか? INSERT?

INSERTはスレーブでも実行されることに注意してください。 SBRを使用していますか?またはRBR?

SHOW CREATE TABLEを使用してください。 DESCRIBEはあまり説明的ではありません!

変更する可能性のあるフィールドにインデックスがあるようです。これはおそらく問題の一部です。一部のインデックスなしで実行できますか?

特に、cronキーに時間がかかるようにしてください-(pluginID、columnID)のみを実行します

Updatedが変更された場合、インデックスの「行」をある場所から削除し、別の場所に再挿入する必要があります。

1
Rick James

私のデータベースにも同じ問題がありました。常に更新され、INSERT ... ON DUPLICATE KEYを使用するテーブルがありました。更新には時間がかかり、mysqlがクラッシュするまで接続がキューに蓄積されていました。私はinnotop、instatをテストし、スナップショットからテーブルを再インストールして復元しましたが、何も機能しませんでした。

最後に、問題をすべての接続を占有していたテーブルに追跡しました。主キーは、署名された32ビットの数値であるint(11)として設定されました。 AUTO_INCREMENTが最大値の2147483647に達しました。これは、次のようにSHOW CREATE TABLEを使用して確認できます。

CREATE TABLE `remote_ip_backoff` (
  `remote_ip_backoff_id` int(11) NOT NULL AUTO_INCREMENT,
  `created_time` datetime NOT NULL,
  `modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `deleted_time` datetime NOT NULL,
  `is_deleted` tinyint(1) NOT NULL,
  `remote_ip_id` int(11) NOT NULL DEFAULT '0',
  `backoff_rule_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`remote_ip_backoff_id`),
  UNIQUE KEY `remote_ip_id` (`remote_ip_id`,`backoff_rule_id`),
) ENGINE=InnoDB AUTO_INCREMENT=2147483647 DEFAULT CHARSET=utf8

したがって、インデックスを更新する挿入は正常に機能しましたが、新しい行を追加しようとする挿入は失敗しました(実際には、同じ自動インクリメントIDで追加されました)。

この問題を解決するには、テーブルを切り捨てるか(実質的にauto_incrementカウンターをリセット)、主キーを増やしてBIGINTを使用します。

ALTER TABLE `remote_ip_backoff` MODIFY `remote_ip_backoff_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;

SIGNED BIGINTの最大サイズは9223372036854775807で、UNSIGNED BIGINTの最大サイズは18446744073709551615(またはSIGNED INTの80億倍)です。

解決策:テーブルの自動インクリメントカウンターを確認します。 INTを使用している場合、最大カウンターサイズに達している可能性があります。

0
hobby