web-dev-qa-db-ja.com

大きなテーブルでの単純なクエリの最適化

DB:MySQL 5.5.20(WampServer、デフォルト構成)
OS:Win 7
HDD:Western Digital 3TB Caviar Green、3.5インチ、IntelliPower、64MB、Sata3(WD30EZRX)
メモリ:8 GB
MySQL my.ini: http://pastie.org/private/go9kaxlmlvirati2txbaa

問題のクエリ:

SELECT name.id AS name_id、name.name、cast_info.id、
cast_info.role_id、cast_info.movi​​e_id
FROM cast_info
name.id = cast_info.person_id ON LEFT JOIN name
WHERE cast_info.movi​​e_id = 1000000
ORDER BY cast_info.movi​​e_id ASC

特定の映画に取り組んだすべての人を取得します。問題は、0.1秒から2.0秒近くまでかかる可能性があることです。長すぎます。ユーザーが1万回実行する必要がある場合、アプリケーションをアンインストールすることもできます。それが終わるのを待つ我慢もなかった。

編集:クエリの実行にかかる時間は、クエリに取り組んだ人の数によって決まります。 10人あたり約0.1秒。

説明:

*************************** 1.行******************** *******
id:1
select_type:SIMPLE
テーブル:cast_info
タイプ:参照
possible_keys:idx_mid、mpi
キー:idx_mid
key_len:4
ref:const
行:15
追加:
*************************** 2.行*************** ************
id:1
select_type:SIMPLE
テーブル:名前
タイプ:eq_ref
possible_keys:PRIMARY、id_name_idx
キー:プライマリ
key_len:4
参照:imdb.cast_info.person_id
行:1
追加:

テーブル:

テーブルの作成cast_info
id int(11)NOT NULL AUTO_INCREMENT、
person_id int(11)NOT NULL、
movie_id int(11)NOT NULL、
person_role_id int(11)デフォルトのNULL、
noteテキスト、
nr_order int(11)デフォルトのNULL、
role_id int(11)NOT NULL、
主キー(id)、
キーidx_pidperson_id)、
キーidx_midmovie_id)、
キーidx_cidperson_role_id)、
キーcast_info_role_id_existsrole_id)、
KEY mpimovie_idperson_idid
)ENGINE = MyISAM AUTO_INCREMENT = 33261692 DEFAULT CHARSET = utf8

CREATE TABLE name
id int(11)NOT NULL AUTO_INCREMENT、
name varchar(110)NOT NULL、
imdb_index varchar(12)デフォルトのNULL、
imdb_id int(11)デフォルトのNULL、
gender varchar(1)DEFAULT NULL、
name_pcode_cf varchar(5)デフォルトのNULL、
name_pcode_nf varchar(5)デフォルトのNULL、
surname_pcode varchar(5)デフォルトのNULL、
md5sum varchar(32)デフォルトのNULL、
主キー(id)、
キーidx_namename(6))、
キーidx_imdb_idimdb_id)、
キーidx_pcodecfname_pcode_cf)、
キーidx_pcodenfname_pcode_nf)、
キーidx_pcodesurname_pcode)、
キーidx_md5md5sum)、
キーid_name_idxidname
)ENGINE = MyISAM AUTO_INCREMENT = 4287972 DEFAULT CHARSET = utf8

ありがとう!

編集:これは、1人のユーザーが1つのローカルアプリケーションで使用するローカルデータベースであるため、MyISAMが使用されます。同時に1つのクエリのみが実行されます。また、IMDbPyはInnoDBでデータベースを構築するのに少なくとも1か月かかるため...

編集:InnoDBに変換した後にEXPLAINをクエリします

*************************** 1.行******************** *******
id:1
select_type:SIMPLE
テーブル:cast_info
タイプ:参照
possible_keys:mpi
キー:mpi
key_len:3
ref:const
行:23
追加:
*************************** 2.行*************** ************
id:1
select_type:SIMPLE
テーブル:名前
タイプ:eq_ref
possible_keys:PRIMARY、id_name_idx
キー:プライマリ
key_len:4
参照:imdb.cast_info.person_id
行:1
追加:

5
TheMagician

InnoDBを使用するとより高速に実行され、

  • _PRIMARY KEY_は「クラスター化」されています。これにより、nameへの検索が速くなります。

  • たとえば、5G(8GBマシンの場合)の_innodb_buffer_pool_size_を適切に設定すると、大量のデータがキャッシュされ、1万回の操作のI/Oが最小限になります。

また、必要に応じて_MEDIUMINT UNSIGNED_または_SMALLINT UNSIGNED_を使用して、データを縮小(およびI/Oを削減)することもできます。

削除できる(すべき)冗長なインデックスがあります。これはロードをスピードアップします。また、name(6)はおそらく役に立たないでしょう。

5
Rick James

クエリを見て、説明してから、テーブルの定義と最初の質問が頭に浮かびました。まだMyISAM @ 5.5を使用しているのはなぜですか?これをInnoDBに変更すると、結果が得られます。この0.1から2の範囲は、ロックまたはその他の理由が原因である可能性がありますが、最初にその問題を回避しましょう。

以下の変換ではテーブルがロックされ、ダウンタイムが発生する可能性があることに注意してください。

alter table cast_info engine=innodb;

alter table name engine=innodb;

1
mysql_user

パフォーマンスはハードドライブと一致しています。SSD、またはさらに優れたRAIDシステムを検討する必要があります。ドライブは低速なデスクトップクラスのハードドライバーであり、データベースの作業にはまったく適していません。 7200 rpmのデスクトップでテストしてみると、すでに改善が見られます。 Peopleテーブルが大きすぎてRAM(OSによってキャッシュされ、ユーザーメモリにロードされない))の場合、ハードドライブへの物理的な非順次アクセスがパフォーマンスの問題です。

「真の」データベースを実行しないが、デスクトップアプリケーションでデータを顧客に発送する場合、簡単な解決策は、必要なすべてのデータを使用して、映画の冗長フィールド「cast_data」を非正規化して追加することです。 JSONとして。このような構造の更新は、映画以外の方法(キャストの誕生日の更新など)で実行すると困難になりますが、データはストレージに関係なく非常に高速に取得されます。

1
user140142