如何使这个查询使用我的多列索引?

Chr*_*itt 5 postgresql performance index postgresql-performance

目前,我有一个定义如下的视图:

                       View "public.customer_list"
  Column   |          Type           | Modifiers | Storage  | Description 
-----------+-------------------------+-----------+----------+-------------
 id        | bigint                  |           | plain    | 
 name      | character varying(100)  |           | extended | 
 street    | character varying(100)  |           | extended | 
 zip       | character varying(10)   |           | extended | 
 city      | character varying(100)  |           | extended | 
 country   | character varying(3)    |           | extended | 
 phone     | character varying(100)  |           | extended | 
 mail      | character varying(100)  |           | extended | 
 rating    | integer                 |           | plain    | 
 salesnote | character varying(1800) |           | extended | 
View definition:
 SELECT c.id,
    c.name,
    a.street,
    a.zip,
    a.city,
    a.country,
    c.phone,
    c.mail,
    c.rating,
    c.salesnote
   FROM crm_customer c
     JOIN crm_address a ON a.id = c.address_id;
Run Code Online (Sandbox Code Playgroud)

为了更好地搜索列表,我创建了一个索引,如下所示:

CREATE INDEX crm_customer_big_index 
    ON crm_customer (name ASC, 
                     name text_pattern_ops, 
                     (id::text) text_pattern_ops, 
                     phone text_pattern_ops, 
                     mail text_pattern_ops, 
                     rating);
Run Code Online (Sandbox Code Playgroud)

我用不同的 where 查询来搜索这个表,主要是这样的:

SELECT * 
  FROM customer_list
 WHERE lower(name::text) LIKE 'env%' 
       AND rating = 3 
 ORDER BY name ASC 
 LIMIT 20 
 OFFSET 0;
Run Code Online (Sandbox Code Playgroud)

但是我的分析器仍然不会使用索引。有没有办法使用一个?

             QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=164.04..164.08 rows=15 width=129) (actual time=3.243..3.244 rows=1 loops=1)
   ->  Sort  (cost=164.04..164.08 rows=15 width=129) (actual time=3.243..3.243 rows=1 loops=1)
         Sort Key: c.name
         Sort Method: quicksort  Memory: 26kB
         ->  Nested Loop  (cost=0.28..163.75 rows=15 width=129) (actual time=0.020..3.225 rows=1 loops=1)
               ->  Seq Scan on crm_customer c  (cost=0.00..111.13 rows=15 width=98) (actual time=0.012..3.216 rows=1 loops=1)
                     Filter: ((rating = 3) AND (lower((name)::text) ~~ 'env%'::text))
                     Rows Removed by Filter: 2978
               ->  Index Only Scan using crm_address_search_index on crm_address a  (cost=0.28..3.50 rows=1 width=47) (actual time=0.006..0.006 rows=1 loops=1)
                     Index Cond: (id = c.address_id)
                     Heap Fetches: 0
 Planning time: 0.580 ms
 Execution time: 3.286 ms
Run Code Online (Sandbox Code Playgroud)

目前,查询仍然“有点”快。但是,我的表中可以有更多数据。此外,crm_address有一个索引 over street, zip, city, country,它工作正常。

Erw*_*ter 6

表达lower(name::text)是不属于你的指数,这也似乎没有有用所有,至少我们在你的问题中看到的:


CREATE INDEX crm_customer_big_index 
    ON crm_customer (name ASC, 
                     name text_pattern_ops, 
                     (id::text) text_pattern_ops, 
                     phone text_pattern_ops, 
                     mail text_pattern_ops, 
                     rating);
Run Code Online (Sandbox Code Playgroud)

该索引将涵盖您的查询:

CREATE INDEX crm_customer_foo_index ON crm_customer (
  rating
, lower(name::text) text_pattern_ops
, address_id);  -- for the join
Run Code Online (Sandbox Code Playgroud)

为了优化,我建议另外调整您的查询:

SELECT * 
FROM   customer_list
WHERE  lower(name::text) LIKE 'env%' 
AND    rating = 3 
ORDER  BY lower(name::text), name
LIMIT  20;
Run Code Online (Sandbox Code Playgroud)

此外,如果您只对 的前几个字符感兴趣,name character varying(100)只需索引前几个字符,即可使索引更短更快:

CREATE INDEX crm_customer_foo_index ON crm_customer (
  rating
, lower(left(name::text, 7)) text_pattern_ops  -- example with local optimum
, address_id);  -- for the join
Run Code Online (Sandbox Code Playgroud)

查询必须匹配索引表达式:

WHERE  lower(left(name::text, 7)) LIKE 'env%' 
...
ORDER  BY lower(left(name::text, 7)), name
Run Code Online (Sandbox Code Playgroud)

不确定风景是否以某种方式挡住了视线。但它应该是透明的。

我根本不会用varchar(n)。只是text

关于模式匹配和text_pattern_ops

为什么我把rating索引放在第一位?

有一些查询技术可以更好地利用非前导索引列。考虑Postgres Wiki 上的 "Loose indexscan"


归档时间:

查看次数:

1001 次

最近记录:

10 年,1 月 前