mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-15 01:53:41 +08:00
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.
672 lines
27 KiB
PL/PgSQL
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 -------
|