timescaledb/sql/size_utils.sql
shhnwz 699fcf48aa Stats improvement for Uncompressed Chunks
During the compression autovacuum use to be disabled for uncompressed
chunk and enable after decompression. This leads to postgres
maintainence issue. Let's not disable autovacuum for uncompressed
chunk anymore. Let postgres take care of the stats in its natural way.

Fixes #309
2023-03-22 23:51:13 +05:30

831 lines
32 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_internal.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 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 LATERAL _timescaledb_internal.relation_size(
format('%I.%I'::text, c.schema_name, c.table_name)::regclass) AS relsize ON TRUE
LEFT JOIN _timescaledb_catalog.chunk comp ON comp.id = c.compressed_chunk_id
LEFT JOIN LATERAL _timescaledb_internal.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_internal.data_node_hypertable_info(
node_name NAME,
schema_name_in name,
table_name_in name
)
RETURNS TABLE (
table_bytes bigint,
index_bytes bigint,
toast_bytes bigint,
total_bytes bigint)
AS '@MODULE_PATHNAME@', 'ts_dist_remote_hypertable_info' LANGUAGE C VOLATILE STRICT;
CREATE OR REPLACE FUNCTION _timescaledb_internal.data_node_chunk_info(
node_name NAME,
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)
AS '@MODULE_PATHNAME@', 'ts_dist_remote_chunk_info' LANGUAGE C VOLATILE STRICT;
CREATE OR REPLACE FUNCTION _timescaledb_internal.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
JOIN LATERAL _timescaledb_internal.relation_size(
format('%I.%I', schema_name, table_name)::regclass) 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;
CREATE OR REPLACE FUNCTION _timescaledb_internal.hypertable_remote_size(
schema_name_in name,
table_name_in name)
RETURNS TABLE (
table_bytes bigint,
index_bytes bigint,
toast_bytes bigint,
total_bytes bigint,
node_name NAME)
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
SELECT
sum(entry.table_bytes)::bigint AS table_bytes,
sum(entry.index_bytes)::bigint AS index_bytes,
sum(entry.toast_bytes)::bigint AS toast_bytes,
sum(entry.total_bytes)::bigint AS total_bytes,
srv.node_name
FROM (
SELECT
s.node_name
FROM
_timescaledb_catalog.hypertable AS ht,
_timescaledb_catalog.hypertable_data_node AS s
WHERE
ht.schema_name = schema_name_in
AND ht.table_name = table_name_in
AND s.hypertable_id = ht.id
) AS srv
LEFT OUTER JOIN LATERAL _timescaledb_internal.data_node_hypertable_info(
srv.node_name, schema_name_in, table_name_in) entry ON TRUE
GROUP BY srv.node_name;
$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;
is_distributed BOOL = FALSE;
BEGIN
SELECT relname, nspname, replication_factor > 0
INTO table_name, schema_name, is_distributed
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, replication_factor > 0
INTO schema_name, table_name, is_distributed
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;
CASE WHEN is_distributed THEN
RETURN QUERY
SELECT *, NULL::name
FROM _timescaledb_internal.hypertable_local_size(schema_name, table_name)
UNION
SELECT *
FROM _timescaledb_internal.hypertable_remote_size(schema_name, table_name);
ELSE
RETURN QUERY
SELECT *, NULL::name
FROM _timescaledb_internal.hypertable_local_size(schema_name, table_name);
END CASE;
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;
CREATE OR REPLACE FUNCTION _timescaledb_internal.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;
---should return same information as chunks_local_size--
CREATE OR REPLACE FUNCTION _timescaledb_internal.chunks_remote_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,
node_name NAME)
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
SELECT
entry.chunk_id,
entry.chunk_schema,
entry.chunk_name,
entry.table_bytes AS table_bytes,
entry.index_bytes AS index_bytes,
entry.toast_bytes AS toast_bytes,
entry.total_bytes AS total_bytes,
srv.node_name
FROM (
SELECT
s.node_name
FROM
_timescaledb_catalog.hypertable AS ht,
_timescaledb_catalog.hypertable_data_node AS s
WHERE
ht.schema_name = schema_name_in
AND ht.table_name = table_name_in
AND s.hypertable_id = ht.id
) AS srv
LEFT OUTER JOIN LATERAL _timescaledb_internal.data_node_chunk_info(
srv.node_name, schema_name_in, table_name_in) entry ON TRUE
WHERE
entry.chunk_name IS NOT NULL;
$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;
is_distributed BOOL;
BEGIN
SELECT relname, nspname, replication_factor > 0
INTO table_name, schema_name, is_distributed
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;
CASE WHEN is_distributed THEN
RETURN QUERY SELECT ch.chunk_schema, ch.chunk_name, ch.table_bytes, ch.index_bytes,
ch.toast_bytes, ch.total_bytes, ch.node_name
FROM _timescaledb_internal.chunks_remote_size(schema_name, table_name) ch;
ELSE
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_internal.chunks_local_size(schema_name, table_name) chl;
END CASE;
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
---------- end of detailed size functions ------
CREATE OR REPLACE FUNCTION _timescaledb_internal.range_value_to_pretty(
time_value BIGINT,
column_type REGTYPE
)
RETURNS TEXT LANGUAGE PLPGSQL STABLE AS
$BODY$
DECLARE
BEGIN
IF NOT _timescaledb_internal.dimension_is_finite(time_value) 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_internal.to_timestamp(time_value)); -- microseconds
WHEN 'DATE'::regtype THEN
RETURN format('%L', timezone('UTC',_timescaledb_internal.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
local_table_name NAME = NULL;
local_schema_name NAME = NULL;
is_distributed BOOL = FALSE;
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
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_internal.get_approx_row_count(relation);
WITH compressed_hypertable AS (SELECT table_name, schema_name FROM _timescaledb_catalog.hypertable ht
WHERE ht.id = local_compressed_hypertable_id)
SELECT c.oid INTO compressed_hypertable_oid FROM pg_class c
INNER JOIN compressed_hypertable h ON (c.relname = h.table_name)
INNER JOIN pg_namespace n ON (n.nspname = h.schema_name);
compressed_row_count = _timescaledb_internal.get_approx_row_count(compressed_hypertable_oid);
RETURN (uncompressed_row_count + (compressed_row_count * max_compressed_row_count));
ELSE
uncompressed_row_count = _timescaledb_internal.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';
WITH compressed_ns_oid AS ( SELECT table_name, oid FROM _timescaledb_catalog.chunk ch INNER JOIN pg_namespace ns ON
(ch.id = local_compressed_chunk_id and ch.schema_name = ns.nspname))
SELECT c.oid FROM pg_class c INNER JOIN compressed_ns_oid
ON ( c.relnamespace = compressed_ns_oid.oid AND c.relname = compressed_ns_oid.table_name)
INTO local_compressed_chunk_oid;
uncompressed_row_count = _timescaledb_internal.get_approx_row_count(relation);
compressed_row_count = _timescaledb_internal.get_approx_row_count(local_compressed_chunk_oid);
RETURN uncompressed_row_count + (compressed_row_count * max_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_internal.get_approx_row_count(relation);
RETURN uncompressed_row_count;
ELSE
-- 'compressed chunk only #4';
compressed_row_count = _timescaledb_internal.get_approx_row_count(relation) * max_compressed_row_count;
RETURN compressed_row_count;
END IF;
END IF;
-- Check for input relation is Plain RELATION
uncompressed_row_count = _timescaledb_internal.get_approx_row_count(relation);
RETURN uncompressed_row_count;
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
CREATE OR REPLACE FUNCTION _timescaledb_internal.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_internal.data_node_compressed_chunk_stats (node_name name, 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
)
AS '@MODULE_PATHNAME@' , 'ts_dist_remote_compressed_chunk_info' LANGUAGE C VOLATILE STRICT;
CREATE OR REPLACE FUNCTION _timescaledb_internal.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;
CREATE OR REPLACE FUNCTION _timescaledb_internal.compressed_chunk_remote_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,
node_name name)
LANGUAGE SQL
STABLE STRICT
AS
$BODY$
SELECT
ch.*,
srv.node_name
FROM (
SELECT
s.node_name
FROM
_timescaledb_catalog.hypertable AS ht,
_timescaledb_catalog.hypertable_data_node AS s
WHERE
ht.schema_name = schema_name_in
AND ht.table_name = table_name_in
AND s.hypertable_id = ht.id) AS srv
LEFT OUTER JOIN LATERAL _timescaledb_internal.data_node_compressed_chunk_stats (
srv.node_name, schema_name_in, table_name_in) ch ON TRUE
WHERE ch.chunk_name IS NOT NULL;
$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;
is_distributed bool;
BEGIN
SELECT
relname,
nspname,
replication_factor > 0
INTO
table_name,
schema_name,
is_distributed
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;
CASE WHEN is_distributed THEN
RETURN QUERY
SELECT
*
FROM
_timescaledb_internal.compressed_chunk_remote_stats (schema_name, table_name);
ELSE
RETURN QUERY
SELECT
*,
NULL::name
FROM
_timescaledb_internal.compressed_chunk_local_stats (schema_name, table_name);
END CASE;
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_internal.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;
CREATE OR REPLACE FUNCTION _timescaledb_internal.data_node_index_size (node_name name, schema_name_in name, index_name_in name)
RETURNS TABLE ( hypertable_id INTEGER, total_bytes BIGINT)
AS '@MODULE_PATHNAME@' , 'ts_dist_remote_hypertable_index_info' LANGUAGE C VOLATILE STRICT;
CREATE OR REPLACE FUNCTION _timescaledb_internal.indexes_remote_size(
schema_name_in NAME,
table_name_in NAME,
index_name_in NAME
)
RETURNS BIGINT
LANGUAGE SQL VOLATILE STRICT AS
$BODY$
SELECT
sum(entry.total_bytes)::bigint AS total_bytes
FROM (
SELECT
s.node_name
FROM
_timescaledb_catalog.hypertable AS ht,
_timescaledb_catalog.hypertable_data_node AS s
WHERE
ht.schema_name = schema_name_in
AND ht.table_name = table_name_in
AND s.hypertable_id = ht.id
) AS srv
JOIN LATERAL _timescaledb_internal.data_node_index_size(
srv.node_name, schema_name_in, index_name_in) entry ON TRUE;
$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;
is_distributed BOOL;
ht_id INTEGER;
index_bytes BIGINT;
BEGIN
SELECT c.relname, cl.relname, nsp.nspname, ht.replication_factor > 0
INTO ht_index_name, ht_name, ht_schema_name, is_distributed
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_internal.indexes_local_size(ht_schema_name, ht_index_name) il;
IF index_bytes IS NULL THEN
index_bytes = 0;
END IF;
-- Add size from data nodes
IF is_distributed THEN
index_bytes = index_bytes + _timescaledb_internal.indexes_remote_size(ht_schema_name, ht_name, ht_index_name);
END IF;
RETURN index_bytes;
END;
$BODY$ SET search_path TO pg_catalog, pg_temp;
-------------End index size for hypertables -------