PostgreSQL具有全局和分区排名的物化视图

时间:2015-07-03 16:02:54

标签: postgresql query-performance window-functions materialized-views

我有一张10密耳的桌子。用户评分。 我需要创建具有全局评级和按国家/地区评级的物化视图,并且每天刷新一次。

我提出了以下选择查询:

SELECT row_number() OVER(ORDER BY value DESC, id) AS rank_global, 
       row_number() OVER(PARTITION BY country ORDER BY value DESC, id) AS rank_country,
       * 
FROM rate 
ORDER BY value DESC, id
LIMIT 100000

有没有办法加快这个查询,或者有另一种方法可以做同样的事情?我创建了btree(值desc,id)和(country,value desc,id)索引,但仍需要很长时间才能完成。

示例:

创建一个表并使用具有随机值列和随机国家/地区的用户填充该表:

CREATE TABLE rate
(
  id serial NOT NULL,
  name text,
  value integer NOT NULL DEFAULT 0,
  country character varying,
  CONSTRAINT rate_pkey PRIMARY KEY (id)
);

INSERT INTO rate 
(SELECT n, ('user_'||n), (random()*30)::int, ('country_'||(random()*3)::int) 
FROM generate_series(0,10) AS n);

CREATE INDEX rate_country_value_id_index
ON rate
USING btree(country, value DESC, id);

CREATE INDEX rate_value_id_index
ON rate
USING btree(value DESC, id);

表格内容:

id  name  value  country
0  user_0   28  country_2
1  user_1   24  country_2
2  user_2   29  country_1
3  user_3   11  country_1
4  user_4   16  country_1
5  user_5   28  country_0
6  user_6   3   country_1
7  user_7   7   country_1
8  user_8   28  country_1
9  user_9   4   country_0
10 user_10  29  country_1

然后我创建物化视图:

CREATE MATERIALIZED VIEW rate_view AS 
SELECT row_number() OVER (ORDER BY value DESC, id) AS rgl, 
       row_number() OVER (PARTITION BY country ORDER BY value DESC, id) AS rc,
       * 
FROM rate 
ORDER BY value DESC, id;

查看内容(rgl - 全球排名,rc - 按国家/地区排名):

rgl rc id   name  value  country
1   1  2   user_2   29  country_1
2   2  10  user_10  29  country_1
3   1  5   user_5   28  country_0
4   1  0   user_0   28  country_2
5   3  8   user_8   28  country_1
6   2  1   user_1   24  country_2
7   4  4   user_4   16  country_1
8   5  3   user_3   11  country_1
9   6  7   user_7   7   country_1
10  2  9   user_9   4   country_0
11  7  6   user_6   3   country_1

现在我可以创建复杂的查询来选择排名最接近的用户及其邻居的排名。全球和国家。

例如,(在视图上创建(value,id)和(rgl)索引之后)这里是全球前50名和最近排名为5999942的用户:

(
  WITH closest_rank AS
  ( 
    SELECT rgl FROM rate_view 
    WHERE value <= 9999942 
    ORDER BY value DESC, id ASC 
    LIMIT 1 
  )
  SELECT rgl, name, value 
  FROM rate_view 
  WHERE rgl > (SELECT rgl-3 FROM closest_rank ) 
  ORDER BY rgl ASC 
  LIMIT 5
)
UNION
SELECT rgl, name, value 
FROM rate_view 
WHERE rgl <=50 
ORDER BY rgl;

0 个答案:

没有答案