- 映画の大規模なデータベース (4000 以上の映画) があり、さまざまなショップの XML から取得したジャンル別にフィルター処理したいと考えています。
- すべての映画は複数のジャンルを持つことができるため、映画とジャンルは多対多の関係になります。
- すべてのジャンルに複数の名前を付けることができます (異なる言語、スペルミス)
- 元の形式のすべてのジャンル (すべてのスペルミスを含む) は、クロス結合テーブルと結合され、次に映画テーブルと結合されます。
- すべてのジャンルには、悪い名前と良い名前をグループ化 (またはクラスター化) する列と、出力したい名前を示す別の列があります。
- 映画データベースをフィルタリングして、ジャンルのスペルに関係なく、1 つまたは 2 つのジャンルから映画を選択したい
私のテーブルは次のように設定されています(movies
簡潔にするためにいくつかの列を削除しました):
CREATE TABLE `movies` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL DEFAULT '',
`alias` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `alias` (`alias`),
KEY `title` (`title`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
CREATE TABLE `movies_x_genre` (
`movieid` int(11) NOT NULL,
`genreid` int(11) unsigned NOT NULL,
PRIMARY KEY (`movieid`,`genreid`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `genre` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`genre` varchar(100) NOT NULL,
`group` int(11) unsigned DEFAULT NULL,
`type_id` tinyint(1) DEFAULT NULL,
`valid` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `genre` (`genre`,`type_id`),
KEY `idx_genre` (`genre`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
例:
有効または無効なジャンルがあります
INSERT INTO `genre` (`id`,`genre`,`group`,`type_id`,`valid`) VALUES
(1,"Comedy",1,1,1),
(2,"Comedies",1,1,0),
(3,"Action",2,1,1),
(4,"Acton",2,1,0);
INSERT INTO `movie_x_genre` (`movieid`,`genreid`) VALUES
(1,1),
(2,2),
(1,3),
(2,4);
説明
私が直面している問題は、映画のジャンルを多くの言語でジャンルテーブルに保存し、特定の言語ではジャンルのバリエーションを保存することです。すべてのジャンルは同じ意味、または少なくとも同じ意味ですが、別の言語では共通しています手動で設定された列に保存された「グループ」ID group
、映画はそれに付随するジャンルに結合され、ジャンルは新しい ID でデータベースに保存されます。新しいジャンルの場合、これにより、ジャンルを今すぐ使用して、グループに属する必要がある場合は後で修正します。なぜなら、毎日手動でジャンルをグループ化することはできないからです。
ジャンルの言語 ID は type_id に格納され、valid
列はジャンル名のどのバリエーションが正しいものであるかを示します。
クエリを選択
以下のクエリを実行すると、言語やバリエーションに関係なく、ジャンル「コメディ」のすべての映画が選択されます
「Comedies」を選択すると、ID 1 と ID 2 のムービーを選択したいのですが、どちらもコメディーであり、記述が異なるだけです。ただし、select クエリは非常に遅く、約 0.5 秒かかります。以下の部分を実行すると、「 tmp テーブルへのコピー」に非常に時間がかかっています
SET profiling = 1;
SELECT SQL_NO_CACHE i.id,i.alias,i.title
FROM genre g
INNER JOIN genre g2 ON g.`group`=g2.`group`
INNER JOIN movies_x_genre x ON x.genreid=g.id
INNER JOIN movies i ON i.id=x.movieid
WHERE g2.`genre` = "comedy"
GROUP BY i.id;
SHOW profile;
私はこの答えに出くわし、ディスクmysqlのtmpテーブルへのコピーをスキップして実行しました
SHOW VARIABLES LIKE '%tmp_table_size%';#1073741824 = 1GB
SHOW VARIABLES LIKE '%max_heap_table_size%';#1073741824 = 1GB
これ以上増やす必要はないと思います
選択が遅いのはなぜですか?テーブルを正しく整理しましたか? インデックスがありませんか? テーブルが間違っている場合、どのようにテーブルを整理すればよいですか? そのような映画をフィルタリングするための情報を保存する最も効率的な方法は何ですか?