如何在PostgreSQL中加速查询
我在PostgreSQL中有一个带有大数据的数据库(现在大约是46GB,数据库将继续增长)。我在常用列上创建了索引,并修改了配置文件:如何在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
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 <> '';