如何在PostgreSQL中加速查询

如何在PostgreSQL中加速查询,sql,windows,postgresql,postgresql-performance,Sql,Windows,Postgresql,Postgresql Performance,我在PostgreSQL中有一个带有大数据的数据库(现在大约是46GB,数据库将继续增长)。我在常用列上创建了索引,并修改了配置文件: shared_buffers = 1GB temp_buffers = 256MB work_mem = 512MB 但这个查询仍然很慢: select distinct us_category_id as cat, count(h_user_id) as res from web_hits inner join users on h_user_id = u

我在PostgreSQL中有一个带有大数据的数据库(现在大约是46GB,数据库将继续增长)。我在常用列上创建了索引,并修改了配置文件:

shared_buffers = 1GB
temp_buffers = 256MB
work_mem = 512MB
但这个查询仍然很慢:

select distinct us_category_id as cat, count(h_user_id) as res from web_hits 
inner join users on h_user_id = us_id 
where (h_datetime)::date = ('2015-06-26')::date and us_category_id != ''
group by us_category_id
解释和分析:


首先,不需要区分:

select u.us_category_id as cat, count(h_user_id) as res
from web_hits h inner join
     users u
     on h.h_user_id = u.us_id 
where (h.h_datetime)::date = '2015-06-26'::date and
      u.us_category_id <> ''
group by u.us_category_id
选择u.us\u类别\u id作为cat,计数(h\u用户\u id)作为res
从web_点击h内部连接
用户u
在h.h_用户_id=u.us_id上
其中(h.h_datetime)::日期='2015-06-26'::日期和
u、 美国类别识别码“
按u.us\u类别\u id分组
其次,要删除列上的转换。因此:

select u.us_category_id as cat, count(h_user_id) as res
from web_hits h inner join
     users u
     on h.h_user_id = u.us_id 
where (h.h_datetime >= '2015-06-26' and h.h_datetime < '2015-06-27) and
      u.us_category_id <> ''
group by u.us_category_id;
选择u.us\u类别\u id作为cat,计数(h\u用户\u id)作为res
从web_点击h内部连接
用户u
在h.h_用户_id=u.us_id上
其中(h.h_datetime>='2015-06-26'和h.h_datetime<'2015-06-27)和
u、 美国类别识别码“
按u.us\u类别\u id分组;

然后,以下索引应该有助于查询:
web\u hits(h\u datetime,h\u user\u id)
。在
用户(us\u id,us\u category\u id)上建立索引也可能是有益的。

首先,不需要使用不同的索引:

select u.us_category_id as cat, count(h_user_id) as res
from web_hits h inner join
     users u
     on h.h_user_id = u.us_id 
where (h.h_datetime)::date = '2015-06-26'::date and
      u.us_category_id <> ''
group by u.us_category_id
选择u.us\u类别\u id作为cat,计数(h\u用户\u id)作为res
从web_点击h内部连接
用户u
在h.h_用户_id=u.us_id上
其中(h.h_datetime)::日期='2015-06-26'::日期和
u、 美国类别识别码“
按u.us\u类别\u id分组
其次,要删除列上的转换。因此:

select u.us_category_id as cat, count(h_user_id) as res
from web_hits h inner join
     users u
     on h.h_user_id = u.us_id 
where (h.h_datetime >= '2015-06-26' and h.h_datetime < '2015-06-27) and
      u.us_category_id <> ''
group by u.us_category_id;
选择u.us\u类别\u id作为cat,计数(h\u用户\u id)作为res
从web_点击h内部连接
用户u
在h.h_用户_id=u.us_id上
其中(h.h_datetime>='2015-06-26'和h.h_datetime<'2015-06-27)和
u、 美国类别识别码“
按u.us\u类别\u id分组;

然后,以下索引应该有助于查询:
web\u hits(h\u datetime,h\u user\u id)
。在
用户(us\u id,us\u category\u id)上建立索引也可能是有益的。

问题中缺少基本信息。我的部分答案是基于有根据的猜测。
web\u hits.h\u user\u id
有时为空,就像您在评论中添加的那样

查询 基本上,查询在任何情况下都可以简化/改进为:

SELECT u.us_category_id AS cat, count(*) AS res
FROM   users    u
JOIN   web_hits w ON w.h_user_id = u.us_id
WHERE  w.h_datetime >= '2015-06-26 0:0'::timestamp
AND    w.h_datetime <  '2015-06-27 0:0'::timestamp
AND    w.h_user_id IS NOT NULL  -- remove irrelevant rows, match index
AND    u.us_category_id <> ''
GROUP  BY 1;
索引 无论哪种方式,都最适合您的情况:

一,

从索引中删除
web\u hits.h\u user\u id为NULL的行

按该顺序排列,而不是建议按相反的顺序排列。详细说明:

二,

在用户(us\U id)上创建索引us\U usid\U cat\U not\U empty\U idx
其中us_类别_id“”;
这将大大减少,因为我们不在索引中存储可能很长的
varchar
us\u category\u id
——我们无论如何都不需要这样做。我们只需要知道它是
。如果您有
integer
列,则此考虑不适用

我们还排除了
us\u category\u id
中带有
'
NULL
的行,这使得索引更小,但也更安全

您必须权衡特殊索引的维护成本和它们的好处。如果您经常运行带有匹配条件的查询,它会有回报,否则可能不会,总体而言,更通用的索引可能会更好


当然,所有关于这个问题的常规建议也适用


坦率地说,您的查询不太正确,而且您的设置中有许多项目是可疑的。处理像你明显的大桌子,你可以考虑专业帮助。

基本信息在这个问题中丢失了。我的部分答案是基于有根据的猜测。

web\u hits.h\u user\u id
有时为空,就像您在评论中添加的那样

查询 基本上,查询在任何情况下都可以简化/改进为:

SELECT u.us_category_id AS cat, count(*) AS res
FROM   users    u
JOIN   web_hits w ON w.h_user_id = u.us_id
WHERE  w.h_datetime >= '2015-06-26 0:0'::timestamp
AND    w.h_datetime <  '2015-06-27 0:0'::timestamp
AND    w.h_user_id IS NOT NULL  -- remove irrelevant rows, match index
AND    u.us_category_id <> ''
GROUP  BY 1;
索引 无论哪种方式,都最适合您的情况:

一,

从索引中删除
web\u hits.h\u user\u id为NULL的行

按该顺序排列,而不是建议按相反的顺序排列。详细说明:

二,

在用户(us\U id)上创建索引us\U usid\U cat\U not\U empty\U idx
其中us_类别_id“”;
这将大大减少,因为我们不在索引中存储可能很长的
varchar
us\u category\u id
——我们无论如何都不需要这样做。我们只需要知道它是
。如果您有
integer
列,则此考虑不适用

我们还排除了
us\u category\u id
中带有
'
NULL
的行,这使得索引更小,但也更安全

您必须权衡特殊索引的维护成本和它们的好处。如果您经常运行带有匹配条件的查询,它会有回报,否则可能不会,总体而言,更通用的索引可能会更好


当然,所有关于这个问题的常规建议也适用


坦率地说,您的查询不太正确,而且您的设置中有许多项目是可疑的。像你这样处理巨大的表格,你可以考虑专业的帮助。

只是一个注释,你可以去掉独立的关键字,因为结果已经被你的组所区分。请张贴表格和索引定义。你能详细说明已经到位的索引吗?这两个表看起来都是通过seq scan访问的。我从您的设置中删除了噪音(默认设置)。另一方面,重要信息缺失。考虑标签信息中的指令。为什么一个表属于
postgres
,而另一个表属于
sveta
?您对多个ID列使用字符数据类型而不是普通的
integer
(或
bigint
)的任何特定原因?以及为什么
web\u hits.h\u user\u ID
未定义
非空
?列中是否有空值?如果是,您打算如何计算?看起来应该有来自
we的FK约束
CREATE INDEX wh_usid_datetime_idx ON web_hits(h_user_id, h_datetime)
WHERE  h_user_id IS NOT NULL;
CREATE INDEX us_usid_cat_not_empty_idx ON users(us_id)
WHERE  us_category_id <> '';