当前位置:   article > 正文

PostgreSQL 快速给指定表每个字段创建索引 - 2

postgrel字段加索引

标签

PostgreSQL , 索引 , 所有字段 , 并行创建单个索引 , max_parallel_maintenance_workers , 异步调用 , dblink , 并行创建多个索引 , adhoc查询


背景

PostgreSQL 支持丰富的类型、索引,统计信息。

不同的应用场合,数据类型,可使用不同的索引接口(btree,hash,gin,gist,spgist,brin,bloom等)达到不同的效果。

https://www.postgresql.org/docs/11/static/datatype.html

https://www.postgresql.org/docs/11/static/functions.html

https://www.postgresql.org/docs/11/static/indexes.html

在某些业务场合,业务上可能需要对任意字段组合进行查询,可以使用gin或rum 联合索引接口(把需要搜索的字段都塞到一个索引里面,内部使用bitmap scan),但是这些索引创建速度比较慢,并且索引最多只能放32列(硬编码限制 src/include/pg_config_manual.h INDEX_MAX_KEYS)。

所以另一种选择是使用单列独立索引,当单列独立索引过滤性不够好时,数据库自动会选择多个索引做bitmap 合并扫描.

《PostgreSQL bitmapAnd, bitmapOr, bitmap index scan, bitmap heap scan》

那么每一列应该使用什么索引接口?

除了取决于数据类型,还取决于数据的分布,柱状图。

《PostgreSQL 9种索引的原理和应用场景》

《PostgreSQL SQL自动优化案例 - 极简,自动推荐索引》

《自动选择正确索引访问接口(btree,hash,gin,gist,sp-gist,brin,bitmap...)的方法》

数据类型与索引类型匹配的通用选择方法

https://www.postgresql.org/docs/11/static/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE

大类选择

CodeCategory推荐 索引接口
AArray typesgin
BBoolean typesbtree , 不建议加索引,选择性不好
CComposite types-
DDate/time typesbtree
EEnum types-
GGeometric typesgist
INetwork address typesgist, spgist
NNumeric typesbtree
PPseudo-types-
RRange typesgist, spgist
SString typesbtree : varchar text_pattern_ops , bpchar bpchar_pattern_ops ; 
模糊查询(pg_trgm) gin : varchar gin_trgm_ops
TTimespan typesbtree
UUser-defined types-
VBit-string types-
Xunknown type-

小类选择

select typcategory , typname from pg_type order by 1,2;  
CodeCategory推荐 索引接口
Uaclitem-
Ubox2d-
Ubox2df-
Ubox3d-
Ubytea-
Ucid-
Ugbtreekey16-
Ugbtreekey32-
Ugbtreekey4-
Ugbtreekey8-
Ugbtreekey_var-
Ugeographygist
Ugeometrygist
Ugidx-
Ugtrgm-
Ugtsvector-
Ujsongin
Ujsonbgin , OPS : jsonb_path_ops
Umacaddr-
Umacaddr8-
Upg_lsn-
Upgis_abs-
Uraster-
Urefcursor-
Usmgr-
Uspheroid-
Utid-
Utsquerygin, rum
Utsvectorgin, rum
Utxid_snapshot-
Uuuidhash
Uxidbtree
Uxml-

依据以上规则,生成create index的SQL

写一个UDF函数,将以上规格写到UDF里面,自动生成每一列的索引SQL,自动使用合适的索引方法,OPS。

  1. create or replace function gen_whole_index_sqls(
  2. v_nsp name,
  3. v_tbl name,
  4. v_tbs name
  5. ) returns text[] as $$
  6. declare
  7. v_attname name;
  8. v_typid oid;
  9. v_typca "char";
  10. v_typname name;
  11. res text[];
  12. idxprefix text := to_char(clock_timestamp(),'yyyymmddhh24miss');
  13. idxsuffix int := 1;
  14. sql text := 'create index IF NOT EXISTS i'||idxprefix||'_%s on '||quote_ident(v_nsp)||'.'||quote_ident(v_tbl)||' using %s (%I %s) tablespace '||quote_ident(v_tbs)||' ;';
  15. begin
  16. for v_attname,v_typid in select attname,atttypid from pg_attribute where not attisdropped and attnum >= 1 and attrelid=(quote_ident(v_nsp)||'.'||quote_ident(v_tbl))::regclass
  17. loop
  18. select typcategory,typname into v_typca,v_typname from pg_type where oid=v_typid;
  19. case v_typca
  20. when 'A' then
  21. res := array_append(res, format(sql,idxsuffix,'gin',v_attname,''));
  22. when 'D', 'N', 'T' then
  23. res := array_append(res, format(sql,idxsuffix,'btree',v_attname,''));
  24. when 'S' then
  25. if v_typname='text' or v_typname='varchar' then
  26. res := array_append(res, format(sql,idxsuffix,'btree',v_attname,'text_pattern_ops'));
  27. elsif v_typname='bpchar' then
  28. res := array_append(res, format(sql,idxsuffix,'btree',v_attname,'bpchar_pattern_ops'));
  29. else
  30. res := array_append(res, format(sql,idxsuffix,'btree',v_attname,''));
  31. end if;
  32. -- 如果字符串要支持模糊查询,使用gin索引
  33. -- if v_typname='text' or v_typname='varchar' then
  34. -- res := array_append(res, format(sql,idxsuffix,'gin',v_attname,'gin_trgm_ops'));
  35. -- else
  36. -- res := array_append(res, format(sql,idxsuffix,'btree',v_attname,''));
  37. -- end if;
  38. when 'G' then
  39. if v_typname not in ('line') then
  40. res := array_append(res, format(sql,idxsuffix,'gist',v_attname,''));
  41. else
  42. continue;
  43. end if;
  44. when 'I', 'R' then
  45. res := array_append(res, format(sql,idxsuffix,'gist',v_attname,''));
  46. -- 可选spgist
  47. -- res := array_append(res, format(sql,idxsuffix,'spgist',v_attname,''));
  48. when 'U' then
  49. case v_typname
  50. when 'geography', 'geometry' then
  51. res := array_append(res, format(sql,idxsuffix,'gist',v_attname,''));
  52. when 'jsonb' then
  53. res := array_append(res, format(sql,idxsuffix,'gin',v_attname,'jsonb_path_ops'));
  54. -- 可选默认gin ops
  55. -- https://www.postgresql.org/docs/11/static/datatype-json.html#JSON-INDEXING
  56. -- res := array_append(res, format(sql,idxsuffix,'gin',v_attname,''));
  57. when 'tsvector' then
  58. res := array_append(res, format(sql,idxsuffix,'gin',v_attname,''));
  59. when 'uuid', 'xid' then
  60. res := array_append(res, format(sql,idxsuffix,'hash',v_attname,''));
  61. else
  62. continue;
  63. end case;
  64. else
  65. continue;
  66. end case;
  67. idxsuffix := idxsuffix+1;
  68. end loop;
  69. return res;
  70. end;
  71. $$ language plpgsql strict;

测试

1、创建测试表,包含各种数据类型

  1. create table "你好t12" (
  2. c1 int,
  3. "-_c2&a-b" int8,
  4. c3 text,
  5. c4 varchar(1000),
  6. c5 char(1000),
  7. c6 "char",
  8. c7 timestamp,
  9. c8 interval,
  10. c9 int[],
  11. c10 tsvector,
  12. c11 tsquery,
  13. c12 time,
  14. c13 date,
  15. c14 numeric,
  16. c15 float,
  17. c16 point,
  18. c17 box,
  19. c18 line,
  20. c19 circle,
  21. c20 inet,
  22. c21 cidr,
  23. c22 int8range,
  24. c23 tsrange,
  25. c24 geometry,
  26. c25 geography,
  27. c26 uuid,
  28. c27 xid,
  29. c28 json,
  30. c29 jsonb
  31. );

2、使用本文提供的UDF,生成CREATE INDEX SQL

  1. select * from unnest(gen_whole_index_sqls('public','你好t12','pg_default'));
  2. unnest
  3. ------------------------------------------------------------------------------------------------------------------------------
  4. create index IF NOT EXISTS i20180903171836_1 on public."你好t12" using btree (c1 ) tablespace pg_default ;
  5. create index IF NOT EXISTS i20180903171836_2 on public."你好t12" using btree ("-_c2&a-b" ) tablespace pg_default ;
  6. create index IF NOT EXISTS i20180903171836_3 on public."你好t12" using btree (c3 text_pattern_ops) tablespace pg_default ;
  7. create index IF NOT EXISTS i20180903171836_4 on public."你好t12" using btree (c4 text_pattern_ops) tablespace pg_default ;
  8. create index IF NOT EXISTS i20180903171836_5 on public."你好t12" using btree (c5 bpchar_pattern_ops) tablespace pg_default ;
  9. create index IF NOT EXISTS i20180903171836_6 on public."你好t12" using btree (c6 ) tablespace pg_default ;
  10. create index IF NOT EXISTS i20180903171836_7 on public."你好t12" using btree (c7 ) tablespace pg_default ;
  11. create index IF NOT EXISTS i20180903171836_8 on public."你好t12" using btree (c8 ) tablespace pg_default ;
  12. create index IF NOT EXISTS i20180903171836_9 on public."你好t12" using gin (c9 ) tablespace pg_default ;
  13. create index IF NOT EXISTS i20180903171836_10 on public."你好t12" using gin (c10 ) tablespace pg_default ;
  14. create index IF NOT EXISTS i20180903171836_11 on public."你好t12" using btree (c12 ) tablespace pg_default ;
  15. create index IF NOT EXISTS i20180903171836_12 on public."你好t12" using btree (c13 ) tablespace pg_default ;
  16. create index IF NOT EXISTS i20180903171836_13 on public."你好t12" using btree (c14 ) tablespace pg_default ;
  17. create index IF NOT EXISTS i20180903171836_14 on public."你好t12" using btree (c15 ) tablespace pg_default ;
  18. create index IF NOT EXISTS i20180903171836_15 on public."你好t12" using gist (c16 ) tablespace pg_default ;
  19. create index IF NOT EXISTS i20180903171836_16 on public."你好t12" using gist (c17 ) tablespace pg_default ;
  20. create index IF NOT EXISTS i20180903171836_17 on public."你好t12" using gist (c19 ) tablespace pg_default ;
  21. create index IF NOT EXISTS i20180903171836_18 on public."你好t12" using gist (c20 ) tablespace pg_default ;
  22. create index IF NOT EXISTS i20180903171836_19 on public."你好t12" using gist (c21 ) tablespace pg_default ;
  23. create index IF NOT EXISTS i20180903171836_20 on public."你好t12" using gist (c22 ) tablespace pg_default ;
  24. create index IF NOT EXISTS i20180903171836_21 on public."你好t12" using gist (c23 ) tablespace pg_default ;
  25. create index IF NOT EXISTS i20180903171836_22 on public."你好t12" using gist (c24 ) tablespace pg_default ;
  26. create index IF NOT EXISTS i20180903171836_23 on public."你好t12" using gist (c25 ) tablespace pg_default ;
  27. create index IF NOT EXISTS i20180903171836_24 on public."你好t12" using hash (c26 ) tablespace pg_default ;
  28. create index IF NOT EXISTS i20180903171836_25 on public."你好t12" using hash (c27 ) tablespace pg_default ;
  29. create index IF NOT EXISTS i20180903171836_26 on public."你好t12" using gin (c29 jsonb_path_ops) tablespace pg_default ;
  30. (26 rows)

3、创建索引测试

使用之前提到的并行跑后台任务的方法,并行创建多个索引,充分利用硬件资源加速。

《PostgreSQL dblink异步调用实践,跑并行多任务 - 例如开N个并行后台任务创建索引, 开N个后台任务跑若干SQL》

  1. select * from run_sqls_parallel(6, gen_whole_index_sqls('public','你好t12','pg_default')) as t(a text);
  2. NOTICE: the last 3 tasks running.
  3. NOTICE: whole tasks done.
  4. run_sqls_parallel
  5. -------------------
  6. (1 row)

4、检验

  1. postgres=# \d 你好t12
  2. Table "public.你好t12"
  3. Column | Type | Collation | Nullable | Default
  4. ----------+-----------------------------+-----------+----------+---------
  5. c1 | integer | | |
  6. -_c2&a-b | bigint | | |
  7. c3 | text | | |
  8. c4 | character varying(1000) | | |
  9. c5 | character(1000) | | |
  10. c6 | "char" | | |
  11. c7 | timestamp without time zone | | |
  12. c8 | interval | | |
  13. c9 | integer[] | | |
  14. c10 | tsvector | | |
  15. c11 | tsquery | | |
  16. c12 | time without time zone | | |
  17. c13 | date | | |
  18. c14 | numeric | | |
  19. c15 | double precision | | |
  20. c16 | point | | |
  21. c17 | box | | |
  22. c18 | line | | |
  23. c19 | circle | | |
  24. c20 | inet | | |
  25. c21 | cidr | | |
  26. c22 | int8range | | |
  27. c23 | tsrange | | |
  28. c24 | geometry | | |
  29. c25 | geography | | |
  30. c26 | uuid | | |
  31. c27 | xid | | |
  32. c28 | json | | |
  33. c29 | jsonb | | |
  34. Indexes:
  35. "i20180903171855_1" btree (c1)
  36. "i20180903171855_10" gin (c10)
  37. "i20180903171855_11" btree (c12)
  38. "i20180903171855_12" btree (c13)
  39. "i20180903171855_13" btree (c14)
  40. "i20180903171855_14" btree (c15)
  41. "i20180903171855_15" gist (c16)
  42. "i20180903171855_16" gist (c17)
  43. "i20180903171855_17" gist (c19)
  44. "i20180903171855_18" gist (c20)
  45. "i20180903171855_19" gist (c21)
  46. "i20180903171855_2" btree ("-_c2&a-b")
  47. "i20180903171855_20" gist (c22)
  48. "i20180903171855_21" gist (c23)
  49. "i20180903171855_22" gist (c24)
  50. "i20180903171855_23" gist (c25)
  51. "i20180903171855_24" hash (c26)
  52. "i20180903171855_25" hash (c27)
  53. "i20180903171855_26" gin (c29 jsonb_path_ops)
  54. "i20180903171855_3" btree (c3 text_pattern_ops)
  55. "i20180903171855_4" btree (c4 text_pattern_ops)
  56. "i20180903171855_5" btree (c5 bpchar_pattern_ops)
  57. "i20180903171855_6" btree (c6)
  58. "i20180903171855_7" btree (c7)
  59. "i20180903171855_8" btree (c8)
  60. "i20180903171855_9" gin (c9)
  1. postgres=# \di i20180903171855_*
  2. List of relations
  3. Schema | Name | Type | Owner | Table
  4. --------+--------------------+-------+----------+---------
  5. public | i20180903171855_1 | index | postgres | 你好t12
  6. public | i20180903171855_10 | index | postgres | 你好t12
  7. public | i20180903171855_11 | index | postgres | 你好t12
  8. public | i20180903171855_12 | index | postgres | 你好t12
  9. public | i20180903171855_13 | index | postgres | 你好t12
  10. public | i20180903171855_14 | index | postgres | 你好t12
  11. public | i20180903171855_15 | index | postgres | 你好t12
  12. public | i20180903171855_16 | index | postgres | 你好t12
  13. public | i20180903171855_17 | index | postgres | 你好t12
  14. public | i20180903171855_18 | index | postgres | 你好t12
  15. public | i20180903171855_19 | index | postgres | 你好t12
  16. public | i20180903171855_2 | index | postgres | 你好t12
  17. public | i20180903171855_20 | index | postgres | 你好t12
  18. public | i20180903171855_21 | index | postgres | 你好t12
  19. public | i20180903171855_22 | index | postgres | 你好t12
  20. public | i20180903171855_23 | index | postgres | 你好t12
  21. public | i20180903171855_24 | index | postgres | 你好t12
  22. public | i20180903171855_25 | index | postgres | 你好t12
  23. public | i20180903171855_26 | index | postgres | 你好t12
  24. public | i20180903171855_3 | index | postgres | 你好t12
  25. public | i20180903171855_4 | index | postgres | 你好t12
  26. public | i20180903171855_5 | index | postgres | 你好t12
  27. public | i20180903171855_6 | index | postgres | 你好t12
  28. public | i20180903171855_7 | index | postgres | 你好t12
  29. public | i20180903171855_8 | index | postgres | 你好t12
  30. public | i20180903171855_9 | index | postgres | 你好t12
  31. (26 rows)

小结

1、本文提供了一个UDF,用于生成创建索引的SQL(返回SQL数组)

gen_whole_index_sqls('name space','表名','表空间名')  

2、使用之前提到的并行跑后台任务的方法,并行创建多个索引,充分利用硬件资源加速。

《PostgreSQL dblink异步调用实践,跑并行多任务 - 例如开N个并行后台任务创建索引, 开N个后台任务跑若干SQL》

例如

select * from run_sqls_parallel(6, gen_whole_index_sqls('public','你好t12','pg_default')) as t(a text);  

3、结合表的统计信息(analyze table后),可以把生成CREATE INDEX SQL做得更加完美。

《自动选择正确索引访问接口(btree,hash,gin,gist,sp-gist,brin,bitmap...)的方法》

参考

https://www.postgresql.org/docs/11/static/plpgsql-control-structures.html#PLPGSQL-FOREACH-ARRAY

《PostgreSQL dblink异步调用实践,跑并行多任务 - 例如开N个并行后台任务创建索引, 开N个后台任务跑若干SQL》

《PostgreSQL 9种索引的原理和应用场景》

《PostgreSQL SQL自动优化案例 - 极简,自动推荐索引》

《自动选择正确索引访问接口(btree,hash,gin,gist,sp-gist,brin,bitmap...)的方法》

《PostgreSQL 快速给指定表每个字段创建索引》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/655234
推荐阅读
相关标签
  

闽ICP备14008679号