表现不佳的postgres sql

时间:2016-04-22 14:30:06

标签: sql postgresql postgresql-9.3 rails-postgresql postgresql-performance

这是我的sql,然后是解释。我需要提高性能。有什么想法吗?

PostgreSQL 9.3.12 on x86_64-unknown-linux-gnu,由gcc编译(Ubuntu 4.8.4-2ubuntu1~14.04.1)4.8.4,64位

explain analyze
SELECT  DISTINCT "apts"."id", practices.name AS alias_0 
FROM "apts" 
LEFT OUTER JOIN "patients" ON "patients"."id" = "apts"."patient_id" 
LEFT OUTER JOIN "practices" ON "practices"."id" = "apts"."practice_id" 
LEFT OUTER JOIN "eligibility_messages" ON "eligibility_messages"."apt_id" = "apts"."id" 
WHERE (apts.eligibility_status_id != 1) 
AND (eligibility_messages.current = 't') 
AND (practices.id = '104')  
ORDER BY practices.name desc 
LIMIT 25 OFFSET 0


Limit  (cost=881321.34..881321.41 rows=25 width=20) (actual time=2928.225..2928.227 rows=25 loops=1)
->  Sort  (cost=881321.34..881391.94 rows=28240 width=20) (actual time=2928.223..2928.224 rows=25 loops=1)
Sort Key: practices.name
Sort Method: top-N heapsort  Memory: 26kB
->  HashAggregate  (cost=880242.03..880524.43 rows=28240 width=20) (actual time=2927.213..2927.319 rows=520 loops=1)
->  Nested Loop  (cost=286614.55..880100.83 rows=28240 width=20) (actual time=206.180..2926.791 rows=520 loops=1)
->  Seq Scan on practices  (cost=0.00..6.36 rows=1 width=20) (actual time=0.018..0.031 rows=1 loops=1)
Filter: (id = 104)
Rows Removed by Filter: 108
->  Hash Join  (cost=286614.55..879812.07 rows=28240 width=8) (actual time=206.159..2926.643 rows=520 loops=1)
Hash Cond: (eligibility_messages.apt_id = apts.id)
->  Seq Scan on eligibility_messages  (cost=0.00..561275.63 rows=2029532 width=4) (actual time=0.691..2766.867 rows=67559 loops=1)
Filter: current
Rows Removed by Filter: 3924633
->  Hash  (cost=284614.02..284614.02 rows=115082 width=12) (actual time=121.957..121.957 rows=91660 loops=1)
Buckets: 16384  Batches: 2  Memory Usage: 1974kB
->  Bitmap Heap Scan on apts  (cost=8296.88..284614.02 rows=115082 width=12) (actual time=19.927..91.038 rows=91660 loops=1)
Recheck Cond: (practice_id = 104)
Filter: (eligibility_status_id <> 1)
Rows Removed by Filter: 80169
->  Bitmap Index Scan on index_apts_on_practice_id  (cost=0.00..8268.11 rows=177540 width=0) (actual time=16.856..16.856 rows=179506 loops=1)
Index Cond: (practice_id = 104)
Total runtime: 2928.361 ms

1 个答案:

答案 0 :(得分:3)

首先,将查询重写为更易于管理的形式:

SELECT DISTINCT a."id", pr.name AS alias_0 
FROM "apts" a JOIN
     "practices" pr
     ON pr."id" = a."practice_id" JOIN
     "eligibility_messages" em
     ON em."apt_id" = a."id" 
WHERE (a.eligibility_status_id <> 1) AND
      (em.current = 't') AND
      (a.practice_id = 104)  
ORDER BY pr.name desc ;

注意:

  • WHERE子句无论如何都会将外连接转换为内连接,所以你也可以正确地表达它们。
  • 我怀疑pr.id实际上是一个字符串
  • patients表格未被使用,所以我只是将其删除了。
  • 也许你甚至不再需要select distinct
  • where中的条件转换为apts而不是practices

如果这还不够快,您需要索引,可能在apts(practice_id, eligibility_status_id, id)practices(id)eligibility_messages(apt_id, current)上。