db: add user_actions view.

Add a user_actions view. This view unions together a bunch of tables to
produce an event log of every action taken by a user.

Also add a bunch of indexes to make queries on this table efficient.
Even though the view is an enormous query combining together about 30
different tables, queries are very efficient as long as every table has
`created_at` and `(user_id, created)` indexes.
This commit is contained in:
evazion
2022-09-13 20:33:53 -05:00
parent abf493794f
commit 0830af49a7
3 changed files with 849 additions and 48 deletions

View File

@@ -0,0 +1,67 @@
class CreateUserActions < ActiveRecord::Migration[7.0]
disable_ddl_transaction!
def change
create_view :user_actions
add_index :bans, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :bulk_update_requests, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :dmails, :created_at, algorithm: :concurrently, where: "owner_id = from_id", name: "index_sent_dmails_on_created_at", if_not_exists: true
add_index :favorite_groups, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :forum_posts, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :forum_post_votes, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :forum_topics, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :moderation_reports, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :post_approvals, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :post_disapprovals, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :post_flags, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :post_replacements, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :saved_searches, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :tag_aliases, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :tag_implications, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :tag_versions, :created_at, algorithm: :concurrently, where: "updater_id IS NOT NULL", name: "index_tag_versions_on_created_at_where_updater_id_is_not_null", if_not_exists: true
add_index :users, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :user_events, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :user_feedback, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :uploads, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :user_upgrades, :created_at, algorithm: :concurrently, where: "status IN (20, 30)", name: "index_completed_user_upgrades_on_created_at", if_not_exists: true
add_index :user_name_change_requests, :created_at, algorithm: :concurrently, if_not_exists: true
add_index :artist_versions, [:updater_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :artist_commentary_versions, [:updater_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :bans, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :bulk_update_requests, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :comments, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :comment_votes, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :dmails, [:owner_id, :created_at], algorithm: :concurrently, where: "owner_id = from_id", name: "index_sent_dmails_on_owner_id_and_created_at", if_not_exists: true
add_index :favorite_groups, [:created_at, :id, :is_public, :creator_id], algorithm: :concurrently, name: "index_favorite_groups_on_created_at_id_is_public_creator_id", if_not_exists: true
add_index :forum_posts, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :forum_post_votes, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :forum_topics, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :mod_actions, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :moderation_reports, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :note_versions, [:updater_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :posts, [:uploader_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :post_appeals, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :post_approvals, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :post_disapprovals, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :post_flags, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :post_replacements, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :post_votes, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :saved_searches, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :tag_aliases, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :tag_implications, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :tag_versions, [:updater_id, :created_at], algorithm: :concurrently, where: "updater_id IS NOT NULL", name: "index_tag_versions_on_updater_id_and_created_at", if_not_exists: true
add_index :uploads, [:uploader_id, :created_at, :id], algorithm: :concurrently, if_not_exists: true
add_index :users, [:id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :user_events, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :user_feedback, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :user_feedback, [:creator_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :user_upgrades, [:purchaser_id, :created_at], algorithm: :concurrently, where: "status IN (20, 30)", name: "index_completed_user_upgrades_on_updater_id_and_created_at", if_not_exists: true
add_index :user_name_change_requests, [:user_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :wiki_page_versions, [:updater_id, :created_at], algorithm: :concurrently, if_not_exists: true
add_index :forum_posts, [:topic_id, :id], algorithm: :concurrently, if_not_exists: true
add_index :users, :bit_prefs, where: "get_bit(bit_prefs::bit(31), 24) = 1", algorithm: :concurrently, name: "index_users_on_enable_private_favorites", if_not_exists: true # users.enable_private_favorites = true
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
SELECT 'ArtistVersion'::character varying AS model_type, id AS model_id, updater_id AS user_id, 'create'::character varying AS event_type, created_at AS event_at
FROM artist_versions
UNION ALL
SELECT 'ArtistCommentaryVersion', id, updater_id, 'create', created_at
FROM artist_commentary_versions
UNION ALL
SELECT 'Ban', id, user_id, 'subject', created_at
FROM bans
UNION ALL
SELECT 'BulkUpdateRequest', id, user_id, 'create', created_at
FROM bulk_update_requests
UNION ALL
SELECT 'Comment', id, creator_id, 'create', created_at
FROM comments
UNION ALL
SELECT 'CommentVote', id, user_id, 'create', created_at
FROM comment_votes
UNION ALL (
SELECT 'Dmail', id, from_id, 'create', created_at
FROM dmails
WHERE from_id != owner_id
ORDER BY created_at DESC
)
UNION ALL
SELECT 'FavoriteGroup', id, creator_id, 'create', created_at
FROM favorite_groups
UNION ALL
SELECT 'ForumPost', id, creator_id, 'create', created_at
FROM forum_posts
UNION ALL
SELECT 'ForumPostVote', id, creator_id, 'create', created_at
FROM forum_post_votes
UNION ALL
SELECT 'ForumTopic', id, creator_id, 'create', created_at
FROM forum_topics
UNION ALL
SELECT 'ModAction', id, creator_id, 'create', created_at
FROM mod_actions
UNION ALL
SELECT 'ModerationReport', id, creator_id, 'create', created_at
FROM moderation_reports
UNION ALL
SELECT 'NoteVersion', id, updater_id, 'create', created_at
FROM note_versions
UNION ALL
SELECT 'Post', id, uploader_id, 'create', created_at
FROM posts
UNION ALL
SELECT 'PostAppeal', id, creator_id, 'create', created_at
FROM post_appeals
UNION ALL
SELECT 'PostApproval', id, user_id, 'create', created_at
FROM post_approvals
UNION ALL
SELECT 'PostDisapproval', id, user_id, 'create', created_at
FROM post_disapprovals
UNION ALL
SELECT 'PostFlag', id, creator_id, 'create', created_at
FROM post_flags
UNION ALL
SELECT 'PostReplacement', id, creator_id, 'create', created_at
FROM post_replacements
UNION ALL
SELECT 'PostVote', id, user_id, 'create', created_at
FROM post_votes
UNION ALL
SELECT 'SavedSearch', id, user_id, 'create', created_at
FROM saved_searches
UNION ALL
SELECT 'TagAlias', id, creator_id, 'create', created_at
FROM tag_aliases
UNION ALL
SELECT 'TagImplication', id, creator_id, 'create', created_at
FROM tag_implications
UNION ALL (
SELECT 'TagVersion', id, updater_id, 'create', created_at
FROM tag_versions
WHERE updater_id IS NOT NULL
ORDER BY created_at DESC
) UNION ALL
SELECT 'Upload', id, uploader_id, 'create', created_at
FROM uploads
UNION ALL
SELECT 'User', id, id, 'create', created_at
FROM users
UNION ALL
SELECT 'UserEvent', id, user_id, 'create', created_at
FROM user_events
UNION ALL
SELECT 'UserFeedback', id, creator_id, 'create', created_at
FROM user_feedback
UNION ALL
SELECT 'UserFeedback', id, user_id, 'subject', created_at
FROM user_feedback
UNION ALL (
SELECT 'UserUpgrade', id, purchaser_id, 'create', created_at
FROM user_upgrades
WHERE status IN (20, 30)
ORDER BY created_at DESC
) UNION ALL
SELECT 'UserNameChangeRequest', id, user_id, 'create', created_at
FROM user_name_change_requests
UNION ALL
SELECT 'WikiPageVersion', id, updater_id, 'create', created_at
FROM wiki_page_versions