0
votes

I have a postgres table with the following structure:

+---------+-------------+-------------+----------+---------+---------+
|   id    |  timestamp  |   numvalues |  text1   |  text2  |  text3  |
+---------+-------------+-------------+----------+---------+---------+
|abcd12344|    4124135  |[1,2,53,1241]| apple    | banana  | papaya  |
+---------+-------------+-------------+----------+---------+---------+

id - random alphanumeric value<br>
timestamp - epoch timestamp<br>
numvalues - array of integers<br>
text(n) - text values

The table has about 150 million rows.

I make an inner query to get the nth percentile of the data ordered on one of the values in the array. Then, I need to get the averages of several values from the array. The length of the array is around 31.

SELECT AVG(COALESCE(numvalues[2], 0))::NUMERIC(10,0), AVG(COALESCE(numvalues[3], 0))::NUMERIC(10,0)...AVG(COALESCE(numvalues[12], 0))::NUMERIC(10,0) 
FROM (SELECT timestamp, numvalues, ntile(100) 
      OVER (ORDER BY numvalues[1]) pval FROM tablename WHERE timestamp >= somevalue and timestamp <= somevalue) innertable 
WHERE pval >= x and pval <= y;

This returns about 7 million rows out of 150 million which is about 5% of the table. However, it does not use the index. Running an EXPLAIN ANALYZE shows that it uses a Seq Scan instead, even when enable_seqscan is set to off.

However, a similar query :

SELECT text1, count(distinct(id))
FROM (SELECT timestamp, id, text1, numvalues, ntile(100) 
      OVER (ORDER BY numvalues[1]) pval FROM tablename WHERE timestamp >= somevalue and timestamp <= somevalue) innertable 
WHERE pval >= x and pval <= y GROUP BY text1;

does use the index.

The index is on the timestamp column

The results of EXPLAIN ANALYZE:

explain analyze select text1, count(distinct(id)) 
    from (select timestamp, text1, numvalues, id, ntile(100) over (order by numvalues[1]) pval from table where timestamp >= 1431100800 and timestamp <= 1431108000 and numvalues[1] NOTNULL) innertable 
    where pval >= 90 and pval <= 90 group by text1;

                                  QUERY PLAN

--------------------------------------------------------------------------------
GroupAggregate  (cost=4554118.06..4554641.66 rows=1 width=28) (actual time=218641.221..219051.984 rows=20 loops=1)
   ->  Sort  (cost=4554118.06..4554292.59 rows=69812 width=28) (actual time=218640.546..218728.294 rows=71441 loops=1)
         Sort Key: innertable.text1
         Sort Method: quicksort  Memory: 8654kB
         ->  Subquery Scan on innertable  (cost=4094722.75..4548501.27 rows=69812 width=28) (actual time=216502.946..218521.666 rows=71441 loops=1)
           Filter: ((innertable.pval >= 90) AND (innertable.pval <= 90))
           Rows Removed by Filter: 7072674
           ->  WindowAgg  (cost=4094722.75..4339065.03 rows=13962416 width=118) (actual time=202276.333..211374.235 rows=7144115 loops=1)
                 ->  Sort  (cost=4094722.75..4129628.79 rows=13962416 width=118) (actual time=164912.487..190272.316 rows=7144115 loops=1)
                       Sort Key: (table.numvalues[9])
                       Sort Method: external merge  Disk: 1387704kB
                       ->  Index Scan using table_time_idx on table  (cost=0.57..1578710.87 rows=13962416 width=118) (actual time=0.124..141014.505 rows=7144115 loops=1)
                             Index Cond: (("timestamp" >= 1431100800) AND ("timestamp" <= 1431108000))
                             Filter: (numvalues[1] IS NOT NULL)
                             Rows Removed by Filter: 7090075
 Total runtime: 219340.709 ms
(16 rows)



explain analyze select avg(coalesce(numvalues[9], 0))::NUMERIC(10,0) mean9, avg(coalesce(numvalues[30],0))::NUMERIC(10,0),  avg(coalesce(numvalues[8],0))::NUMERIC(10,0) - avg(coalesce(numvalues[30], 0))::NUMERIC(10,0) mean0, avg(coalesce(numvalues[10],0))::NUMERIC(10,0) - avg(coalesce(numvalues[8], 0))::NUMERIC(10,0) mean1, avg(coalesce(numvalues[14],0))::NUMERIC(10,0) - avg(coalesce(numvalues[10], 0))::NUMERIC(10,0) mean2, avg(coalesce(numvalues[13],0))::NUMERIC(10,0) - avg(coalesce(numvalues[14], 0))::NUMERIC(10,0) mean3, avg(coalesce(numvalues[9],0))::NUMERIC(10,0) - avg(coalesce(numvalues[13], 0))::NUMERIC(10,0) mean4 
    from (select timestamp, id, numvalues, ntile(100) over (order by numvalues[1] ) pval from table where timestamp >= 1431093600.00 and timestamp <= 1431100800.00 and numvalues[9] NOTNULL) innerTable 
    where pval >= 90.00 and pval <= 90.00 ;

QUERY PLAN                                                                        
--------------------------------------------------------------------------------
 Aggregate  (cost=12662077.32..12662077.37 rows=1 width=82) (actual time=650343.769..650343.770 rows=1 loops=1)
   ->  Subquery Scan on innertable  (cost=12634854.54..12661968.84 rows=3615 width=82) (actual time=647745.962..650232.725 rows=71441 loops=1)
         Filter: (((innertable.pval)::numeric >= 90.00) AND ((innertable.pval)::numeric <= 90.00))
         Rows Removed by Filter: 7072674
          ->  WindowAgg  (cost=12634854.54..12647507.88 rows=723048 width=248) (actual time=632388.293..642338.237 rows=7144115 loops=1)
           ->  Sort  (cost=12634854.54..12636662.16 rows=723048 width=248) (actual time=599893.771..617413.102 rows=7144115 loops=1)
                 Sort Key: (table.numvalues[9])
                 Sort Method: external merge  Disk: 3214248kB
                 ->  Seq Scan on req_p0swajch2t  (cost=0.00..12480460.48 rows=723048 width=248) (actual time=0.041..575423.062 rows=7144115 loops=1)
                       Filter: ((numvalues[1] IS NOT NULL) AND (("timestamp")::numeric >= 1431100800.00) AND (("timestamp")::numeric <= 1431108000.00))
                       Rows Removed by Filter: 138191935
Total runtime: 650785.126 ms
(12 rows)

Can anyone help me out with why Postgres would use an index for one query and not the other? Running a VACUUM ANALYZE didn't help either.

Is there any way to speed up the queries? A query over the whole table would take about 20 - 30 minutes! Partitioning didn't make much difference since queries span multiple partitions and it showed an improvement of only about a couple of minutes when the number of partitions spanned became larger.I have a postgres table with the following structure:

+---------+-------------+-------------+----------+---------+---------+
|   id    |  timestamp  |   numvalues |  text1   |  text2  |  text3  |
+---------+-------------+-------------+----------+---------+---------+
|abcd12344|    4124135  |[1,2,53,1241]| apple    | banana  | papaya  |
+---------+-------------+-------------+----------+---------+---------+

id - random alphanumeric value<br>
timestamp - epoch timestamp<br>
numvalues - array of integers<br>
text(n) - text values

The table has about 150 million rows.

I make an inner query to get the nth percentile of the data ordered on one of the values in the array. Then, I need to get the averages of several values from the array. The length of the array is around 31.

SELECT AVG(COALESCE(numvalues[2], 0))::NUMERIC(10,0), AVG(COALESCE(numvalues[3], 0))::NUMERIC(10,0)...AVG(COALESCE(numvalues[12], 0))::NUMERIC(10,0) 
FROM (SELECT timestamp, numvalues, ntile(100) 
      OVER (ORDER BY numvalues[1]) pval FROM tablename WHERE timestamp >= somevalue and timestamp <= somevalue) innertable 
WHERE pval >= x and pval <= y;

This returns about 7 million rows out of 150 million which is about 5% of the table. However, it does not use the index. Running an EXPLAIN ANALYZE shows that it uses a Seq Scan instead, even when enable_seqscan is set to off.

However, a similar query :

SELECT text1, count(distinct(id))
FROM (SELECT timestamp, id, text1, numvalues, ntile(100) 
      OVER (ORDER BY numvalues[1]) pval FROM tablename WHERE timestamp >= somevalue and timestamp <= somevalue) innertable 
WHERE pval >= x and pval <= y GROUP BY text1;

does use the index.

The index is on the timestamp column

The results of EXPLAIN ANALYZE:

explain analyze select text1, count(distinct(id)) 
    from (select timestamp, text1, numvalues, id, ntile(100) over (order by numvalues[1]) pval from table where timestamp >= 1431100800 and timestamp <= 1431108000 and numvalues[1] NOTNULL) innertable 
    where pval >= 90 and pval <= 90 group by text1;

                                  QUERY PLAN

--------------------------------------------------------------------------------
GroupAggregate  (cost=4554118.06..4554641.66 rows=1 width=28) (actual time=218641.221..219051.984 rows=20 loops=1)
   ->  Sort  (cost=4554118.06..4554292.59 rows=69812 width=28) (actual time=218640.546..218728.294 rows=71441 loops=1)
         Sort Key: innertable.text1
         Sort Method: quicksort  Memory: 8654kB
         ->  Subquery Scan on innertable  (cost=4094722.75..4548501.27 rows=69812 width=28) (actual time=216502.946..218521.666 rows=71441 loops=1)
           Filter: ((innertable.pval >= 90) AND (innertable.pval <= 90))
           Rows Removed by Filter: 7072674
           ->  WindowAgg  (cost=4094722.75..4339065.03 rows=13962416 width=118) (actual time=202276.333..211374.235 rows=7144115 loops=1)
                 ->  Sort  (cost=4094722.75..4129628.79 rows=13962416 width=118) (actual time=164912.487..190272.316 rows=7144115 loops=1)
                       Sort Key: (table.numvalues[9])
                       Sort Method: external merge  Disk: 1387704kB
                       ->  Index Scan using table_time_idx on table  (cost=0.57..1578710.87 rows=13962416 width=118) (actual time=0.124..141014.505 rows=7144115 loops=1)
                             Index Cond: (("timestamp" >= 1431100800) AND ("timestamp" <= 1431108000))
                             Filter: (numvalues[1] IS NOT NULL)
                             Rows Removed by Filter: 7090075
 Total runtime: 219340.709 ms
(16 rows)



explain analyze select avg(coalesce(numvalues[9], 0))::NUMERIC(10,0) mean9, avg(coalesce(numvalues[30],0))::NUMERIC(10,0),  avg(coalesce(numvalues[8],0))::NUMERIC(10,0) - avg(coalesce(numvalues[30], 0))::NUMERIC(10,0) mean0, avg(coalesce(numvalues[10],0))::NUMERIC(10,0) - avg(coalesce(numvalues[8], 0))::NUMERIC(10,0) mean1, avg(coalesce(numvalues[14],0))::NUMERIC(10,0) - avg(coalesce(numvalues[10], 0))::NUMERIC(10,0) mean2, avg(coalesce(numvalues[13],0))::NUMERIC(10,0) - avg(coalesce(numvalues[14], 0))::NUMERIC(10,0) mean3, avg(coalesce(numvalues[9],0))::NUMERIC(10,0) - avg(coalesce(numvalues[13], 0))::NUMERIC(10,0) mean4 
    from (select timestamp, id, numvalues, ntile(100) over (order by numvalues[1] ) pval from table where timestamp >= 1431093600.00 and timestamp <= 1431100800.00 and numvalues[9] NOTNULL) innerTable 
    where pval >= 90.00 and pval <= 90.00 ;

QUERY PLAN                                                                        
--------------------------------------------------------------------------------
 Aggregate  (cost=12662077.32..12662077.37 rows=1 width=82) (actual time=650343.769..650343.770 rows=1 loops=1)
   ->  Subquery Scan on innertable  (cost=12634854.54..12661968.84 rows=3615 width=82) (actual time=647745.962..650232.725 rows=71441 loops=1)
         Filter: (((innertable.pval)::numeric >= 90.00) AND ((innertable.pval)::numeric <= 90.00))
         Rows Removed by Filter: 7072674
          ->  WindowAgg  (cost=12634854.54..12647507.88 rows=723048 width=248) (actual time=632388.293..642338.237 rows=7144115 loops=1)
           ->  Sort  (cost=12634854.54..12636662.16 rows=723048 width=248) (actual time=599893.771..617413.102 rows=7144115 loops=1)
                 Sort Key: (table.numvalues[9])
                 Sort Method: external merge  Disk: 3214248kB
                 ->  Seq Scan on req_p0swajch2t  (cost=0.00..12480460.48 rows=723048 width=248) (actual time=0.041..575423.062 rows=7144115 loops=1)
                       Filter: ((numvalues[1] IS NOT NULL) AND (("timestamp")::numeric >= 1431100800.00) AND (("timestamp")::numeric <= 1431108000.00))
                       Rows Removed by Filter: 138191935
Total runtime: 650785.126 ms
(12 rows)

Can anyone help me out with why Postgres would use an index for one query and not the other? Running a VACUUM ANALYZE didn't help either.

Is there any way to speed up the queries? A query over the whole table would take about 20 - 30 minutes! Partitioning didn't make much difference since queries span multiple partitions and it showed an improvement of only about a couple of minutes when the number of partitions spanned became larger.

1
why timestamp is cast to numeric in query with seq scan? it can be an issueAdamSkywalker
Why do you select the timestamp in the subquery when you don't use it in the outer query?Frank Heikens
@FrankHeikens - Yes, you're right, I don't need to select timestamp. Thanks, I'll remove thatSanjanaS801

1 Answers

3
votes

I guess you can't reply in comments so I have to post an answer.

Explain analyze showed, that your timestamp columns are compared with numeric values timestamp >= 1431093600.00 and timestamp <= 1431100800.00 and because of that they were cast to numeric:

Filter: ((numvalues[1] IS NOT NULL) AND (("timestamp")::numeric >= 1431100800.00) AND (("timestamp")::numeric <= 1431108000.00))

Investigate why that happened and try to fix it.