Files
usenet-indexer/database/migrations/1768620765000_partial_indexes.ts
T

45 lines
2.2 KiB
TypeScript

import { BaseSchema } from '@adonisjs/lucid/schema'
/**
* Smaller indexes (LOG.md 2026-09-28 (17)). 99.5% of releases have no files
* yet (most never will), and search only looks at releases with files; most
* binaries have no size, fingerprint, file or parent. Indexing only the rows
* that queries can match saves GBs and work on every insert. Built
* concurrently, so ingest keeps running.
*/
const INDEXES: [table: string, name: string, definition: string][] = [
['releases', 'releases_name_trgm', `USING gin (name gin_trgm_ops) WHERE file_count > 0`],
['releases', 'releases_contents_trgm', `USING gin ((contents::text) gin_trgm_ops) WHERE file_count > 0`],
['releases', 'releases_posted_at_idx', `(posted_at DESC NULLS LAST) WHERE file_count > 0`],
['releases', 'releases_size_index', `(size) WHERE file_count > 0`],
['releases', 'releases_file_count_index', `(file_count) WHERE file_count > 0`],
['releases', 'releases_complete_idx', `(complete) WHERE file_count > 0`],
['releases', 'releases_category_idx', `(category) WHERE file_count > 0`],
['binaries', 'binaries_md5_16k_index', `(md5_16k) WHERE md5_16k IS NOT NULL`],
['binaries', 'binaries_size_index', `(size) WHERE size IS NOT NULL`],
['binaries', 'binaries_file_id_idx', `(file_id) WHERE file_id IS NOT NULL`],
['binaries', 'binaries_parent_binary_id_index', `(parent_binary_id) WHERE parent_binary_id IS NOT NULL`],
]
export default class extends BaseSchema {
static disableTransactions = true
async up() {
for (const [table, name, definition] of INDEXES) {
// Build the partial index under a temporary name, then swap it in.
await this.db.rawQuery(`DROP INDEX CONCURRENTLY IF EXISTS ${name}_partial`)
await this.db.rawQuery(`CREATE INDEX CONCURRENTLY ${name}_partial ON ${table} ${definition}`)
await this.db.rawQuery(`DROP INDEX CONCURRENTLY IF EXISTS ${name}`)
await this.db.rawQuery(`ALTER INDEX ${name}_partial RENAME TO ${name}`)
}
}
async down() {
for (const [table, name, definition] of INDEXES) {
const full = definition.replace(/ WHERE .*$/, '')
await this.db.rawQuery(`DROP INDEX CONCURRENTLY IF EXISTS ${name}`)
await this.db.rawQuery(`CREATE INDEX CONCURRENTLY ${name} ON ${table} ${full}`)
}
}
}