分頁顯示是web開發常見需求,隨着表數據增加,200萬以上時,翻頁越到后面越慢,這個時候慢查詢成為一個痛點,關於count(*)慢的原因,簡單說會進行全表掃描,再排序,導致查詢變慢。這里介紹postgresql一種解決方案。對於大表,我們有時候並不需要返回精確的數值,可以采用模糊的總數代替。
原始語句
SELECT COUNT(*) AS "__count" FROM "my_table"
優化語句
SELECT reltuples::numeric FROM pg_class WHERE relname = table_name
介紹Django admin 分頁優化
from django.contrib.auth.admin import UserAdmin from django.core.paginator import Paginator, cached_property from django.db import connections class UserAdmin(UserAdmin): paginator = TablePaginator class TablePaginator(Paginator): @cached_property def count(self): return ( self._get_pgsql_estimate_count() if not self.object_list.query.where else super(LargeTablePaginator, self).count ) def _get_pgsql_estimate_count(self): with connections["default"].cursor() as cursor: cursor.execute( "SELECT reltuples::numeric FROM pg_class WHERE relname = %s", [self.object_list.query.model._meta.db_table], ) total_count = int(cursor.fetchone()[0]) return total_count