用于地理点范围和数值范围查询的复合多列索引
Composite multicolumn index for geopoint range and numeric range query
我正在构建一个应用程序,其中服务器需要 select 行基于一些 criteria/filters。其中之一是用户的位置和用户希望查看帖子的半径和其他过滤器,例如日期范围和过滤另一列的值。这将用于临时事件发现应用程序。
我读过有关 PostGIS 的文章,我知道有一个 point
数据类型。基于 this 的回答,我明白最好从相等到范围列排序,尽管我觉得地理点列应该是第一个。但主要问题是,如何创建这样的索引?我考虑过 GiST 索引,但不确定是否有帮助。
假设以下简化事件table(忽略有效位置数据):
id event_title event_position event_type is_public start_date
(varchar) (point lat/lon) (smallint) (boolean) (timestamptz)
-- --------------------------- --------------- --------- --------- ----
1 "John's Party" (122,35) 0 0 2020-07-05
2 "Revolution then Starbucks" (123,30) 1 1 2020-07-06
3 "Study for math exam" (120,36) 2 1 2020-07-07
4 "Party after exam" (120,36) 1 1 2020-07-08
5 "Hiking next to the city" (95,40) 3 1 2020-07-09
6 "Football match" (-42,31) 4 1 2020-07-10
因此,在此 table 中,用户将能够查询 public 接近 (122,34) 100 公里的事件(假设前三行落入此区域)且事件类型为 0 , 1 或 2 个落在日期 2020-07-05 和 2020-07-07 之间。用户将获得 ID 为 2 和 3 的行。
这是我要使用适当索引优化的查询。谢谢!
在 btree_gist extension 的帮助下,您可以将 event_type 和 start_date 列与 event_position 一起包含到 GiST 索引中。但是,只要限制子句类似于 event_type in (0, 1, 2)
,event_type 在索引中就不会很有用。 (但如果列表只包含一个元素,它将被重写为一个等式,在这种情况下它可以有效地使用索引中的该列。)所以使用其他两列将是我的起点。我会把通常更有选择性的放在第一位。如果您打算将过去的事件留在 table 而不是清除它们,那么日期可能最终会成为更具选择性的日期。
如果位置条件不是很挑剔(例如,您的大部分活动都在纽约市,您的大部分用户都在纽约市,几乎所有地方都在 100 公里以内),那么您可能想要一种不同的方法。只需在 (event_type, start_date)
上创建一个默认的 BTREE 索引。与 GiST 不同,这样的 BTREE 可以有效地使用 event_type in (0, 1, 2)
和 AND start_date between x and y
.
这样的条件
我不认为存在 GiST 不能有效使用 in-list 而 BTREE 可以的根本原因。也许这会在未来的某个版本中为 GiST 修复。
我正在构建一个应用程序,其中服务器需要 select 行基于一些 criteria/filters。其中之一是用户的位置和用户希望查看帖子的半径和其他过滤器,例如日期范围和过滤另一列的值。这将用于临时事件发现应用程序。
我读过有关 PostGIS 的文章,我知道有一个 point
数据类型。基于 this 的回答,我明白最好从相等到范围列排序,尽管我觉得地理点列应该是第一个。但主要问题是,如何创建这样的索引?我考虑过 GiST 索引,但不确定是否有帮助。
假设以下简化事件table(忽略有效位置数据):
id event_title event_position event_type is_public start_date
(varchar) (point lat/lon) (smallint) (boolean) (timestamptz)
-- --------------------------- --------------- --------- --------- ----
1 "John's Party" (122,35) 0 0 2020-07-05
2 "Revolution then Starbucks" (123,30) 1 1 2020-07-06
3 "Study for math exam" (120,36) 2 1 2020-07-07
4 "Party after exam" (120,36) 1 1 2020-07-08
5 "Hiking next to the city" (95,40) 3 1 2020-07-09
6 "Football match" (-42,31) 4 1 2020-07-10
因此,在此 table 中,用户将能够查询 public 接近 (122,34) 100 公里的事件(假设前三行落入此区域)且事件类型为 0 , 1 或 2 个落在日期 2020-07-05 和 2020-07-07 之间。用户将获得 ID 为 2 和 3 的行。
这是我要使用适当索引优化的查询。谢谢!
在 btree_gist extension 的帮助下,您可以将 event_type 和 start_date 列与 event_position 一起包含到 GiST 索引中。但是,只要限制子句类似于 event_type in (0, 1, 2)
,event_type 在索引中就不会很有用。 (但如果列表只包含一个元素,它将被重写为一个等式,在这种情况下它可以有效地使用索引中的该列。)所以使用其他两列将是我的起点。我会把通常更有选择性的放在第一位。如果您打算将过去的事件留在 table 而不是清除它们,那么日期可能最终会成为更具选择性的日期。
如果位置条件不是很挑剔(例如,您的大部分活动都在纽约市,您的大部分用户都在纽约市,几乎所有地方都在 100 公里以内),那么您可能想要一种不同的方法。只需在 (event_type, start_date)
上创建一个默认的 BTREE 索引。与 GiST 不同,这样的 BTREE 可以有效地使用 event_type in (0, 1, 2)
和 AND start_date between x and y
.
我不认为存在 GiST 不能有效使用 in-list 而 BTREE 可以的根本原因。也许这会在未来的某个版本中为 GiST 修复。