随着用户数量的增加,我的Django网站开始运行缓慢。 New Relic告诉我,持续时间最长的查询是用户查询查询:
SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" LEFT OUTER JOIN "account_emailaddress" ON ("auth_user"."id" = "account_emailaddress"."user_id") WHERE (UPPER("auth_user"."email"::text) = UPPER(%s) OR UPPER("account_emailaddress"."email"::text) = UPPER(%s) )
我已创建索引以希望加快上述查询:
CREATE INDEX auth_user_email_upper ON auth_user (UPPER(email));
CREATE INDEX account_emailaddress_email_upper ON account_emailaddress (UPPER(email));
不幸的是,运行与SELECT
相同的EXPLAIN SELECT
查询表明Postgres没有使用我刚刚创建的索引:
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------
Merge Left Join (cost=0.35..17926.55 rows=2039 width=83)
Merge Cond: (auth_user.id = account_emailaddress.user_id)
Filter: ((upper((auth_user.email)::text) = '%s'::text) OR (upper((account_emailaddress.email)::text) = '%s'::text))
-> Index Scan using auth_user_pkey on auth_user (cost=0.08..12637.91 rows=406463 width=83)
-> Index Scan using account_emailaddress_user_id on account_emailaddresss (cost=0.08..3868.99 rows=221167 width=26)
(5 rows)
我发现如果原始查询中没有OR
条件,并且只有1 WHERE
子句,则会使用索引。但是,使用这两个子句时,使用的索引支持JOIN
而不是扫描。
我可以采取哪些措施来优化此查询吗?
编辑:根据要求,以下是EXPLAIN ANALYZE
的输出:
EXPLAIN ANALYZE SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" LEFT OUTER JOIN "account_emailaddress" ON ("auth_user"."id" = "account_emailaddress"."user_id") WHERE (UPPER("auth_user"."email"::text) = UPPER('REPLACED_EMAIL') OR UPPER("account_emailaddress"."email"::text) = UPPER('REPLACED_EMAIL') );
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Merge Left Join (cost=0.26..18096.69 rows=2032 width=81) (actual time=22986.017..22986.017 rows=0 loops=1)
Merge Cond: (http://auth_user.id = account_emailaddress.user_id)
Filter: ((upper((auth_user.email)::text) = 'REPLACED_EMAIL'::text) OR (upper((account_emailaddress.email)::text) = 'REPLACED_EMAIL'::text))
Rows Removed by Filter: 402817
-> Index Scan using auth_user_pkey on auth_user (cost=0.08..12808.70 rows=405161 width=81) (actual time=0.017..6235.838 rows=402817 loops=1)
-> Index Scan using account_emailaddress_user_id on account_emailaddress (cost=0.08..3868.99 rows=221167 width=26) (actual time=0.009..4034.638 rows=221189 loops=1)
Total runtime: 22997.255 ms
(7 rows)
编辑2:版本为:
PostgreSQL 9.3.2 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit