2013-06-24 54 views
0

我們有3張桌子。Postgresql慢速查詢。更改查詢或posgresql.conf?

10,000行中之一,並在第二行80000和400行中的第三個。

守則運作良好,但最近我們遇到的性能問題。

EXPLAIN ANALYZE SELECT "users_users"."id", "users_users"."email" 
FROM "users_users" WHERE (NOT ("users_users"."email" IN 
    (SELECT U0."email" FROM "users_blacklist" U0)) 
    AND NOT ("users_users"."id" IN (SELECT U0."user_id" 
FROM "games_user2game" U0))) ORDER BY "users_users"."id" DESC; 
                     QUERY PLAN                   
--------------------------------------------------------------------------------------------------------------------------------------------------------- 
Index Scan Backward using users_user_pkey on users_users (cost=9.25..12534132.45 rows=2558 width=26) (actual time=46.101..77158.318 rows=2510 loops=1) 
    Filter: ((NOT (hashed SubPlan 1)) AND (NOT (SubPlan 2))) 
    Rows Removed by Filter: 7723 
    SubPlan 1 
    -> Seq Scan on users_blacklist u0 (cost=0.00..8.20 rows=420 width=22) (actual time=0.032..0.318 rows=420 loops=1) 
    SubPlan 2 
    -> Materialize (cost=0.00..2256.20 rows=77213 width=4) (actual time=0.003..4.042 rows=35774 loops=9946) 
      -> Seq Scan on games_user2game u0 (cost=0.00..1568.13 rows=77213 width=4) (actual time=0.011..17.159 rows=77213 loops=1) 
Total runtime: 77159.689 ms 
(9 rows) 

主要問題:是否確定,我們滿足少於100,000行加入2代表的性能問題?

哪裏挖?我們應該改變查詢還是挖掘數據庫設置?

UPD臨時解決方案是通過在代碼中預取子查詢來擺脫子查詢。

+2

如果我沒有記錯,改變你的查詢中使用'Exists'而不是'in'可以提高性能 – Scotch

+0

哪些指標上'users_users'表中定義? –

+0

@a_horse_with_no_name,索引是在查詢中播放的所有字段上定義的。 users_users在電子郵件和ID上有索引。 –

回答

1

我不知道SQL的Postgres的dialet但它可能是值得與外連接嘗試。在許多其他dbms中,它們可以提供比次選更好的性能。

東西沿着

SELECT "users_users"."id", "users_users"."email" 
FROM "users_users" us left join "users_blacklist" uo on uo.email = us.email 
         left join "games_user2game" ug on us.id = ug.user_id 
where uo.email is null 
AND ug.id is null 

行我認爲正在做同樣的事情,你的原始查詢,但你必須進行測試,以確保。

1

我也遇到類似問題,SQL Server上運行,並改寫與存在,如@Scotch表明,效果良好查詢。

SELECT 
    "users_users"."id", 
    "users_users"."email" 
FROM "users_users" 
WHERE 
NOT EXISTS 
(
    SELECT NULL FROM "users_blacklist" WHERE "users_blacklist"."email" = "users_users"."email" 
) 
AND NOT EXISTS 
(
    SELECT NULL FROM "games_user2game" WHERE "games_user2game"."user_id" = "users_users"."user_id" 
) 
ORDER BY "users_users"."id" DESC; 

該查詢會給你們誰也列入黑名單的所有用戶,誰在比賽中都沒有。它可能比外部連接選項更快,這取決於postgres如何計劃查詢。

+0

謝謝。看起來我們就必須按照ORM生成的查詢的提升空間,80,000行是不是導致尺度問題呢。 –

+0

如果導致完全相同的執行計劃,我也不會感到驚訝。 Postgres查詢優化器非常聰明 –

+0

@a_horse_with_no_name NOT IN和NOT EXISTS不相等 - 在9.x行中Postgres能夠對NOT EXISTS使用更好的優化(抗連接)。 –