postgresql - 专门为仪表板构建的表有几个过滤器......最好的索引方法?

标签 postgresql

我创建了一个物化 View ,以便输入仪表板。

我的目标是以尽可能最快的方式选择该表,但我不知道如何实现它。我希望如果我描述该表及其使用方式,有人可以提供一些指导。

上下文是一个具有漏斗步骤的网站。每一行都是用户触发漏斗步骤的一个实例,例如添加到购物车、结帐、付款详细信息,最后是交易。

由于该表用于分析目的,因此每天早上只会使用 cron 自动刷新一次,所以我不担心实时更新速度,只需使用各种 where 子句选择速度。

假设我有下面描述的字段:

(N = ~1300 万,预计到 1 月份将达到 ~20,每月增长数百万) 表是唯一的,包含 session ID、用户 ID 和漏斗步骤的组合。

 - Session Id (Id, so some duplication but generally very very granular - Varchar)
 - User Id (Id, so some duplication but generally very very granular - Varchar)
 - Date (Date)
 - Funnel Step (10 distinct value - Varchar)
 - Device Category (3 distinct values - Varchar)
 - Country (~ 100 distinct values - varchar)
 - City (~1000+ distinct values - varchar)
 - Source (several thousand distinct values, nevertheless, stakeholder would like a filter - varchar)

我会单独索引每个字段吗?或者,我应该索引 oneer 中的所有字段吗? Per the documentation ,我想我可以一次索引最多32个字段。但考虑到我的主要目标是选择查询速度而不是其他一切,这样做是否明智?

该表将输入仪表板,仪表板读取该表并将过滤器输入动态转换为 where 子句。每次用户调整过滤器时,都会根据过滤器/where 子句输入读取表并进行分组和聚合。

示例查询:

select 
  event_action,
  count(distinct user_id) as users
from website_data.ecom_funnel
where date >= $input_start_date
and date <= $input_end_date
and device_category in ($mobile, $desktop, $tablet)
and country in ($list of all countries minus any not selected)
and source in ($list of all sources minus any not selected)
group by 1 order by users desc

这将产生一个漏斗形的数据表。

我无法预先聚合,因为关注的主要指标是用户,而不是 session 。必须从基础表中删除这些重复数据。经典示例...假设一个人一周每天访问一个网站一次。那么该周的独立访问者总数为 1,但是如果我按天对访问者进行求和,我会得到 7。与我的表类似,一些用户需要多次 session 才能完成漏斗。因此,这就是为什么我无法预聚合表,因为我需要对基础数据应用过滤器,然后count(distinct user id)

以下是对字段子集的解释(如果有用):

QUERY PLAN
Sort  (cost=862194.66..862194.68 rows=9 width=24)
  Sort Key: (count(DISTINCT client_id)) DESC
  ->  GroupAggregate  (cost=847955.01..862194.51 rows=9 width=24)
        Group Key: event_action
        ->  Sort  (cost=847955.01..852701.48 rows=1898589 width=37)
              Sort Key: event_action
              ->  Seq Scan on ecom_funnel  (cost=0.00..589150.14 rows=1898589 width=37)
                    Filter: ((device_category = ANY ('{mobile,desktop}'::text[])) AND (source = 'google'::text))

我的首要具体问题是,考虑到我的用例,我应该单独索引每个字段还是应该创建一个索引?这有关系吗?

最重要的是,如果有任何关于优化此物化 View 以更快地运行选择查询的提示,我们将不胜感激。

最佳答案

查看您的过滤条件,您应该通过发布来检查 device_category 字段的基数

select device_category, count(*) from website_data.ecom_funnel group by device_category

并查看值以确定索引是否应首先包含此列。这里可能的索引(不知道基数)将是多列,包括:

(device_category, date)

话虽如此,在每个单独的列上创建索引没有任何好处,因为您的查询不会全部使用它们,所以它确实很重要。您会减慢非读取操作的其他 CRUD 操作。

在所有列上创建索引可能也不会让您加快太多速度,但这是基于底层(表中)的数据以及您的过滤器与没有它们的整体查询的比较(被过滤的列中值的基数)。这很可能会产生巨大的开销,需要遍历索引树,然后获取 rowids 以返回所需的数据。

总而言之,我会尝试将索引缩小到在过滤中最重要的列,这意味着它们会删除大部分正在检索的数据。如果您的查询旨在返回表中的大部分行,那么不幸的是,需要进行聚合,因为这不会加快速度。

希望有帮助。


编辑:我刚刚读到您已经发布了表格中不同值的计数。我不确定漏斗步骤在您的表中绑定(bind)到什么,但假设它是一个名为 event_action 的列,那么创建一个索引可能会更有益,该索引也有助于分组:

(date, event_action)

看来您根本省略了 GROUP BY 子句,该子句应该包含在内,并且应该按 event_action 进行分组,因为这就是您的选择部分正在做的事情。

如果每次执行选择查询时将日期范围缩小到几天/几个月,那么使用第一个 date 列创建索引可能会带来巨大的好处。

请记住,索引中列的位置很重要。

如果您查找几个月的值,比如说,您应该预先聚合并将每个月的预先计算值存储在另一个表中,然后将该数据UNION ALL 到当前查询,该查询只会从以下位置选择数据当前(仍在更新)时间。

关于postgresql - 专门为仪表板构建的表有几个过滤器......最好的索引方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59507438/

相关文章:

javascript - 如何根据经纬度计算距离

sql - 每月累计总计和 Postgresql

java - 无法建立 JDBC 连接 [jdbc :postgres://localhost:5432/hibernatedb]

postgresql - 在 Heroku Postgres 上管理独立数据库的可编程方式

windows - Windows 上的 PostgreSQL : is there a default password?

bash - postgres定期自动转储

ruby-on-rails - Hstore 上的 Rails Postgres 查询以避免 SQL 注入(inject)

sql - 如何在 PostgreSQL 中使用条件查询和子查询创建唯一索引?

postgresql - postgres 中带有 psql 的空行。我怎样才能删除它?

postgresql 全文接近度 (`<->` ) 搜索 json 文档