解释postgres查询,为什么WHERE和LIMIT的查询要长得多

时间:2017-12-06 18:00:15

标签: postgresql database-performance

我使用的是postgres v9.6.5。我有一个看起来并不复杂的查询,并且想知道为什么会如此"慢" (它并不是那么慢,但我实际上并没有很多数据 - 比如几千行。)

以下是查询:

Limit  (cost=0.43..12.84 rows=10 width=148) (actual time=0.062..53.866 rows=4 loops=1)
  ->  Nested Loop  (cost=0.43..4750.03 rows=3826 width=148) (actual time=0.061..53.864 rows=4 loops=1)
        Join Filter: (b1.user_id = u3.id)
        Rows Removed by Join Filter: 67404
        ->  Nested Loop  (cost=0.43..3945.32 rows=17856 width=152) (actual time=0.025..38.457 rows=16852 loops=1)
              ->  Index Scan Backward using orders_pkey on orders o0  (cost=0.29..897.80 rows=17856 width=148) (actual time=0.016..11.558 rows=16852 loops=1)
              ->  Index Scan using balances_pkey on balances b1  (cost=0.14..0.16 rows=1 width=8) (actual time=0.001..0.001 rows=1 loops=16852)
                    Index Cond: (id = o0.balance_id)
        ->  Materialize  (cost=0.00..1.19 rows=3 width=4) (actual time=0.000..0.000 rows=4 loops=16852)
              ->  Seq Scan on users u3  (cost=0.00..1.18 rows=3 width=4) (actual time=0.023..0.030 rows=4 loops=1)
                    Filter: (partner_id = 3)
                    Rows Removed by Filter: 12
Planning time: 0.780 ms
Execution time: 54.053 ms

那个查询计划:

LIMIT

我实际上在没有Sort (cost=874.23..883.80 rows=3826 width=148) (actual time=11.361..11.362 rows=4 loops=1) Sort Key: o0.id DESC Sort Method: quicksort Memory: 26kB -> Hash Join (cost=3.77..646.55 rows=3826 width=148) (actual time=11.300..11.346 rows=4 loops=1) Hash Cond: (o0.balance_id = b1.id) -> Seq Scan on orders o0 (cost=0.00..537.56 rows=17856 width=148) (actual time=0.012..8.464 rows=16852 loops=1) -> Hash (cost=3.55..3.55 rows=18 width=4) (actual time=0.125..0.125 rows=24 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Hash Join (cost=1.21..3.55 rows=18 width=4) (actual time=0.046..0.089 rows=24 loops=1) Hash Cond: (b1.user_id = u3.id) -> Seq Scan on balances b1 (cost=0.00..1.84 rows=84 width=8) (actual time=0.011..0.029 rows=96 loops=1) -> Hash (cost=1.18..1.18 rows=3 width=4) (actual time=0.028..0.028 rows=4 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on users u3 (cost=0.00..1.18 rows=3 width=4) (actual time=0.014..0.021 rows=4 loops=1) Filter: (partner_id = 3) Rows Removed by Filter: 12 Planning time: 0.569 ms Execution time: 11.420 ms 的情况下尝试了,我的计划完全不同:

WHERE

也没有LIMIT(但Limit (cost=0.43..4.74 rows=10 width=148) (actual time=0.023..0.066 rows=10 loops=1) -> Nested Loop (cost=0.43..7696.26 rows=17856 width=148) (actual time=0.022..0.065 rows=10 loops=1) Join Filter: (b1.user_id = u3.id) Rows Removed by Join Filter: 139 -> Nested Loop (cost=0.43..3945.32 rows=17856 width=152) (actual time=0.009..0.029 rows=10 loops=1) -> Index Scan Backward using orders_pkey on orders o0 (cost=0.29..897.80 rows=17856 width=148) (actual time=0.007..0.015 rows=10 loops=1) -> Index Scan using balances_pkey on balances b1 (cost=0.14..0.16 rows=1 width=8) (actual time=0.001..0.001 rows=1 loops=10) Index Cond: (id = o0.balance_id) -> Materialize (cost=0.00..1.21 rows=14 width=4) (actual time=0.001..0.001 rows=15 loops=10) -> Seq Scan on users u3 (cost=0.00..1.14 rows=14 width=4) (actual time=0.005..0.007 rows=16 loops=1) Planning time: 0.286 ms Execution time: 0.097 ms ):

WHERE

如您所见,没有@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View v = findViewById(R.id.buttonlog); v.setOnClickListener((View.OnClickListener) this); } @Override public void onClick(View v) { if(v.getId()==R.id.buttonlog) { Intent intent = new Intent(this,LoginActivity.class); this.startActivity(intent); } }} 它会更快。有人可以向我提供一些信息,我可以在哪里寻找解释这些计划以更好地理解它们吗?而且我还能做些什么来加快这些查询的速度(或者我不应该担心因为100倍的数据仍会足够快? - 50ms对我来说没问题)

1 个答案:

答案 0 :(得分:2)

PostgreSQL认为如果它以正确的顺序扫描orders,它将会最快,直到它找到满足users条件的匹配WHERE条目。

但是,似乎数据分布必须在找到匹配项之前扫描大约17000 orders

由于PostgreSQL不知道值如何在各个表之间建立关联,因此您无法做任何改变。

您可以强制PostgreSQL在没有LIMIT子句的情况下规划查询,如下所示:

SELECT *
FROM (<your query without ORDER BY and LIMIT> OFFSET 0) q
ORDER BY id DESC LIMIT 10;

使用top-N-sort,这应该会更好。