snippetsqlMinor
How to make this query use my multicolumn index?
Viewed 0 times
thisquerymakemulticolumnhowindexuse
Problem
Currently, I have a view which is defined like this:
To better search through the List I created an index with the following:
I search through this table with a varying where query mostly it looks like that:
But still my analyzer won't ever use an index. Is there a way to use one?
```
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=164.04..164.08 rows=15 width=129) (actual time=3
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;To better search through the List I created an index with the following:
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);I search through this table with a varying where query mostly it looks like that:
SELECT *
FROM customer_list
WHERE lower(name::text) LIKE 'env%'
AND rating = 3
ORDER BY name ASC
LIMIT 20
OFFSET 0;But still my analyzer won't ever use an index. Is there a way to use one?
```
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=164.04..164.08 rows=15 width=129) (actual time=3
Solution
The expression
This index would cover your query:
To optimize, I suggest to adapt your query additionally:
Also, if you are only interested in the first few characters of
The query must match the index expression:
Not sure if the view is in the way somehow. But it should be transparent.
I wouldn't use
About pattern matching and
Why did I put
There are query techniques to better capitalize on non-leading index columns. Consider the Postgres Wiki on "Loose indexscan".
lower(name::text) is not covered by your index, which also does not seem to be useful at all, at least for what we see in your question:
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);
This index would cover your query:
CREATE INDEX crm_customer_foo_index ON crm_customer (
rating
, lower(name::text) text_pattern_ops
, address_id); -- for the joinTo optimize, I suggest to adapt your query additionally:
SELECT *
FROM customer_list
WHERE lower(name::text) LIKE 'env%'
AND rating = 3
ORDER BY lower(name::text), name
LIMIT 20;Also, if you are only interested in the first few characters of
name character varying(100), make the index shorter and faster by just indexing those first few characters: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 joinThe query must match the index expression:
WHERE lower(left(name::text, 7)) LIKE 'env%'
...
ORDER BY lower(left(name::text, 7)), nameNot sure if the view is in the way somehow. But it should be transparent.
I wouldn't use
varchar(n) at all. Just text:- Should I add an arbitrary length limit to VARCHAR columns?
About pattern matching and
text_pattern_ops:- Pattern matching with LIKE, SIMILAR TO or regular expressions
Why did I put
rating first in the index?- Multicolumn index and performance
There are query techniques to better capitalize on non-leading index columns. Consider the Postgres Wiki on "Loose indexscan".
Code Snippets
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);CREATE INDEX crm_customer_foo_index ON crm_customer (
rating
, lower(name::text) text_pattern_ops
, address_id); -- for the joinSELECT *
FROM customer_list
WHERE lower(name::text) LIKE 'env%'
AND rating = 3
ORDER BY lower(name::text), name
LIMIT 20;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 joinWHERE lower(left(name::text, 7)) LIKE 'env%'
...
ORDER BY lower(left(name::text, 7)), nameContext
StackExchange Database Administrators Q#116705, answer score: 6
Revisions (0)
No revisions yet.