PostgreSQL LIKE query performance variations

I have been seeing quite a large variation in response times regarding LIKE queries to a particular table in my database. Sometimes I will get results within 200-400 ms (very acceptable) but other times it might take as much as 30 seconds to return results.

I understand that LIKE queries are very resource intensive but I just don't understand why there would be such a large difference in response times. I have built a btree index on the owner1 field but I don't think it helps with LIKE queries. Anyone have any ideas?

Sample SQL:

SELECT gid, owner1 FORM parcels
WHERE owner1 ILIKE '%someones name%' LIMIT 10

I've also tried:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%') LIMIT 10

And:

SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('someones name%') LIMIT 10

With similar results.
Table Row Count: about 95,000.


FTS does not support LIKE

The previously accepted answer was incorrect. Full Text Search with its full text indexes is not for the LIKE operator at all, it has its own operators and doesn't work for arbitrary strings. It operates on words based on dictionaries and stemming. It does support prefix matching for words, but not with the LIKE operator:

  • Get partial match from GIN indexed TSVECTOR column
  • Trigram indexes for LIKE

    Install the additional module pg_trgm which provides operator classes for GIN and GiST trigram indexes to support all LIKE and ILIKE patterns , not just left-anchored ones:

    Example index:

    CREATE INDEX tbl_col_gin_trgm_idx  ON tbl USING gin  (col gin_trgm_ops);

    Or:

    CREATE INDEX tbl_col_gist_trgm_idx ON tbl USING gist (col gist_trgm_ops);
  • Difference between GiST and GIN index
  • Example query:

    SELECT * FROM tbl WHERE col LIKE '%foo%';   -- leading wildcard
    SELECT * FROM tbl WHERE col ILIKE '%foo%';  -- works case insensitively as well

    Trigrams? What about shorter strings?

    Words with less than 3 letters in indexed values still work. The manual:

    Each word is considered to have two spaces prefixed and one space suffixed when determining the set of trigrams contained in the string.

    And search patterns with less than 3 letters? The manual:

    For both LIKE and regular-expression searches, keep in mind that a pattern with no extractable trigrams will degenerate to a full-index scan.

    Meaning, that index / bitmap index scans still work (query plans for prepared statement won't break), it just won't buy you better performance. Typically no big loss, since 1- or 2-letter strings are hardly selective (more than a few percent of the underlying table matches) and index support would not improve performance to begin with, because a full table scan is faster.


    text_pattern_ops for prefix matching

    For just left-anchored patterns (no leading wildcard) you get the optimum with a suitable operator class for a btree index: text_pattern_ops or varchar_pattern_ops . Both built-in features of standard Postgres, no additional module needed. Similar performance, but much smaller index.

    Example index:

    CREATE INDEX tbl_col_text_pattern_ops_idx ON tbl(col text_pattern_ops);

    Example query:

    SELECT * FROM tbl WHERE col LIKE 'foo%';  -- no leading wildcard

    Or, if you should be running your database with the 'C' locale (effectively no locale), then everything is sorted according to byte order anyway and a plain btree index with default operator class does the job.

    More details, explanation, examples and links in these related answers on dba.SE:

  • Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL
  • How is LIKE implemented?
  • Finding similar strings with PostgreSQL quickly

  • Possibly the fast ones are anchored patterns with case-sensitive like that can use indexes. ie there is no wild card at the beginning of the match string so the executor can use an index range scan. (the relevant comment in the docs is here) Lower and ilike will also lose your ability to use the index unless you specifically create an index for that purpose (see functional indexes).

    If you want to search for string in the middle of the field, you should look into full text or trigram indexes. First of them is in Postgres core, the other is available in the contrib modules.


    You could install Wildspeed, a different type of index in PostgreSQL. Wildspeed does work with %word% wildcards, no problem. The downside is the size of the index, this can be large, very large.

    链接地址: http://www.djcxy.com/p/87232.html

    上一篇: Postgres使用通常的数组索引而不是intarray索引

    下一篇: PostgreSQL LIKE查询性能变化