timescaledb/sql/size_utils.sql
Nikhil Sontakke 2b8f98c616 Support approximate hypertable size
If a lot of chunks are involved then the current pl/pgsql function
to compute the size of each chunk via a nested loop is pretty slow.
Additionally, the current functionality makes a system call to get the
file size on disk for each chunk everytime this function is called.
That again slows things down. We now have an approximate function which
is implemented in C to avoid the issues in the pl/pgsql function.
Additionally, this function also uses per backend caching using the
smgr layer to compute the approximate size cheaply. The PG cache
invalidation clears off the cached size for a chunk when DML happens
into it. That size cache is thus able to get the latest size in a
matter of minutes. Also, due to the backend caching, any long running
session will only fetch latest data for new or modified chunks and can
use the cached data (which is calculated afresh the first time around)
effectively for older chunks.
2024-02-01 13:25:41 +05:30

672 lines
27 KiB
PL/PgSQL

-- This file and its contents are licensed under the Apache License 2.0.
-- Please see the included NOTICE for copyright information and
-- LICENSE-APACHE for a copy of the license.
-- This file contains utility functions to get the relation size
-- of hypertables, chunks, and indexes on hypertables.
CREATE OR REPLACE FUNCTION _timescaledb_functions.relation_size(relation REGCLASS)
RETURNS TABLE (total_size BIGINT, heap_size BIGINT, index_size BIGINT, toast_size BIGINT)
AS '@MODULE_PATHNAME@', 'ts_relation_size' LANGUAGE C VOLATILE;
CREATE OR REPLACE FUNCTION _timescaledb_functions.relation_approximate_size(relation REGCLASS)
RETURNS TABLE (total_size BIGINT, heap_size BIGINT, index_size BIGINT, toast_size BIGINT)
AS '@MODULE_PATHNAME@', 'ts_relation_approximate_size' LANGUAGE C STRICT VOLATILE;
CREATE OR REPLACE VIEW _timescaledb_internal.hypertable_chunk_local_size AS
SELECT
h.schema_name AS hypertable_schema,
h.table_name AS hypertable_name,
h.id AS hypertable_id,
c.id AS chunk_id,
c.schema_name AS chunk_schema,
c.table_name AS chunk_name,
COALESCE((relsize).total_size, 0) AS total_bytes,
COALESCE((relsize).heap_size, 0) AS heap_bytes,
COALESCE((relsize).index_size, 0) AS index_bytes,
COALESCE((relsize).toast_size, 0) AS toast_bytes,
COALESCE((relcompsize).total_size, 0) AS compressed_total_size,
COALESCE((relcompsize).heap_size, 0) AS compressed_heap_size,
COALESCE((relcompsize).index_size, 0) AS compressed_index_size,
COALESCE((relcompsize).toast_size, 0) AS compressed_toast_size
FROM
_timescaledb_catalog.hypertable h
JOIN _timescaledb_catalog.chunk c ON h.id = c.hypertable_id
AND c.dropped IS FALSE
JOIN pg_class cl ON cl.relname = c.table_name AND cl.relkind = 'r'
JOIN pg_namespace n ON n.oid = cl.relnamespace
AND n.nspname = c.schema_name
JOIN LATERAL _timescaledb_functions.relation_size(cl.oid) AS relsize ON TRUE
LEFT JOIN _timescaledb_catalog.chunk comp ON comp.id = c.compressed_chunk_id
LEFT JOIN LATERAL _timescaledb_functions.relation_size(
CASE WHEN comp.schema_name IS NOT NULL AND comp.table_name IS NOT NULL THEN
format('%I.%I', comp.schema_name, comp.table_name)::regclass
ELSE
NULL::regclass
END
) AS relcompsize ON TRUE;
GRANT SELECT ON _timescaledb_internal.hypertable_chunk_local_size TO PUBLIC;
CREATE OR REPLACE FUNCTION _timescaledb_functions.hypertable_local_size(
schema_name_in name,
table_name_in name)
RETURNS TABLE (
table_bytes BIGINT,
index_bytes BIGINT,
toast_bytes BIGINT,
total_bytes BIGINT)
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
/* get the main hypertable id and sizes */
WITH _hypertable_sizes AS (
SELECT
id,
COALESCE((relsize).total_size, 0) AS total_bytes,
COALESCE((relsize).heap_size, 0) AS heap_bytes,
COALESCE((relsize).index_size, 0) AS index_bytes,
COALESCE((relsize).toast_size, 0) AS toast_bytes,
0::BIGINT AS compressed_total_size,
0::BIGINT AS compressed_index_size,
0::BIGINT AS compressed_toast_size,
0::BIGINT AS compressed_heap_size
FROM
_timescaledb_catalog.hypertable ht
JOIN pg_class c ON relname = ht.table_name AND c.relkind = 'r'
JOIN pg_namespace n ON n.oid = c.relnamespace
AND n.nspname = ht.schema_name
JOIN LATERAL _timescaledb_functions.relation_size(c.oid) AS relsize ON TRUE
WHERE
schema_name = schema_name_in
AND table_name = table_name_in
),
/* calculate the size of the hypertable chunks */
_chunk_sizes AS (
SELECT
chunk_id,
COALESCE(ch.total_bytes, 0) AS total_bytes,
COALESCE(ch.heap_bytes, 0) AS heap_bytes,
COALESCE(ch.index_bytes, 0) AS index_bytes,
COALESCE(ch.toast_bytes, 0) AS toast_bytes,
COALESCE(ch.compressed_total_size, 0) AS compressed_total_size,
COALESCE(ch.compressed_index_size, 0) AS compressed_index_size,
COALESCE(ch.compressed_toast_size, 0) AS compressed_toast_size,
COALESCE(ch.compressed_heap_size, 0) AS compressed_heap_size
FROM
_timescaledb_internal.hypertable_chunk_local_size ch
JOIN _hypertable_sizes ht ON ht.id = ch.hypertable_id
WHERE hypertable_schema = schema_name_in
AND hypertable_name = table_name_in
)
/* calculate the SUM of the hypertable and chunk sizes */
SELECT
(SUM(heap_bytes) + SUM(compressed_heap_size))::BIGINT AS heap_bytes,
(SUM(index_bytes) + SUM(compressed_index_size))::BIGINT AS index_bytes,
(SUM(toast_bytes) + SUM(compressed_toast_size))::BIGINT AS toast_bytes,
(SUM(total_bytes) + SUM(compressed_total_size))::BIGINT AS total_bytes
FROM
(SELECT * FROM _hypertable_sizes
UNION ALL
SELECT * FROM _chunk_sizes) AS sizes;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Get relation size of hypertable
-- like pg_relation_size(hypertable)
--
-- hypertable - hypertable to get size of
--
-- Returns:
-- table_bytes - Disk space used by hypertable (like pg_relation_size(hypertable))
-- index_bytes - Disk space used by indexes
-- toast_bytes - Disk space of toast tables
-- total_bytes - Total disk space used by the specified table, including all indexes and TOAST data
CREATE OR REPLACE FUNCTION @extschema@.hypertable_detailed_size(
hypertable REGCLASS)
RETURNS TABLE (table_bytes BIGINT,
index_bytes BIGINT,
toast_bytes BIGINT,
total_bytes BIGINT,
node_name NAME)
LANGUAGE PLPGSQL VOLATILE STRICT AS
$BODY$
DECLARE
table_name NAME = NULL;
schema_name NAME = NULL;
BEGIN
SELECT relname, nspname
INTO table_name, schema_name
FROM pg_class c
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
INNER JOIN _timescaledb_catalog.hypertable ht ON (ht.schema_name = n.nspname AND ht.table_name = c.relname)
WHERE c.OID = hypertable;
IF table_name IS NULL THEN
SELECT h.schema_name, h.table_name
INTO schema_name, table_name
FROM pg_class c
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
INNER JOIN _timescaledb_catalog.continuous_agg a ON (a.user_view_schema = n.nspname AND a.user_view_name = c.relname)
INNER JOIN _timescaledb_catalog.hypertable h ON h.id = a.mat_hypertable_id
WHERE c.OID = hypertable;
IF table_name IS NULL THEN
RETURN;
END IF;
END IF;
RETURN QUERY
SELECT *, NULL::name
FROM _timescaledb_functions.hypertable_local_size(schema_name, table_name);
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
--- returns total-bytes for a hypertable (includes table + index)
CREATE OR REPLACE FUNCTION @extschema@.hypertable_size(
hypertable REGCLASS)
RETURNS BIGINT
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
-- One row per data node is returned (in case of a distributed
-- hypertable), so sum them up:
SELECT sum(total_bytes)::bigint
FROM @extschema@.hypertable_detailed_size(hypertable);
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Get approximate relation size of hypertable
--
-- hypertable - hypertable to get approximate size of
--
-- Returns:
-- table_bytes - Approximate disk space used by hypertable
-- index_bytes - Approximate disk space used by indexes
-- toast_bytes - Approximate disk space of toast tables
-- total_bytes - Total approximate disk space used by the specified table, including all indexes and TOAST data
CREATE OR REPLACE FUNCTION @extschema@.hypertable_approximate_detailed_size(relation REGCLASS)
RETURNS TABLE (table_bytes BIGINT, index_bytes BIGINT, toast_bytes BIGINT, total_bytes BIGINT)
AS '@MODULE_PATHNAME@', 'ts_hypertable_approximate_size' LANGUAGE C VOLATILE;
--- returns approximate total-bytes for a hypertable (includes table + index)
CREATE OR REPLACE FUNCTION @extschema@.hypertable_approximate_size(
hypertable REGCLASS)
RETURNS BIGINT
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
SELECT sum(total_bytes)::bigint
FROM @extschema@.hypertable_approximate_detailed_size(hypertable);
$BODY$ SET search_path TO pg_catalog, pg_temp;
CREATE OR REPLACE FUNCTION _timescaledb_functions.chunks_local_size(
schema_name_in name,
table_name_in name)
RETURNS TABLE (
chunk_id integer,
chunk_schema NAME,
chunk_name NAME,
table_bytes bigint,
index_bytes bigint,
toast_bytes bigint,
total_bytes bigint)
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
SELECT
ch.chunk_id,
ch.chunk_schema,
ch.chunk_name,
(ch.total_bytes - COALESCE( ch.index_bytes , 0 ) - COALESCE( ch.toast_bytes, 0 ) + COALESCE( ch.compressed_heap_size , 0 ))::bigint as heap_bytes,
(COALESCE( ch.index_bytes, 0 ) + COALESCE( ch.compressed_index_size , 0) )::bigint as index_bytes,
(COALESCE( ch.toast_bytes, 0 ) + COALESCE( ch.compressed_toast_size, 0 ))::bigint as toast_bytes,
(ch.total_bytes + COALESCE( ch.compressed_total_size, 0 ))::bigint as total_bytes
FROM
_timescaledb_internal.hypertable_chunk_local_size ch
WHERE
ch.hypertable_schema = schema_name_in
AND ch.hypertable_name = table_name_in;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Get relation size of the chunks of an hypertable
-- hypertable - hypertable to get size of
--
-- Returns:
-- chunk_schema - schema name for chunk
-- chunk_name - chunk table name
-- table_bytes - Disk space used by chunk table
-- index_bytes - Disk space used by indexes
-- toast_bytes - Disk space of toast tables
-- total_bytes - Disk space used in total
-- node_name - node on which chunk lives if this is
-- a distributed hypertable.
CREATE OR REPLACE FUNCTION @extschema@.chunks_detailed_size(
hypertable REGCLASS
)
RETURNS TABLE (
chunk_schema NAME,
chunk_name NAME,
table_bytes BIGINT,
index_bytes BIGINT,
toast_bytes BIGINT,
total_bytes BIGINT,
node_name NAME)
LANGUAGE PLPGSQL VOLATILE STRICT AS
$BODY$
DECLARE
table_name NAME;
schema_name NAME;
BEGIN
SELECT relname, nspname
INTO table_name, schema_name
FROM pg_class c
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
INNER JOIN _timescaledb_catalog.hypertable ht ON (ht.schema_name = n.nspname AND ht.table_name = c.relname)
WHERE c.OID = hypertable;
IF table_name IS NULL THEN
SELECT h.schema_name, h.table_name
INTO schema_name, table_name
FROM pg_class c
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
INNER JOIN _timescaledb_catalog.continuous_agg a ON (a.user_view_schema = n.nspname AND a.user_view_name = c.relname)
INNER JOIN _timescaledb_catalog.hypertable h ON h.id = a.mat_hypertable_id
WHERE c.OID = hypertable;
IF table_name IS NULL THEN
RETURN;
END IF;
END IF;
RETURN QUERY SELECT chl.chunk_schema, chl.chunk_name, chl.table_bytes, chl.index_bytes,
chl.toast_bytes, chl.total_bytes, NULL::NAME
FROM _timescaledb_functions.chunks_local_size(schema_name, table_name) chl;
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
---------- end of detailed size functions ------
CREATE OR REPLACE FUNCTION _timescaledb_functions.range_value_to_pretty(
time_value BIGINT,
column_type REGTYPE
)
RETURNS TEXT LANGUAGE PLPGSQL STABLE AS
$BODY$
DECLARE
BEGIN
IF NOT (time_value > (-9223372036854775808)::bigint AND
time_value < 9223372036854775807::bigint) THEN
RETURN '';
END IF;
IF time_value IS NULL THEN
RETURN format('%L', NULL);
END IF;
CASE column_type
WHEN 'BIGINT'::regtype, 'INTEGER'::regtype, 'SMALLINT'::regtype THEN
RETURN format('%L', time_value); -- scale determined by user.
WHEN 'TIMESTAMP'::regtype, 'TIMESTAMPTZ'::regtype THEN
-- assume time_value is in microsec
RETURN format('%1$L', _timescaledb_functions.to_timestamp(time_value)); -- microseconds
WHEN 'DATE'::regtype THEN
RETURN format('%L', timezone('UTC',_timescaledb_functions.to_timestamp(time_value))::date);
ELSE
RETURN time_value;
END CASE;
END
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Convenience function to return approximate row count
--
-- relation - table or hypertable to get approximate row count for
--
-- Returns:
-- Estimated number of rows according to catalog tables
CREATE OR REPLACE FUNCTION @extschema@.approximate_row_count(relation REGCLASS)
RETURNS BIGINT
LANGUAGE PLPGSQL VOLATILE STRICT AS
$BODY$
DECLARE
mat_ht REGCLASS = NULL;
local_table_name NAME = NULL;
local_schema_name NAME = NULL;
is_compressed BOOL = FALSE;
uncompressed_row_count BIGINT = 0;
compressed_row_count BIGINT = 0;
local_compressed_hypertable_id INTEGER = 0;
local_compressed_chunk_id INTEGER = 0;
compressed_hypertable_oid OID;
local_compressed_chunk_oid OID;
max_compressed_row_count BIGINT = 1000;
is_compressed_chunk INTEGER;
BEGIN
-- Check if input relation is continuous aggregate view then
-- get the corresponding materialized hypertable and schema name
SELECT format('%I.%I', ht.schema_name, ht.table_name)::regclass
INTO mat_ht
FROM pg_class c
JOIN pg_namespace n ON (n.OID = c.relnamespace)
JOIN _timescaledb_catalog.continuous_agg a ON (a.user_view_schema = n.nspname AND a.user_view_name = c.relname)
JOIN _timescaledb_catalog.hypertable ht ON (a.mat_hypertable_id = ht.id)
WHERE c.OID = relation;
IF mat_ht IS NOT NULL THEN
relation = mat_ht;
END IF;
SELECT relname, nspname FROM pg_class c
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
INTO local_table_name, local_schema_name
WHERE c.OID = relation;
-- Check for input relation is Hypertable
IF EXISTS (SELECT 1
FROM _timescaledb_catalog.hypertable WHERE table_name = local_table_name AND schema_name = local_schema_name) THEN
SELECT compressed_hypertable_id FROM _timescaledb_catalog.hypertable INTO local_compressed_hypertable_id
WHERE table_name = local_table_name AND schema_name = local_schema_name;
IF local_compressed_hypertable_id IS NOT NULL THEN
uncompressed_row_count = _timescaledb_functions.get_approx_row_count(relation);
-- use the compression_chunk_size stats to fetch precompressed num rows
SELECT COALESCE(SUM(numrows_pre_compression), 0) FROM _timescaledb_catalog.chunk srcch,
_timescaledb_catalog.compression_chunk_size map, _timescaledb_catalog.hypertable srcht
INTO compressed_row_count
WHERE map.chunk_id = srcch.id
AND srcht.id = srcch.hypertable_id AND srcht.table_name = local_table_name
AND srcht.schema_name = local_schema_name;
RETURN (uncompressed_row_count + compressed_row_count);
ELSE
uncompressed_row_count = _timescaledb_functions.get_approx_row_count(relation);
RETURN uncompressed_row_count;
END IF;
END IF;
-- Check for input relation is CHUNK
IF EXISTS (SELECT 1 FROM _timescaledb_catalog.chunk WHERE table_name = local_table_name AND schema_name = local_schema_name) THEN
with compressed_chunk as (select 1 as is_compressed_chunk from _timescaledb_catalog.chunk c
inner join _timescaledb_catalog.hypertable h on (c.hypertable_id = h.compressed_hypertable_id)
where c.table_name = local_table_name and c.schema_name = local_schema_name ),
chunk_temp as (select compressed_chunk_id from _timescaledb_catalog.chunk c where c.table_name = local_table_name and c.schema_name = local_schema_name)
select ct.compressed_chunk_id, cc.is_compressed_chunk from chunk_temp ct LEFT OUTER JOIN compressed_chunk cc ON 1 = 1
INTO local_compressed_chunk_id, is_compressed_chunk;
-- 'input is chunk #1';
IF is_compressed_chunk IS NULL AND local_compressed_chunk_id IS NOT NULL THEN
-- 'Include both uncompressed and compressed chunk #2';
-- use the compression_chunk_size stats to fetch precompressed num rows
SELECT COALESCE(numrows_pre_compression, 0) FROM _timescaledb_catalog.compression_chunk_size
INTO compressed_row_count
WHERE compressed_chunk_id = local_compressed_chunk_id;
uncompressed_row_count = _timescaledb_functions.get_approx_row_count(relation);
RETURN (uncompressed_row_count + compressed_row_count);
ELSIF is_compressed_chunk IS NULL AND local_compressed_chunk_id IS NULL THEN
-- 'input relation is uncompressed chunk #3';
uncompressed_row_count = _timescaledb_functions.get_approx_row_count(relation);
RETURN uncompressed_row_count;
ELSE
-- 'compressed chunk only #4';
-- use the compression_chunk_size stats to fetch precompressed num rows
SELECT COALESCE(SUM(numrows_pre_compression), 0) FROM _timescaledb_catalog.chunk srcch,
_timescaledb_catalog.compression_chunk_size map INTO compressed_row_count
WHERE map.compressed_chunk_id = srcch.id
AND srcch.table_name = local_table_name AND srcch.schema_name = local_schema_name;
RETURN compressed_row_count;
END IF;
END IF;
-- Check for input relation is Plain RELATION
uncompressed_row_count = _timescaledb_functions.get_approx_row_count(relation);
RETURN uncompressed_row_count;
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
CREATE OR REPLACE FUNCTION _timescaledb_functions.get_approx_row_count(relation REGCLASS)
RETURNS BIGINT
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
WITH RECURSIVE inherited_id(oid) AS
(
SELECT relation
UNION ALL
SELECT i.inhrelid
FROM pg_inherits i
JOIN inherited_id b ON i.inhparent = b.oid
)
-- reltuples for partitioned tables is the sum of it's children in pg14 so we need to filter those out
SELECT COALESCE((SUM(reltuples) FILTER (WHERE reltuples > 0 AND relkind <> 'p')), 0)::BIGINT
FROM inherited_id
JOIN pg_class USING (oid);
$BODY$ SET search_path TO pg_catalog, pg_temp;
-------- stats related to compression ------
CREATE OR REPLACE VIEW _timescaledb_internal.compressed_chunk_stats AS
SELECT
srcht.schema_name AS hypertable_schema,
srcht.table_name AS hypertable_name,
srcch.schema_name AS chunk_schema,
srcch.table_name AS chunk_name,
CASE WHEN srcch.compressed_chunk_id IS NULL THEN
'Uncompressed'::text
ELSE
'Compressed'::text
END AS compression_status,
map.uncompressed_heap_size,
map.uncompressed_index_size,
map.uncompressed_toast_size,
map.uncompressed_heap_size + map.uncompressed_toast_size + map.uncompressed_index_size AS uncompressed_total_size,
map.compressed_heap_size,
map.compressed_index_size,
map.compressed_toast_size,
map.compressed_heap_size + map.compressed_toast_size + map.compressed_index_size AS compressed_total_size
FROM
_timescaledb_catalog.hypertable AS srcht
JOIN _timescaledb_catalog.chunk AS srcch ON srcht.id = srcch.hypertable_id
AND srcht.compressed_hypertable_id IS NOT NULL
AND srcch.dropped = FALSE
LEFT JOIN _timescaledb_catalog.compression_chunk_size map ON srcch.id = map.chunk_id;
GRANT SELECT ON _timescaledb_internal.compressed_chunk_stats TO PUBLIC;
CREATE OR REPLACE FUNCTION _timescaledb_functions.compressed_chunk_local_stats(schema_name_in name, table_name_in name)
RETURNS TABLE (
chunk_schema name,
chunk_name name,
compression_status text,
before_compression_table_bytes bigint,
before_compression_index_bytes bigint,
before_compression_toast_bytes bigint,
before_compression_total_bytes bigint,
after_compression_table_bytes bigint,
after_compression_index_bytes bigint,
after_compression_toast_bytes bigint,
after_compression_total_bytes bigint)
LANGUAGE SQL
STABLE STRICT
AS
$BODY$
SELECT
ch.chunk_schema,
ch.chunk_name,
ch.compression_status,
ch.uncompressed_heap_size,
ch.uncompressed_index_size,
ch.uncompressed_toast_size,
ch.uncompressed_total_size,
ch.compressed_heap_size,
ch.compressed_index_size,
ch.compressed_toast_size,
ch.compressed_total_size
FROM
_timescaledb_internal.compressed_chunk_stats ch
WHERE
ch.hypertable_schema = schema_name_in
AND ch.hypertable_name = table_name_in;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Get per chunk compression statistics for a hypertable that has
-- compression enabled
CREATE OR REPLACE FUNCTION @extschema@.chunk_compression_stats (hypertable REGCLASS)
RETURNS TABLE (
chunk_schema name,
chunk_name name,
compression_status text,
before_compression_table_bytes bigint,
before_compression_index_bytes bigint,
before_compression_toast_bytes bigint,
before_compression_total_bytes bigint,
after_compression_table_bytes bigint,
after_compression_index_bytes bigint,
after_compression_toast_bytes bigint,
after_compression_total_bytes bigint,
node_name name)
LANGUAGE PLPGSQL
STABLE STRICT
AS $BODY$
DECLARE
table_name name;
schema_name name;
BEGIN
SELECT
relname, nspname
INTO
table_name, schema_name
FROM
pg_class c
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
INNER JOIN _timescaledb_catalog.hypertable ht ON (ht.schema_name = n.nspname
AND ht.table_name = c.relname)
WHERE
c.OID = hypertable;
IF table_name IS NULL THEN
RETURN;
END IF;
RETURN QUERY
SELECT
*,
NULL::name
FROM
_timescaledb_functions.compressed_chunk_local_stats(schema_name, table_name);
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Get compression statistics for a hypertable that has
-- compression enabled
CREATE OR REPLACE FUNCTION @extschema@.hypertable_compression_stats (hypertable REGCLASS)
RETURNS TABLE (
total_chunks bigint,
number_compressed_chunks bigint,
before_compression_table_bytes bigint,
before_compression_index_bytes bigint,
before_compression_toast_bytes bigint,
before_compression_total_bytes bigint,
after_compression_table_bytes bigint,
after_compression_index_bytes bigint,
after_compression_toast_bytes bigint,
after_compression_total_bytes bigint,
node_name name)
LANGUAGE SQL
STABLE STRICT
AS
$BODY$
SELECT
count(*)::bigint AS total_chunks,
(count(*) FILTER (WHERE ch.compression_status = 'Compressed'))::bigint AS number_compressed_chunks,
sum(ch.before_compression_table_bytes)::bigint AS before_compression_table_bytes,
sum(ch.before_compression_index_bytes)::bigint AS before_compression_index_bytes,
sum(ch.before_compression_toast_bytes)::bigint AS before_compression_toast_bytes,
sum(ch.before_compression_total_bytes)::bigint AS before_compression_total_bytes,
sum(ch.after_compression_table_bytes)::bigint AS after_compression_table_bytes,
sum(ch.after_compression_index_bytes)::bigint AS after_compression_index_bytes,
sum(ch.after_compression_toast_bytes)::bigint AS after_compression_toast_bytes,
sum(ch.after_compression_total_bytes)::bigint AS after_compression_total_bytes,
ch.node_name
FROM
@extschema@.chunk_compression_stats(hypertable) ch
GROUP BY
ch.node_name;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-------------Get index size for hypertables -------
--schema_name - schema_name for hypertable index
-- index_name - index on hyper table
---note that the query matches against the hypertable's schema name as
-- the input is on the hypertable index and not the chunk index.
CREATE OR REPLACE FUNCTION _timescaledb_functions.indexes_local_size(
schema_name_in NAME,
index_name_in NAME
)
RETURNS TABLE ( hypertable_id INTEGER,
total_bytes BIGINT )
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
WITH chunk_index_size (num_bytes) AS (
SELECT
COALESCE(sum(pg_relation_size(c.oid)), 0)::bigint
FROM
pg_class c,
pg_namespace n,
_timescaledb_catalog.chunk ch,
_timescaledb_catalog.chunk_index ci,
_timescaledb_catalog.hypertable h
WHERE ch.schema_name = n.nspname
AND c.relnamespace = n.oid
AND c.relname = ci.index_name
AND ch.id = ci.chunk_id
AND h.id = ci.hypertable_id
AND h.schema_name = schema_name_in
AND ci.hypertable_index_name = index_name_in
) SELECT
h.id,
-- Add size of index on all chunks + index size on root table
(SELECT num_bytes FROM chunk_index_size) + pg_relation_size(format('%I.%I', schema_name_in, index_name_in)::regclass)::bigint
FROM
pg_class c, pg_index i, _timescaledb_catalog.hypertable h
WHERE
i.indexrelid = format('%I.%I', schema_name_in, index_name_in)::regclass
AND c.oid = i.indrelid
AND h.schema_name = schema_name_in
AND h.table_name = c.relname;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-- Get sizes of indexes on a hypertable
--
-- index_name - index on hyper table
--
-- Returns:
-- total_bytes - size of index on disk
CREATE OR REPLACE FUNCTION @extschema@.hypertable_index_size(
index_name REGCLASS
)
RETURNS BIGINT
LANGUAGE PLPGSQL VOLATILE STRICT AS
$BODY$
DECLARE
ht_index_name NAME;
ht_schema_name NAME;
ht_name NAME;
ht_id INTEGER;
index_bytes BIGINT;
BEGIN
SELECT c.relname, cl.relname, nsp.nspname
INTO ht_index_name, ht_name, ht_schema_name
FROM pg_class c, pg_index cind, pg_class cl,
pg_namespace nsp, _timescaledb_catalog.hypertable ht
WHERE c.oid = cind.indexrelid AND cind.indrelid = cl.oid
AND cl.relnamespace = nsp.oid AND c.oid = index_name
AND ht.schema_name = nsp.nspname ANd ht.table_name = cl.relname;
IF ht_index_name IS NULL THEN
RETURN NULL;
END IF;
-- get the local size or size of access node indexes
SELECT il.total_bytes
INTO index_bytes
FROM _timescaledb_functions.indexes_local_size(ht_schema_name, ht_index_name) il;
IF index_bytes IS NULL THEN
index_bytes = 0;
END IF;
RETURN index_bytes;
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-------------End index size for hypertables -------