zulip/zerver/migrations/0343_alter_useractivityinte...

20 lines
527 B
Python
Raw Normal View History

migrations: Add a (profile,end) index on useractivityinterval. The `user_activity_interval` worker calls: ```python3 last = UserActivityInterval.objects.filter(user_profile=user_profile).order_by("-end")[0] ````` Which results in a query like: ```sql SELECT "zerver_useractivityinterval"."id", "zerver_useractivityinterval"."user_profile_id", "zerver_useractivityinterval"."start", "zerver_useractivityinterval"."end" FROM "zerver_useractivityinterval" WHERE "zerver_useractivityinterval"."user_profile_id" = 12345 ORDER BY "zerver_useractivityinterval"."end" DESC LIMIT 1 ``` For users which have at least one matching row, this results in a query plan like: ``` Limit (cost=0.56..711.38 rows=1 width=24) (actual time=0.078..0.078 rows=1 loops=1) -> Index Scan Backward using zerver_useractivityinterval_7f021a14 on zerver_useractivityinterval (cost=0.56..1031399.46 rows=1451 width=24) (actual time=0.077..0.078 rows=1 loops=1) Filter: (user_profile_id = 12345) Rows Removed by Filter: 98 Planning Time: 0.059 ms Execution Time: 0.088 ms ``` But for users that have just been created, with no matching rows, this is considerably more expensive: ``` Limit (cost=0.56..711.38 rows=1 width=24) (actual time=10798.146..10798.146 rows=0 loops=1) -> Index Scan Backward using zerver_useractivityinterval_7f021a14 on zerver_useractivityinterval (cost=0.56..1031399.46 rows=1451 width=24) (actual time=10798.145..10798.145 rows=0 loops=1) Filter: (user_profile_id = 12345) Rows Removed by Filter: (count of every single row in the table, redacted) Planning Time: 0.053 ms Execution Time: 10798.158 ms ``` Regular vacuuming can force the use of the index on `user_profile_id` as long as there are few enough users, which is fast -- however, at some point, the query planner decides that is insufficiently specific, always chooses the effective-whole-table-scan. Add an index on `(user_profile_id, end)`, which is expected to be sufficiently specific that it is used even with large numbers of user profiles. Ref #19250.
2021-08-31 20:27:52 +02:00
# Generated by Django 3.2.6 on 2021-08-31 19:17
from django.db import migrations, models
migrations: Add a (profile,end) index on useractivityinterval. The `user_activity_interval` worker calls: ```python3 last = UserActivityInterval.objects.filter(user_profile=user_profile).order_by("-end")[0] ````` Which results in a query like: ```sql SELECT "zerver_useractivityinterval"."id", "zerver_useractivityinterval"."user_profile_id", "zerver_useractivityinterval"."start", "zerver_useractivityinterval"."end" FROM "zerver_useractivityinterval" WHERE "zerver_useractivityinterval"."user_profile_id" = 12345 ORDER BY "zerver_useractivityinterval"."end" DESC LIMIT 1 ``` For users which have at least one matching row, this results in a query plan like: ``` Limit (cost=0.56..711.38 rows=1 width=24) (actual time=0.078..0.078 rows=1 loops=1) -> Index Scan Backward using zerver_useractivityinterval_7f021a14 on zerver_useractivityinterval (cost=0.56..1031399.46 rows=1451 width=24) (actual time=0.077..0.078 rows=1 loops=1) Filter: (user_profile_id = 12345) Rows Removed by Filter: 98 Planning Time: 0.059 ms Execution Time: 0.088 ms ``` But for users that have just been created, with no matching rows, this is considerably more expensive: ``` Limit (cost=0.56..711.38 rows=1 width=24) (actual time=10798.146..10798.146 rows=0 loops=1) -> Index Scan Backward using zerver_useractivityinterval_7f021a14 on zerver_useractivityinterval (cost=0.56..1031399.46 rows=1451 width=24) (actual time=10798.145..10798.145 rows=0 loops=1) Filter: (user_profile_id = 12345) Rows Removed by Filter: (count of every single row in the table, redacted) Planning Time: 0.053 ms Execution Time: 10798.158 ms ``` Regular vacuuming can force the use of the index on `user_profile_id` as long as there are few enough users, which is fast -- however, at some point, the query planner decides that is insufficiently specific, always chooses the effective-whole-table-scan. Add an index on `(user_profile_id, end)`, which is expected to be sufficiently specific that it is used even with large numbers of user profiles. Ref #19250.
2021-08-31 20:27:52 +02:00
class Migration(migrations.Migration):
dependencies = [
("zerver", "0342_realm_demo_organization_scheduled_deletion_date"),
]
operations = [
migrations.AddIndex(
model_name="useractivityinterval",
index=models.Index(
fields=["user_profile", "end"],
name="zerver_useractivityinterval_user_profile_id_end_bb3bfc37_idx",
),
migrations: Add a (profile,end) index on useractivityinterval. The `user_activity_interval` worker calls: ```python3 last = UserActivityInterval.objects.filter(user_profile=user_profile).order_by("-end")[0] ````` Which results in a query like: ```sql SELECT "zerver_useractivityinterval"."id", "zerver_useractivityinterval"."user_profile_id", "zerver_useractivityinterval"."start", "zerver_useractivityinterval"."end" FROM "zerver_useractivityinterval" WHERE "zerver_useractivityinterval"."user_profile_id" = 12345 ORDER BY "zerver_useractivityinterval"."end" DESC LIMIT 1 ``` For users which have at least one matching row, this results in a query plan like: ``` Limit (cost=0.56..711.38 rows=1 width=24) (actual time=0.078..0.078 rows=1 loops=1) -> Index Scan Backward using zerver_useractivityinterval_7f021a14 on zerver_useractivityinterval (cost=0.56..1031399.46 rows=1451 width=24) (actual time=0.077..0.078 rows=1 loops=1) Filter: (user_profile_id = 12345) Rows Removed by Filter: 98 Planning Time: 0.059 ms Execution Time: 0.088 ms ``` But for users that have just been created, with no matching rows, this is considerably more expensive: ``` Limit (cost=0.56..711.38 rows=1 width=24) (actual time=10798.146..10798.146 rows=0 loops=1) -> Index Scan Backward using zerver_useractivityinterval_7f021a14 on zerver_useractivityinterval (cost=0.56..1031399.46 rows=1451 width=24) (actual time=10798.145..10798.145 rows=0 loops=1) Filter: (user_profile_id = 12345) Rows Removed by Filter: (count of every single row in the table, redacted) Planning Time: 0.053 ms Execution Time: 10798.158 ms ``` Regular vacuuming can force the use of the index on `user_profile_id` as long as there are few enough users, which is fast -- however, at some point, the query planner decides that is insufficiently specific, always chooses the effective-whole-table-scan. Add an index on `(user_profile_id, end)`, which is expected to be sufficiently specific that it is used even with large numbers of user profiles. Ref #19250.
2021-08-31 20:27:52 +02:00
),
]