【问题标题】:What kind of index should I create to make "WHERE col1 LIKE '0000%' AND col2 = 'somevalue'" faster?我应该创建什么样的索引来使“WHERE col1 LIKE '0000%' AND col2 = 'somevalue'”更快?
【发布时间】:2015-04-05 15:00:58
【问题描述】:

我尝试了以下查询,以便使用 PostgreSQL 的 LIKE 运算符在四叉树内进行搜索。在col3列中,插入了'0133002112300300320'之类的词,描述了四叉树的路径。

CREATE TABLE table1
(col1 CHARACTER(9) NOT NULL,
 col2 INTEGER NOT NULL,
 col3 CHARACTER VARYING(64),
 col4 INTEGER NOT NULL,
 col5 DOUBLE PRECISION NOT NULL,
 PRIMARY KEY(col1,col2,col3));

-- Performs sequential search
SELECT col1,col2,col3,col4,col5
FROM table1
WHERE col1='somevalue' AND col2=0 AND col3 LIKE '01330021123003003%';

问题是我设置的 PRIMARY KEY 索引不适用于WHERE col1='somevalue' AND col2=0 AND col3 LIKE '01330021123003003%'。如果要使用创建的索引,我似乎不能同时使用LIKE 运算符和AND 运算符。

我可以创建任何特殊索引来使SELECT 更快吗?

【问题讨论】:

  • 锚定到开头的模式匹配 (col LIKE 'foo%') 可以在数据库认为有益的情况下使用索引。您如何确定它“不起作用”?
  • 我发现使用EXPLAIN。可以肯定col LIKE 'foo%' 可以使用索引,但是col1 LIKE 'foo%' AND col2='baz' 呢?它还能使用索引吗?
  • 表格有多少行?请出示解释。
  • 有 1033810 行。 Seq Scan on table1 (cost=0.00..48498.61 rows=1 width=89) Filter: (((col3)::text ~~ '01330021123003003%'::text) AND (col1 = 'somevalue'::bpchar) AND (col2 = 0))
  • 我试过EXPLAIN ANALYZE"Rows Removed by Filter: 1033804" "Planning time: 0.127 ms" "Execution time: 477.148 ms"

标签: postgresql indexing database-performance sql-like


【解决方案1】:

看来我不能同时使用 LIKE 运算符和 AND 运算符 时间如果你想使用创建的索引。

在这种情况下可以使用索引。以下是您的精确表和精确查询的方法,在 100k 行中随机分布良好的内容:

insert into table1 select 
   (random()*10000)::int,
   (random()*10000)::int,
    md5(random()::text),
    0,0 
    from generate_series(1,100000);

ANALYZE table1;

EXPLAIN ANALYZE SELECT col1,col2,col3,col4,col5
FROM table1
WHERE col1='somevalue' AND col2=0 AND col3 LIKE '01330021123003003%';

结果:

在 table1 上使用 table1_pkey 进行索引扫描(成本=0.00..8.32 行=1 宽度=59)(实际时间=0.022..0.022 行=0 循环=1) 索引条件:((col1 = 'somevalue'::bpchar) AND (col2 = 0)) 过滤器:((col3)::text ~~ '01330021123003003%'::text) 总运行时间:0.050 毫秒 (4 行)

Index Scan using table1_pkey 表明该索引已用于该查询。

如果您的数据集没有,最合理的原因是您正在搜索太常见的值。

【讨论】:

    【解决方案2】:

    第一个问题是您对没有文本列使用模式匹配表达式。最好把 col3 做成文本。

    其次是创建索引的方式。要将索引与模式匹配表达式一起使用,您必须以特殊方式创建索引。看: http://www.postgresql.org/docs/9.1/static/indexes-opclass.html

    这里有一个例子:

    --Firstly, I generate example data (10m records):
    drop table tmp_example_record;
    create table tmp_example_record as
    select
    id,
      floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||
        floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||
        floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||
        floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text||floor(random()*4)::text as quad_tree_path
    from generate_series(1,10000000) id;
    
    
    --Create copy of quad_tree_path -> on this column we create right index type to pattern matching
    alter table tmp_example_record add column quad_tree_path_copy text;
    update tmp_example_record set quad_tree_path_copy =quad_tree_path;  
    --create index, with a special operator class
    CREATE INDEX tmp_example_record_quad_tree_path_copy_index ON   tmp_example_record (quad_tree_path_copy varchar_pattern_ops);
    
    
    explain analize
    select * from tmp_example_record where quad_tree_path_copy like '212013223122333%'
    --about 10ms
    /*
    "Index Scan using tmp_example_record_quad_tree_path_copy_index on tmp_example_record  (cost=0.56..8.58 rows=1000 width=86)"
     "  Index Cond: ((quad_tree_path_copy ~>=~ '212013223122333'::text) AND (quad_tree_path_copy ~<~ '212013223122334'::text))"
     "  Filter: (quad_tree_path_copy ~~ '212013223122333%'::text)"
     */
    
    explain analize
    select * from tmp_example_record where quad_tree_path like '212013223122333%'
    --more then  2000ms
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-12
      • 1970-01-01
      • 2016-12-05
      • 2013-09-17
      • 1970-01-01
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多