UPDATEを高速にしたい
- 評価 0
- クリップ 0
- VIEW 66
前提・実現したいこと
UPDATE
が非常に遅いので速くしたいです。
accounts
テーブルに約1千万件のデータが入っています。
そのうち約180万件に対してUPDATE
をする必要があるのですが、約3時間たっても終わりません。CPU使用率も高い状態が続いています。(htopコマンドで確認しました)
該当のソースコード
最終ログイン日時が2017/10/01以前のアカウントのみflag
を1にします。
別のプログラムでflag
の値を元に処理する必要があるからです。
※flagの値は全て0になっています。
UPDATE accounts a
SET a.flag = 1
WHERE a.last_login_time < '2017/10/01';
テーブル情報
- accounts テーブル
全データ数約1千万件
key | column | data_type | length |
---|---|---|---|
Primary | user_id | int | 11 |
Key | uuid | varchar | 36 |
name | varchar | 50 | |
creation_time | timestamp | ||
Key | last_login_time | timestamp | |
Key | flag | int | 11 |
CREATE TABLE `accounts` (
`user_id` INT(11) NOT NULL AUTO_INCREMENT,
`uuid` VARCHAR(36) NOT NULL,
`name` VARCHAR(50) NOT NULL,
`creation_time` TIMESTAMP NOT NULL DEFAULT '',
`last_login_time` TIMESTAMP NOT NULL DEFAULT '',
`flag` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`user_id`),
INDEX `uuid` (`uuid`),
INDEX `flag` (`flag`),
INDEX `last_login_time` (`last_login_time`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=0;
その他情報
UPDATE
対象の件数
SELECT count(*)
FROM accounts a
WHERE a.last_login_time < '2017/10/01';
/* 出力 1,810,588 */
/* Affected rows: 0 Found rows: 1 注意: 0 Duration for 1 クエリー: 13.719 sec. */
MariaDBのコンフィグ情報
- /etc/my.cnf.d/server.cnf
[server]
[mysqld]
innodb_buffer_pool_size=24000000000
max_allowed_packet=256MB
character-set-server = utf8
max_connections = 10000
max_user_connections = 10000
max_connect_errors = 9999999
wait_timeout = 30
event_scheduler=ON
datadir=/data/mysql
socket=/data/mysql/mysql.sock
[galera]
[embedded]
[mariadb]
[mariadb-10.1]
試したこと
不要なインデックスを削除する
accounts.name
に付いていたインデックスを削除しました。
速度に変化はありませんでした。Optimize
を実行する
以下を実行しましたが速度に変化はありませんでした。
OPTIMIZE TABLE db_name.accounts
/* note: Table does not support optimize, doing recreate + analyze instead */
/* status: OK */
補足情報(言語/FW/ツール等のバージョンなど)
- VPS(KVM)をレンタルしています
- CentOS 7.3 64bit
- MariaDB 10.2.7
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
0
条件式に
a.flag != 1
を追加したら件数絞れますよね。
投稿 2017/11/11 16:52
score 11640
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
-1
以下のクエリを実行して約30分経過しましたが結果が帰ってきません。CPU使用率が高い状態のままです。
UPDATE accounts a SET a.flag = 1 limit 1000000;
・where
で検索対象を絞りましょう
・インデックスを張りましょう
追記:
実際whereは含まれていませんし,「不要なインデックスを削除した」とは書かれていますがどの程度インデックスが張られているかは書かれていないですし,基本に立ち返るのは大切なので,現時点での回答として不適切とは思いませんが.
「評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。」とも書かれているはずです.
投稿 2017/11/11 18:52
score 170
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
91.51%
aglkjggg
2017/11/11 16:54
情報不足だった点申し訳ないです。
Kosuke_Shibuya
2017/11/11 16:59
aglkjggg
2017/11/11 17:44 編集
論点が少しズレてきて申し訳ないですが、
以下のクエリを実行して約30分経過しましたが結果が帰ってきません。CPU使用率が高い状態のままです。
CPU 12コア メモリ32GBのそれなりに高性能なサーバですので遅くても数分で結果が帰ってきても良いと考えているのですがここまで遅い原因がわかりかねます。
この点について何かご存知ありませんでしょうか。
そもそも100万件のUPDATEは数時間は必ずかかる処理と考えたほうがいいのでしょうか?
UPDATE accounts a SET a.flag = 1 limit 1000000;
Kosuke_Shibuya
2017/11/11 18:45
Kosuke_Shibuya
2017/11/11 18:55