ほとんどのテーブルでMySQL 5.6とInnoDBストレージエンジンを使用します。InnoDBバッファープールのサイズは15 GBで、Innodb DB +インデックスは約10 GBです。サーバーには32GBのRAMがあり、Cent OS 7 x64を実行しています。
約1,000万件以上のレコードを含む1つの大きなテーブルがあります。
24時間ごとにリモートサーバーから更新されたダンプファイルを取得します。ファイルはcsv形式です。私はそのフォーマットを制御できません。ファイルは最大750 MBです。MyISAMテーブルに行ごとにデータを挿入しようとしましたが、35分かかりました。
ファイルから10-12のうち1行につき3つの値のみを取得し、データベースで更新する必要があります。
このようなことを達成する最良の方法は何ですか?
これを毎日する必要があります。
現在、Flowは次のようになっています。
- mysqli_begin_transaction
- ファイルを1行ずつ読み込む
- 各レコードを行ごとに更新します。
- mysqli_commit
上記の操作を完了するには約30〜40分かかりますが、これを実行している間、他の更新が行われているため、
ロック待機タイムアウトを超過しました。トランザクションを再開してみてください
アップデート1
を使用して新しいテーブルにデータを読み込みますLOAD DATA LOCAL INFILE
。MyISAM 38.93 sec
では、InnoDBでは7分5.21秒かかりました。それから私はやった:
UPDATE table1 t1, table2 t2
SET
t1.field1 = t2.field1,
t1.field2 = t2.field2,
t1.field3 = t2.field3
WHERE t1.field10 = t2.field10
Query OK, 434914 rows affected (22 hours 14 min 47.55 sec)
更新2
結合クエリを使用した同じ更新
UPDATE table1 a JOIN table2 b
ON a.field1 = b.field1
SET
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4
(14 hours 56 min 46.85 sec)
コメントの質問からの明確化:
- テーブル内の行の約6%がファイルによって更新されますが、25%になることもあります。
- 更新されるフィールドにはインデックスがあります。テーブルには12個のインデックスがあり、8個のインデックスには更新フィールドが含まれています。
- 1つのトランザクションで更新を行う必要はありません。時間がかかることがありますが、24時間以内です。後でこのテーブルに依存しているsphinxインデックスを更新する必要があるため、テーブル全体をロックせずに1時間で完了できるようにしています。データベースが他のタスクに使用できる限り、ステップに時間がかかるかどうかは関係ありません。
- 前処理ステップでcsv形式を変更できます。重要なのは、迅速な更新とロックなしです。
- 表2はMyISAMです。これは、インファイルのロードデータを使用してcsvファイルから新しく作成されたテーブルです。MYIファイルのサイズは452 MBです。表2は、field1列で索引付けされています。
- MyISAMテーブルのMYDは663MBです。
アップデート3:
両方のテーブルの詳細を次に示します。
CREATE TABLE `content` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`og_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`keywords` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`files_count` smallint(5) unsigned NOT NULL DEFAULT '0',
`more_files` smallint(5) unsigned NOT NULL DEFAULT '0',
`files` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`category` smallint(3) unsigned NOT NULL DEFAULT '600',
`size` bigint(19) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) NOT NULL DEFAULT '0',
`completed` int(11) NOT NULL DEFAULT '0',
`uploaders` int(11) NOT NULL DEFAULT '0',
`creation_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0',
`comments_count` int(11) NOT NULL DEFAULT '0',
`imdb` int(8) unsigned NOT NULL DEFAULT '0',
`video_sample` tinyint(1) NOT NULL DEFAULT '0',
`video_quality` tinyint(2) NOT NULL DEFAULT '0',
`audio_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`subtitle_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
`uploader` int(11) unsigned NOT NULL DEFAULT '0',
`anonymous` tinyint(1) NOT NULL DEFAULT '0',
`enabled` tinyint(1) unsigned NOT NULL DEFAULT '0',
`tfile_size` int(11) unsigned NOT NULL DEFAULT '0',
`scrape_source` tinyint(1) unsigned NOT NULL DEFAULT '0',
`record_num` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`record_num`),
UNIQUE KEY `hash` (`hash`),
KEY `uploaders` (`uploaders`),
KEY `tfile_size` (`tfile_size`),
KEY `enabled_category_upload_date_verified_` (`enabled`,`category`,`upload_date`,`verified`),
KEY `enabled_upload_date_verified_` (`enabled`,`upload_date`,`verified`),
KEY `enabled_category_verified_` (`enabled`,`category`,`verified`),
KEY `enabled_verified_` (`enabled`,`verified`),
KEY `enabled_uploader_` (`enabled`,`uploader`),
KEY `anonymous_uploader_` (`anonymous`,`uploader`),
KEY `enabled_uploaders_upload_date_` (`enabled`,`uploaders`,`upload_date`),
KEY `enabled_verified_category` (`enabled`,`verified`,`category`),
KEY `verified_enabled_category` (`verified`,`enabled`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=7551163 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=FIXED
CREATE TABLE `content_csv_dump_temp` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`category_id` int(11) unsigned NOT NULL DEFAULT '0',
`uploaders` int(11) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) unsigned NOT NULL DEFAULT '0',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
そして、ここcontent
からのデータを使用してテーブルを更新する更新クエリですcontent_csv_dump_temp
UPDATE content a JOIN content_csv_dump_temp b
ON a.hash = b.hash
SET
a.uploaders = b.uploaders,
a.downloaders = b.downloaders,
a.verified = b.verified
アップデート4:
上記のテストはすべてテストマシンで行われましたが、現在は実稼働マシンで同じテストを行っており、クエリは非常に高速です。
mysql> UPDATE content_test a JOIN content_csv_dump_temp b
-> ON a.hash = b.hash
-> SET
-> a.uploaders = b.uploaders,
-> a.downloaders = b.downloaders,
-> a.verified = b.verified;
Query OK, 2673528 rows affected (7 min 50.42 sec)
Rows matched: 7044818 Changed: 2673528 Warnings: 0
私の間違いをおforびします。各レコードの更新の代わりに結合を使用する方が適切です。今私はrick_jamesによって提案されたインデックスを使用してmpreを改善しようとしていますが、ベンチマークが完了したら更新されます。
UPDATEs
ます。csvデータからテーブルを更新するための簡単なステートメントがどのように見えるかを正確に教えてください。 その後、お客様の要件を満たす手法を考案するお手伝いをいたします。
update
、かつ更新質問を確認してください、ありがとう。
INDEX(field2, field3, field4)
(任意の順序で)持っていますか?見せてくださいSHOW CREATE TABLE
。