Skip to content
This repository was archived by the owner on Jul 6, 2021. It is now read-only.

Commit 7fb75c9

Browse files
author
Oleg
committed
Query optimization refs #343
1 parent 14484b4 commit 7fb75c9

12 files changed

+151
-83
lines changed

.ci/h003_step2.sql

-1
This file was deleted.

.ci/h003.sql renamed to .ci/h003_step_1.sql

+2
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ create table t1 as select id::int8 from generate_series(0, 1000000) _(id);
22
alter table t1 add primary key (id);
33
create table t2 as select id, (random() * 1000000)::int8 as t1_id from generate_series(1, 1000000) _(id);
44
alter table t2 add constraint fk_t2_t1 foreign key (t1_id) references t1(id);
5+
vacuum analyze t1;
6+
vacuum analyze t2;

.ci/h003_step_2.sql

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
create index on t2 using btree (t1_id);
2+
vacuum analyze t2;

.ci/test_db_dump.sql

-6
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ set statement_timeout to '20ms';
3838
create index concurrently i_invalid on test_schema.t_with_invalid_index(i);
3939
set statement_timeout to 0;
4040

41-
-- H003 non indexed fks
42-
create table t_fk_1 as select id::int8 from generate_series(0, 1000000) _(id);
43-
alter table t_fk_1 add primary key (id);
44-
create table t_fk_2 as select id, (random() * 1000000)::int8 as t1_id from generate_series(1, 1000000) _(id);
45-
alter table t_fk_2 add constraint fk_t2_t1 foreign key (t1_id) references t_fk_1(id);
46-
4741
-- Bloat level
4842
create table bloated as select i from generate_series(1, 100000) _(i);
4943
create index i_bloated on bloated(i);

.gitlab-ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ before_script:
2525
script:
2626
- psql -h postgres -d dbname -U username -c "SELECT version();"
2727
- echo "Test H003 Non indexed FKs"
28-
- psql -h postgres -d dbname -U username -f .ci/h003.sql
28+
- psql -h postgres -d dbname -U username -f .ci/h003_step_1.sql
2929
- ./checkup -h postgres --username username --project test --dbname dbname -e 1 --file ./resources/checks/H003_non_indexed_fks.sh
3030
- data_dir=$(cat ./artifacts/test/nodes.json | jq -r '.last_check | .dir') && result=$(cat ./artifacts/test/json_reports/$data_dir/H003_non_indexed_fks.json | jq '.results .postgres .data') && ([[ "$result" == "[]" ]] || [[ "$result" == "null" ]]) && exit 301
31-
- psql -h postgres -d dbname -U username -f .ci/h003_step2.sql
31+
- psql -h postgres -d dbname -U username -f .ci/h003_step_2.sql
3232
- rm -Rf ./artifacts/
3333
- ./checkup -h postgres --username username --project test --dbname dbname -e 1 --file ./resources/checks/H003_non_indexed_fks.sh
3434
- data_dir=$(cat ./artifacts/test/nodes.json | jq -r '.last_check | .dir') && result=$(cat ./artifacts/test/json_reports/$data_dir/H003_non_indexed_fks.json | jq '.results .postgres .data') && echo "$result" && cat ./artifacts/test/json_reports/$data_dir/H003_non_indexed_fks.json && (! [[ "$result" == "[]" ]]) && exit 302

checkup

+1-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ validate_args() {
352352
# fill default (not given) psql connection related variables
353353
[[ "${PGPORT}" = "None" ]] && export PGPORT=5432
354354
[[ "${DBNAME}" = "None" ]] && export DBNAME=postgres
355-
[[ "${STIMEOUT}" = "None" ]] && export STIMEOUT=15 # statement timeout
355+
[[ "${STIMEOUT}" = "None" ]] && export STIMEOUT=30 # statement timeout
356356
[[ "${USERNAME}" = "None" ]] && export USERNAME=""
357357

358358
# custom UNIX domain socket directory for PostgreSQL

resources/checks/F004_heap_bloat.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ with data as (
3131
join pg_namespace as ns on ns.oid = tbl.relnamespace
3232
join pg_stats as s on s.schemaname = ns.nspname and s.tablename = tbl.relname and not s.inherited and s.attname = att.attname
3333
left join pg_class as toast on tbl.reltoastrelid = toast.oid
34-
where att.attnum > 0 and not att.attisdropped and s.schemaname not in ('pg_catalog', 'information_schema')
34+
where att.attnum > 0 and not att.attisdropped and s.schemaname not in ('pg_catalog', 'information_schema') and tbl.relpages > 10
3535
group by 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, tbl.relhasoids
3636
order by 2, 3
3737
), step2 as (

resources/checks/F005_index_bloat.sh

+16-11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@ with data as (
99
from pg_class pc
1010
join pg_namespace pn on pn.oid = pc.relnamespace
1111
where reloptions::text ~ 'autovacuum'
12+
), step0 as (
13+
select
14+
tbl.oid tblid, nspname, tbl.relname AS tblname, idx.relname AS idxname, idx.reltuples, idx.relpages, idx.relam,
15+
indrelid, indexrelid, regexp_split_to_table(indkey::text, ' ')::smallint AS attnum, --indkey::smallint[] AS attnum,
16+
coalesce(substring(array_to_string(idx.reloptions, ' ') from 'fillfactor=([0-9]+)')::smallint, 90) as fillfactor
17+
from pg_index
18+
join pg_class idx on idx.oid = pg_index.indexrelid
19+
join pg_class tbl on tbl.oid = pg_index.indrelid
20+
join pg_namespace on pg_namespace.oid = idx.relnamespace
21+
join pg_am a ON idx.relam = a.oid
22+
where a.amname = 'btree'
23+
AND pg_index.indisvalid
24+
AND tbl.relkind = 'r'
25+
AND idx.relpages > 10
26+
AND pg_namespace.nspname NOT IN ('pg_catalog', 'information_schema')
1227
), step1 as (
1328
select
1429
i.tblid,
@@ -36,17 +51,7 @@ with data as (
3651
sum((1 - coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) as nulldatawidth,
3752
max(case when a.atttypid = 'pg_catalog.name'::regtype then 1 else 0 end) > 0 as is_na
3853
from pg_attribute as a
39-
join (
40-
select
41-
tbl.oid tblid, nspname, tbl.relname AS tblname, idx.relname AS idxname, idx.reltuples, idx.relpages, idx.relam,
42-
indrelid, indexrelid, indkey::smallint[] AS attnum,
43-
coalesce(substring(array_to_string(idx.reloptions, ' ') from 'fillfactor=([0-9]+)')::smallint, 90) as fillfactor
44-
from pg_index
45-
join pg_class idx on idx.oid = pg_index.indexrelid
46-
join pg_class tbl on tbl.oid = pg_index.indrelid
47-
join pg_namespace on pg_namespace.oid = idx.relnamespace
48-
where pg_index.indisvalid AND tbl.relkind = 'r' AND idx.relpages > 0
49-
) as i on a.attrelid = i.indexrelid
54+
join step0 as i on a.attrelid = i.indexrelid AND a.attnum = i.attnum
5055
join pg_stats as s on
5156
s.schemaname = i.nspname
5257
and (

resources/checks/H002_unused_indexes.sh

+47-41
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,61 @@
11
${CHECK_HOST_CMD} "${_PSQL} -f -" <<SQL
22
with fk_indexes as (
33
select
4-
schemaname as schema_name,
5-
(indexrelid::regclass)::text as index_name,
6-
(relid::regclass)::text as table_name,
4+
n.nspname as schema_name,
5+
ci.relname as index_name,
6+
cr.relname as table_name,
77
(confrelid::regclass)::text as fk_table_ref,
88
array_to_string(indclass, ', ') as opclasses
9-
from
10-
pg_stat_user_indexes
11-
join pg_index using (indexrelid)
12-
left join pg_constraint
13-
on array_to_string(indkey, ',') = array_to_string(conkey, ',')
14-
and schemaname = (connamespace::regnamespace)::text
15-
and conrelid = relid
16-
and contype = 'f'
17-
where idx_scan = 0
18-
and indisunique is false
19-
and conkey is not null --conkey is not null then true else false end as is_fk_idx
9+
from pg_index i
10+
join pg_class ci on ci.oid = i.indexrelid and ci.relkind = 'i'
11+
join pg_class cr on cr.oid = i.indrelid and cr.relkind = 'r'
12+
join pg_namespace n on n.oid = ci.relnamespace
13+
join pg_constraint cn on cn.conrelid = cr.oid
14+
left join pg_stat_user_indexes si on si.indexrelid = i.indexrelid
15+
where
16+
contype = 'f'
17+
and i.indisunique is false
18+
and conkey is not null
19+
and ci.relpages > 100
20+
and si.idx_scan < 10
2021
), table_scans as (
2122
select relid,
2223
tables.idx_scan + tables.seq_scan as all_scans,
2324
( tables.n_tup_ins + tables.n_tup_upd + tables.n_tup_del ) as writes,
2425
pg_relation_size(relid) as table_size
2526
from pg_stat_user_tables as tables
27+
join pg_class c on c.oid = relid
28+
where c.relpages > 100
2629
), all_writes as (
2730
select sum(writes) as total_writes
2831
from table_scans
2932
), indexes as (
3033
select
31-
idx_stat.relid,
32-
idx_stat.indexrelid,
33-
idx_stat.schemaname as schema_name,
34-
idx_stat.relname as table_name,
35-
idx_stat.indexrelname as index_name,
36-
quote_ident(idx_stat.schemaname) as formated_schema_name,
37-
quote_ident(idx_stat.indexrelname) as formated_index_name,
38-
quote_ident(idx_stat.relname) as formated_table_name,
39-
coalesce(nullif(quote_ident(idx_stat.schemaname), 'public') || '.', '') || quote_ident(idx_stat.relname) as formated_relation_name,
40-
idx_stat.idx_scan,
41-
pg_relation_size(idx_stat.indexrelid) as index_bytes,
42-
indexdef ~* 'using btree' as idx_is_btree,
43-
pg_get_indexdef(pg_index.indexrelid) as index_def,
44-
array_to_string(pg_index.indclass, ', ') as opclasses
45-
from pg_stat_user_indexes as idx_stat
46-
join pg_index
47-
using (indexrelid)
48-
join pg_indexes as indexes
49-
on idx_stat.schemaname = indexes.schemaname
50-
and idx_stat.relname = indexes.tablename
51-
and idx_stat.indexrelname = indexes.indexname
34+
i.indrelid,
35+
i.indexrelid,
36+
n.nspname as schema_name,
37+
cr.relname as table_name,
38+
ci.relname as index_name,
39+
quote_ident(n.nspname) as formated_schema_name,
40+
quote_ident(ci.relname) as formated_index_name,
41+
quote_ident(cr.relname) as formated_table_name,
42+
coalesce(nullif(quote_ident(n.nspname), 'public') || '.', '') || quote_ident(cr.relname) as formated_relation_name,
43+
si.idx_scan,
44+
pg_relation_size(i.indexrelid) as index_bytes,
45+
ci.relpages,
46+
(case when a.amname = 'btree' then true else false end) as idx_is_btree,
47+
pg_get_indexdef(i.indexrelid) as index_def,
48+
array_to_string(i.indclass, ', ') as opclasses
49+
from pg_index i
50+
join pg_class ci on ci.oid = i.indexrelid and ci.relkind = 'i'
51+
join pg_class cr on cr.oid = i.indrelid and cr.relkind = 'r'
52+
join pg_namespace n on n.oid = ci.relnamespace
53+
join pg_am a ON ci.relam = a.oid
54+
left join pg_stat_user_indexes si on si.indexrelid = i.indexrelid
5255
where
53-
pg_index.indisunique = false
54-
and pg_index.indisvalid = true
56+
i.indisunique = false
57+
and i.indisvalid = true
58+
and ci.relpages > 100
5559
), index_ratios as (
5660
select
5761
i.indexrelid as index_id,
@@ -67,6 +71,7 @@ with fk_indexes as (
6771
as scans_per_write,
6872
index_bytes as index_size_bytes,
6973
table_size as table_size_bytes,
74+
i.relpages,
7075
idx_is_btree,
7176
index_def,
7277
formated_index_name,
@@ -78,9 +83,9 @@ with fk_indexes as (
7883
from indexes i
7984
left join fk_indexes fi on
8085
fi.fk_table_ref = i.table_name
86+
and fi.schema_name = i.schema_name
8187
and fi.opclasses like (i.opclasses || '%')
82-
join table_scans
83-
using (relid)
88+
join table_scans ts on ts.relid = i.indrelid
8489
),
8590
-- Never used indexes
8691
never_used_indexes as (
@@ -163,8 +168,9 @@ index_data as (
163168
*,
164169
indkey::text as columns,
165170
array_to_string(indclass, ', ') as opclasses
166-
from pg_index
167-
where indisvalid = true
171+
from pg_index i
172+
join pg_class ci on ci.oid = i.indexrelid and ci.relkind = 'i'
173+
where indisvalid = true and ci.relpages > 100
168174
), redundant_indexes as (
169175
select
170176
i2.indexrelid as index_id,

resources/checks/H003_non_indexed_fks.sh

+29-19
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ with data as (
1515
nspname,
1616
fk_actions_update.action as update_action,
1717
fk_actions_delete.action as delete_action,
18-
conkey as key_cols
18+
conkey as key_cols,
19+
pg_class.relpages
1920
from pg_constraint
2021
join pg_class on conrelid = pg_class.oid
2122
join pg_namespace on pg_class.relnamespace = pg_namespace.oid
2223
join fk_actions as fk_actions_update on confupdtype = fk_actions_update.code
2324
join fk_actions as fk_actions_delete on confdeltype = fk_actions_delete.code
24-
where contype = 'f'
25+
where contype = 'f' -- and pg_class.relpages > 10
2526
), fk_attributes as (
2627
select fkoid, conrelid, attname, attnum
2728
from fk_list
@@ -37,36 +38,32 @@ with data as (
3738
pg_class.relname as indexname,
3839
indrelid,
3940
indkey,
40-
indpred is not null as has_predicate,
41-
pg_get_indexdef(indexrelid) as indexdef
41+
indpred is not null as has_predicate
4242
from pg_index
4343
join pg_class on indexrelid = pg_class.oid
44-
where indisvalid
44+
where indisvalid and pg_class.relkind = 'i' and pg_class.relpages > 10
4545
), fk_index_match as (
4646
select
4747
fk_list.*,
4848
indexid,
4949
indexname,
5050
indkey::int[] as indexatts,
5151
has_predicate,
52-
indexdef,
5352
array_length(key_cols, 1) as fk_colcount,
5453
array_length(indkey,1) as index_colcount,
55-
round(pg_relation_size(conrelid)/(1024^2)::numeric) as table_mb,
54+
relpages,
5655
cols_list
5756
from fk_list
5857
join fk_cols_list using (fkoid)
5958
left join index_list on
6059
conrelid = indrelid
6160
and (indkey::int2[])[0:(array_length(key_cols,1) -1)] operator(pg_catalog.@>) key_cols
62-
6361
), fk_perfect_match as (
6462
select fkoid
6563
from fk_index_match
6664
where
6765
(index_colcount - 1) <= fk_colcount
6866
and not has_predicate
69-
and indexdef like '%USING btree%'
7067
), fk_index_check as (
7168
select 'no index' as issue, *, 1 as issue_sort
7269
from fk_index_match
@@ -82,14 +79,15 @@ with data as (
8279
fkoid,
8380
tabstats.relname as parent_name,
8481
(n_tup_ins + n_tup_upd + n_tup_del + n_tup_hot_upd) as parent_writes,
85-
round(pg_relation_size(parentid)/(1024^2)::numeric) as parent_mb
82+
fk_list.relpages
8683
from pg_stat_user_tables as tabstats
8784
join fk_list on relid = parentid
8885
), fk_table_stats as (
8986
select
9087
fkoid,
9188
(n_tup_ins + n_tup_upd + n_tup_del + n_tup_hot_upd) as writes,
92-
seq_scan as table_scans
89+
seq_scan as table_scans,
90+
relpages
9391
from pg_stat_user_tables as tabstats
9492
join fk_list on relid = conrelid
9593
)
@@ -98,29 +96,41 @@ with data as (
9896
relname as table_name,
9997
conname as fk_name,
10098
issue,
101-
table_mb,
99+
conrelid,
102100
writes,
103101
table_scans,
104102
parent_name,
105-
parent_mb,
103+
parentid,
106104
parent_writes,
107105
cols_list,
108-
indexdef
106+
indexid
109107
from fk_index_check
110108
join parent_table_stats using (fkoid)
111109
join fk_table_stats using (fkoid)
112110
where
113-
table_mb > 9
111+
fk_table_stats.relpages > 100
114112
and (
115113
writes > 1000
116114
or parent_writes > 1000
117-
or parent_mb > 10
115+
or parent_table_stats.relpages > 100
118116
)
119-
order by issue_sort, table_mb desc, table_name, fk_name
117+
order by issue_sort, fk_table_stats.relpages desc, table_name, fk_name
120118
),
121119
num_data as (
122-
select row_number() over () num, data.* from data limit ${ROWS_LIMIT}
120+
select row_number() over () num,
121+
schema_name,
122+
table_name,
123+
fk_name,
124+
issue,
125+
round(pg_relation_size(conrelid)/(1024^2)::numeric) as table_mb,
126+
writes,
127+
table_scans,
128+
parent_name,
129+
round(pg_relation_size(parentid)/(1024^2)::numeric) as parent_mb,
130+
parent_writes,
131+
cols_list,
132+
pg_get_indexdef(indexid) as indexdef
133+
from data limit ${ROWS_LIMIT}
123134
)
124135
select json_object_agg(num_data.num, num_data) from num_data
125136
SQL
126-

resources/checks/L001_table_sizes.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ with data as (
1414
from pg_class c
1515
left join pg_namespace n on n.oid = c.relnamespace
1616
where relkind = 'r' and nspname <> 'pg_catalog'
17+
order by c.relpages desc
18+
limit ${ROWS_LIMIT}
1719
), data2 as (
1820
select
1921
null::oid as oid,
@@ -83,7 +85,6 @@ with data as (
8385
ts.*
8486
from tables ts
8587
where "Table" <> '=====TOTAL====='
86-
limit ${ROWS_LIMIT}
8788
), together as (
8889
select * from total
8990
union all

0 commit comments

Comments
 (0)