190 lines
7.9 KiB
SQL
190 lines
7.9 KiB
SQL
CREATE EXTENSION IF NOT EXISTS hstore;
|
|
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
CREATE EXTENSION IF NOT EXISTS btree_gin;
|
|
|
|
CREATE TYPE name_kind AS ENUM ('main', 'original', 'romaji', 'kanji', 'english');
|
|
CREATE TYPE artist_kind AS ENUM ('main', 'original', 'performer', 'composer', 'arranger');
|
|
|
|
|
|
-- groups resources in specific releases / groupings
|
|
CREATE TABLE releases (
|
|
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
identifiers TEXT[] NOT NULL DEFAULT '{}'::TEXT[], -- array of "semi-unique" identifiers, like site sources or identifiers
|
|
metadata jsonb NOT NULL DEFAULT '{}'::jsonb
|
|
);
|
|
|
|
CREATE INDEX idx_releases_identifiers_gin ON releases USING GIN (identifiers);
|
|
|
|
CREATE TABLE resources (
|
|
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
hash bytea UNIQUE NOT NULL, -- hash of the resource, SHA256
|
|
size BIGINT NOT NULL,
|
|
path bytea, -- can be null if not available locally
|
|
mime TEXT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX idx_resources_hash ON resources USING BTREE (hash); -- TODO: check if you can do partial prefix queries
|
|
CREATE INDEX idx_resources_path ON resources USING BTREE (path);
|
|
CREATE INDEX idx_resources_path_gin ON resources USING GIN (path); -- Allows for partial path queries
|
|
|
|
CREATE TABLE resource_alternate_identifiers (
|
|
resource BIGINT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
identifier bytea NOT NULL,
|
|
|
|
CONSTRAINT fk_resource FOREIGN KEY (resource) REFERENCES resources(id),
|
|
CONSTRAINT idx_resource_alternate_identifiers UNIQUE (resource, name, identifier)
|
|
);
|
|
CREATE INDEX idx_resource_alternate_identifiers_resource ON resource_alternate_identifiers USING BTREE (resource) INCLUDE (name, identifier);
|
|
CREATE INDEX idx_resource_alternate_identifiers_name_identifier ON resource_alternate_identifiers USING BTREE (name, identifier) INCLUDE (resource);
|
|
|
|
CREATE TABLE resource_releases (
|
|
resource BIGINT NOT NULL,
|
|
release BIGINT NOT NULL,
|
|
|
|
CONSTRAINT fk_resource FOREIGN KEY (resource) REFERENCES resources(id),
|
|
CONSTRAINT fk_release FOREIGN KEY (release) REFERENCES releases(id),
|
|
CONSTRAINT idx_resource_releases UNIQUE (resource, release)
|
|
);
|
|
|
|
CREATE INDEX idx_resource_releases_resource ON resource_releases USING BTREE (resource) INCLUDE (release);
|
|
CREATE INDEX idx_resource_releases_release ON resource_releases USING BTREE (release) INCLUDE (resource);
|
|
|
|
CREATE TABLE albums (
|
|
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
cover BIGINT, -- can be null if not available
|
|
identifiers TEXT[] NOT NULL DEFAULT '{}'::TEXT[], -- array of "semi-unique" identifiers, like catalog number
|
|
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
|
|
CONSTRAINT fk_cover FOREIGN KEY (cover) REFERENCES resources(id)
|
|
);
|
|
CREATE INDEX idx_albums_identifiers_gin ON albums USING GIN (identifiers);
|
|
|
|
|
|
CREATE TABLE albums_names (
|
|
album INTEGER NOT NULL,
|
|
kind name_kind NOT NULL,
|
|
name TEXT NOT NULL,
|
|
CONSTRAINT idx_albums_names UNIQUE (album, kind),
|
|
CONSTRAINT fk_album FOREIGN KEY (album) REFERENCES albums(id)
|
|
);
|
|
CREATE INDEX idx_albums_names_album ON albums_names USING BTREE (album);
|
|
CREATE INDEX idx_albums_names_name_gin ON albums_names USING GIN (name gin_trgm_ops);
|
|
|
|
|
|
CREATE TABLE artists (
|
|
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
metadata jsonb NOT NULL DEFAULT '{}'::jsonb
|
|
);
|
|
|
|
CREATE TABLE artists_names (
|
|
artist INTEGER NOT NULL,
|
|
kind name_kind NOT NULL,
|
|
name TEXT NOT NULL,
|
|
CONSTRAINT idx_artists_names UNIQUE (artist, kind),
|
|
CONSTRAINT fk_artist FOREIGN KEY (artist) REFERENCES artists(id)
|
|
);
|
|
CREATE INDEX idx_artists_names_artist ON artists_names USING BTREE (artist);
|
|
CREATE INDEX idx_artists_names_name_gin ON artists_names USING GIN (name gin_trgm_ops);
|
|
|
|
CREATE TABLE songs (
|
|
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
resource BIGINT NOT NULL,
|
|
cover BIGINT, -- set to override album cover. can be null if not available
|
|
album INTEGER, -- can be null
|
|
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
|
|
CONSTRAINT fk_resource FOREIGN KEY (resource) REFERENCES resources(id),
|
|
CONSTRAINT fk_cover FOREIGN KEY (cover) REFERENCES resources(id),
|
|
CONSTRAINT fk_album FOREIGN KEY (album) REFERENCES albums(id)
|
|
);
|
|
CREATE INDEX idx_songs_resource ON songs USING BTREE (resource);
|
|
CREATE INDEX idx_songs_album ON songs USING BTREE (album);
|
|
|
|
CREATE TABLE songs_names (
|
|
song INTEGER NOT NULL,
|
|
kind name_kind NOT NULL,
|
|
name TEXT NOT NULL,
|
|
CONSTRAINT idx_songs_names UNIQUE (song, kind),
|
|
CONSTRAINT fk_song FOREIGN KEY (song) REFERENCES songs(id)
|
|
);
|
|
CREATE INDEX idx_songs_names_song ON songs_names USING BTREE (song);
|
|
CREATE INDEX idx_songs_names_name_gin ON songs_names USING GIN (name gin_trgm_ops);
|
|
|
|
-- extra mapping table of artists <-> song
|
|
CREATE TABLE album_artists (
|
|
album INTEGER NOT NULL,
|
|
artist INTEGER NOT NULL,
|
|
kind artist_kind NOT NULL,
|
|
CONSTRAINT idx_album_artists UNIQUE (album, artist, kind),
|
|
CONSTRAINT fk_album FOREIGN KEY (album) REFERENCES albums(id),
|
|
CONSTRAINT fk_artist FOREIGN KEY (artist) REFERENCES artists(id)
|
|
);
|
|
|
|
CREATE INDEX idx_album_artists_album ON album_artists USING BTREE (album) INCLUDE (artist, kind);
|
|
CREATE INDEX idx_album_artists_artist ON album_artists USING BTREE (artist) INCLUDE (album);
|
|
-- CREATE INDEX idx_album_artists_artist_kind ON album_artists (artist, kind);
|
|
|
|
-- extra mapping table of artists <-> song
|
|
CREATE TABLE song_artists (
|
|
song INTEGER NOT NULL,
|
|
artist INTEGER NOT NULL,
|
|
kind artist_kind NOT NULL,
|
|
CONSTRAINT idx_song_artists UNIQUE (song, artist, kind),
|
|
CONSTRAINT fk_song FOREIGN KEY (song) REFERENCES songs(id),
|
|
CONSTRAINT fk_artist FOREIGN KEY (artist) REFERENCES artists(id)
|
|
);
|
|
|
|
CREATE INDEX idx_song_artists_song ON song_artists USING BTREE (song) INCLUDE (artist, kind);
|
|
CREATE INDEX idx_song_artists_artist ON song_artists USING BTREE (artist) INCLUDE (song);
|
|
-- CREATE INDEX idx_song_artists_artist_kind ON song_artists (artist, kind);
|
|
|
|
CREATE TABLE tags (
|
|
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
|
name TEXT UNIQUE NOT NULL
|
|
);
|
|
|
|
-- primary key covering index
|
|
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS tags_pkey_new ON tags USING BTREE (id) INCLUDE (name);
|
|
ALTER TABLE tags DROP CONSTRAINT tags_pkey, ADD CONSTRAINT tags_pkey PRIMARY KEY USING INDEX tags_pkey_new;
|
|
|
|
CREATE INDEX idx_tags_name ON tags USING BTREE (name) INCLUDE (id);
|
|
|
|
|
|
CREATE TABLE song_taggings (
|
|
tag INTEGER NOT NULL,
|
|
song BIGINT NOT NULL,
|
|
|
|
CONSTRAINT fk_tag FOREIGN KEY (tag) REFERENCES tags(id),
|
|
CONSTRAINT fk_song FOREIGN KEY (song) REFERENCES songs(id),
|
|
CONSTRAINT idx_song_taggings UNIQUE (tag, song)
|
|
);
|
|
|
|
CREATE INDEX idx_song_taggings_tag ON song_taggings USING BTREE (tag) INCLUDE (song);
|
|
CREATE INDEX idx_song_taggings_song ON song_taggings USING BTREE (song) INCLUDE (tag);
|
|
|
|
|
|
CREATE TABLE album_taggings (
|
|
tag INTEGER NOT NULL,
|
|
album INTEGER NOT NULL,
|
|
|
|
CONSTRAINT fk_tag FOREIGN KEY (tag) REFERENCES tags(id),
|
|
CONSTRAINT fk_song FOREIGN KEY (album) REFERENCES albums(id),
|
|
CONSTRAINT idx_album_taggings UNIQUE (tag, album)
|
|
);
|
|
|
|
CREATE INDEX idx_album_taggings_tag ON album_taggings USING BTREE (tag) INCLUDE (album);
|
|
CREATE INDEX idx_album_taggings_album ON album_taggings USING BTREE (album) INCLUDE (tag);
|
|
|
|
-- -- Panako fingerprints
|
|
-- CREATE TABLE song_fingerprints (
|
|
-- song BIGINT NOT NULL,
|
|
-- hash INTEGER NOT NULL, -- 32-bit value
|
|
-- packed INTEGER NOT NULL, -- 32-bit value, packed Time + Frequency
|
|
-- CONSTRAINT idx_song_fingerprints UNIQUE (song, hash, packed),
|
|
-- CONSTRAINT fk_song FOREIGN KEY (song) REFERENCES songs(id)
|
|
-- );
|
|
|
|
-- -- TODO: check this again when CLUSTER works for BRIN: CREATE INDEX idx_song_fingerprints_hash ON song_fingerprints USING BRIN (hash) WITH (pages_per_range = 32, autosummarize = on); -- Use BRIN indexes to have small cache size, BTREE would have more overhead on top
|
|
-- CREATE INDEX idx_song_fingerprints_hash ON song_fingerprints USING BTREE (hash) WITH (fillfactor = 80); -- lower fillfactor for faster insertions
|
|
-- CLUSTER VERBOSE song_fingerprints USING idx_song_fingerprints_hash; |