Files
danbooru/db/migrate/20211008091234_merge_favorites_tables.rb
evazion 340e1008e9 favorites: merge favorites subtables.
Merge the 100 favorite subtables into a single table.

Previously the favorites table was partitioned by user id into 100
subtables to try to make searching by user id faster. This wasn't really
necessary and probably slower than just making an index on
(favorites.user_id, favorites.id) to satisfy ordfav searches. BTree
indexes are logarithmic so dividing an index by 100 doesn't make it 100
times faster to search; instead it just removes a layer or two from the
tree.

This also adds a uniqueness index on (user_id, post_id) to prevent
duplicate favorites. Previously we had to check for duplicates at the
application layer, which required careful locking to do it correctly.

Finally, this adds an index on favorites.id, which was surprisingly
missing before. This made ordering and deleting favorites by id really
slow because it degraded to a sequential scan.
2021-10-08 21:26:42 -05:00

32 lines
1.2 KiB
Ruby

require_relative "20100211181944_create_favorites.rb"
class MergeFavoritesTables < ActiveRecord::Migration[6.1]
def up
execute "set statement_timeout = 0"
execute "CREATE TABLE favorites_copy AS SELECT id, user_id, post_id FROM favorites"
revert CreateFavorites
rename_table :favorites_copy, :favorites
add_index :favorites, [:user_id, :post_id], unique: true, if_not_exists: true
add_index :favorites, [:user_id, :id], if_not_exists: true
add_index :favorites, :post_id, if_not_exists: true
change_column_null :favorites, :user_id, false
change_column_null :favorites, :post_id, false
execute "ALTER TABLE favorites ADD PRIMARY KEY (id)"
max_id = Favorite.maximum(:id).to_i
execute "CREATE SEQUENCE IF NOT EXISTS favorites_id_seq START #{max_id+1} OWNED BY favorites.id"
execute "ALTER TABLE favorites ALTER COLUMN id SET DEFAULT nextval('favorites_id_seq')"
end
def down
execute "set statement_timeout = 0"
rename_table :favorites, :favorites_copy
run CreateFavorites
execute "INSERT INTO favorites(id, user_id, post_id) SELECT id, user_id, post_id FROM favorites_copy"
drop_table :favorites_copy
end
end