web-dev-qa-db-ja.com

複数のテーブルにまたがるインデックスが必要な場合は、データベースを非正規化する必要があります

アルバムと曲の名前のカタログがあります。この曲には、アルバムテーブルへの外部キーがあります。私は次のようなクエリを期待しています:

SELECT * FROM song s
JOIN album a ON a.id = s.album_id
WHERE LOWER(CONCAT_WS(' ', album.name, song.name) = LOWER('Meteora Breaking The Habit')

上記のタイプの検索用語にインデックスを作成したいのですが、複数のテーブルにまたがるインデックスを作成できないようです。この場合、テーブルを非正規化し、曲とアルバムの名前を1つのテーブルに入れるのは理にかなっていますか、それともより良いアプローチがありますか?

参照表:

CREATE TABLE album (
   id SERIAL PRIMARY KEY,
   name text NOT NULL
);

CREATE TABLE song (
   id SERIAL PRIMARY KEY,
   name text NOT NULL,
   album_id integer NOT NULL,
   CONSTRAINT album_id_fk FOREIGN KEY (album_id) REFERENCES album (id)
);

P.S.理解のために、クエリが最初に曲名、後でアルバム名になる可能性があるという事実を無視しています。また、そのクエリを無視すると、バンド名も含まれる可能性があります。クライアントから送信されるクエリの形式はalbum.name + ' ' + song.name

4
user4150760

クエリのLOWER('Meteora Breaking The Habit')部分を、制御できないソースから取得している場合は、曲/アルバムテーブルの構造を維持することをお勧めします(ただし、songテーブルからalbum_idを削除します)。 3番目のテーブルを含める:

CREATE TABLE ALBUM_SONG (
  album_id,
  song_id,
  album_song_name -- this would be album.name || song.name
)

これは基本的に、M-M関係の2つの間の結合テーブルです(「なぜなら、同じ曲が複数のアルバムに含まれている可能性があるからです)。

次に、LOWER(album_song_name)の結合テーブルにインデックスを付けてクエリを実行できます。

1
Joishi Bodio

私のアドバイスと経験-データベースを非正規化しないでください。代わりにそれを再設計し、少なくとも1NF、2NF、および3NFを使用します。私はあなたが使っているテーブルにあまり精通していません。 PKは両方で同じように見えると考えてください。アルバムのPKは曲のPKと同じである必要がありますか?曲はアルバムに依存しているので、ここでは必要ないと思います。これらは1つのテーブルに入れるべきだと思います。アルバムと曲はアーティストに部分的にのみ依存しているため、テーブルで識別される必要があるのはアーティストであり、これらは別のテーブルのアルバムIDにリンクする必要がありますか?私は学位を取得し、リレーショナルデータベースの使用を開始したばかりなので、ここでの支援と学習を望んでいます。

0
Treasa