复合索引中的列顺序

时间:2018-10-30 07:17:56

标签: postgresql query-performance

我在具有超过1300万条记录的表上使用复合索引。 index order is (center_code, created_on, status)。 center_code和status均为varchar(100)而不是NULL,created_on是没有时区的时间戳。

我读到某处索引的顺序在复合索引中很重要。我们必须检查唯一值的数量,并将唯一值最高的那个放在复合索引的第一位。

  • center_code可以具有4000个不同的值。
  • 状态可以有5个不同的值。
  • created_on的最小值为2017-12-12 02:00:49.465317+00

问题是created_on的唯一值可以是多少? 我应该把它放在复合索引中吗?

“按日期编制索引”列以日期,小时或秒为基础。

问题是:

一个简单的SELECT查询花费的时间超过500毫秒,仅使用此复合索引而没有其他操作。

表上的索引:

Indexes:
    "pa_key" PRIMARY KEY, btree (id)
    "pa_uniq" UNIQUE CONSTRAINT, btree (wbill)
    "pa_center_code_created_on_status_idx_new" btree (center_code, created_on, status)

查询为:

EXPLAIN ANALYSE 
SELECT "pa"."wbill" 
FROM "pa" 
WHERE ("pa"."center_code" = 'IND110030AAC' 
AND "pa"."status" IN ('Scheduled') 
AND "pa"."created_on" >= '2018-10-10T00:00:00+05:30'::timestamptz);

查询计划:

   Index Scan using pa_center_code_created_on_status_idx_new on pa  (cost=0.69..3769.18 rows=38 width=13) (actual time=5.592..15.526 rows=78 loops=1)
   Index Cond: (((center_code)::text = 'IND110030AAC'::text) AND (created_on >= '2018-10-09 18:30:00+00'::timestamp with time zone) AND ((status)::text = 'Scheduled'::text))
     Planning time: 1.156 ms
     Execution time: 519.367 ms

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

索引扫描条件读取

(((center_code)::text = 'IND110030AAC'::text) AND
  (created_on >= '2018-10-09 18:30:00+00'::timestamp with time zone) AND
 ((status)::text = 'Scheduled'::text))

但是索引扫描本身仅在(center_code, created_on)上进行,而status上的条件用作过滤器。

不幸的是,这在执行计划中不可见,但遵循以下规则:

只有满足条件的行在索引中彼此相邻时,索引扫描才会使用条件。

让我们考虑这个示例(以索引顺序):

 center_code  | created_on          | status
--------------+---------------------+-----------
 IND110030AAC | 2018-10-09 00:00:00 | Scheduled
 IND110030AAC | 2018-10-09 00:00:00 | Xtra
 IND110030AAC | 2018-10-10 00:00:00 | New
 IND110030AAC | 2018-10-10 00:00:00 | Scheduled
 IND110030AAC | 2018-10-11 00:00:00 | New
 IND110030AAC | 2018-10-11 00:00:00 | Scheduled

您将看到查询需要第四行和第六行。

PostgreSQL不能在所有三个条件下扫描索引,因为所需的行不是彼此相邻的。只需扫描前两个条件,因为满足这些条件的所有行都紧挨着。

您的多列索引规则是错误的。索引左侧的列必须是其中=被用作条件中的比较运算符的列。

完美的索引应该是(center_code, status, created_on)上的索引。