PERF: improve performance of publish_notifications_state

PERF: improve performance of publish_notifications_state

User.publish_notifications_state is called every time a notification is created, this can become a very critical code path.

On some heavy notification related sites this can be a major CPU user on PG

This index makes it much cheaper to publish notification state, cause a simple index lookup does the trick.

diff --git a/app/models/notification.rb b/app/models/notification.rb
index 03160cd..c54d449 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -246,6 +246,7 @@ end
 #
 #  idx_notifications_speedup_unread_count                       (user_id,notification_type) WHERE (NOT read)
 #  index_notifications_on_post_action_id                        (post_action_id)
+#  index_notifications_on_read_or_n_type                        (user_id,id DESC,read,topic_id) UNIQUE WHERE (read OR (notification_type <> 6))
 #  index_notifications_on_user_id_and_created_at                (user_id,created_at)
 #  index_notifications_on_user_id_and_id                        (user_id,id) UNIQUE WHERE ((notification_type = 6) AND (NOT read))
 #  index_notifications_on_user_id_and_topic_id_and_post_number  (user_id,topic_id,post_number)
diff --git a/app/models/user_custom_field.rb b/app/models/user_custom_field.rb
index 0fb77e5..b648653 100644
--- a/app/models/user_custom_field.rb
+++ b/app/models/user_custom_field.rb
@@ -17,5 +17,6 @@ end
 #
 # Indexes
 #
+#  idx_user_custom_fields_last_reminded_at       (name,user_id) UNIQUE WHERE ((name)::text = 'last_reminded_at'::text)
 #  index_user_custom_fields_on_user_id_and_name  (user_id,name)
 #
diff --git a/db/migrate/20190514055014_add_read_notification_index.rb b/db/migrate/20190514055014_add_read_notification_index.rb
new file mode 100644
index 0000000..57b2c0a
--- /dev/null
+++ b/db/migrate/20190514055014_add_read_notification_index.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+class AddReadNotificationIndex < ActiveRecord::Migration[5.2]
+  disable_ddl_transaction!
+
+  def up
+    # doing this by hand cause I am ordering id DESC
+    execute <<~SQL
+      CREATE UNIQUE INDEX CONCURRENTLY index_notifications_on_read_or_n_type
+      ON notifications(user_id, id DESC, read, topic_id)
+      WHERE read or notification_type <> 6
+    SQL
+
+    # we need to do this to ensure this index hits
+    # on some sites this was missing prior
+    execute <<~SQL
+      VACUUM ANALYZE notifications
+    SQL
+  end
+
+  def down
+    raise ActiveRecord::IrreversibleMigration
+  end
+end

GitHub sha: 62418456

1 Like