mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 11:03:36 +08:00
This change refactors the chunk index handling to make better use of standard PostgreSQL catalog information, while removing the hypertable_index metadata table and associated triggers, including those on the chunk_index table. The chunk_index table itself is also simplified. A benefit of this refactoring is that indexes are no longer created using string mangling to construct the CREATE INDEX command for a chunk, based on the string definition of the hypertable index. Instead, indexes are created in C using proper index-related internal data structures. Chunk indexes can now also be renamed and are added in the parent index tablespace. Changing tablespace on a hypertable index also recurses to chunks, as expected. Default indexes that are added when creating a hypertable use the hypertable's tablespace. Creating Hypertable indexes with the CONCURRENTLY modifier is currently blocked, due to unclear semantics regarding concurrent creation over many tables, including how to deal with snapshots.
416 lines
15 KiB
PL/PgSQL
416 lines
15 KiB
PL/PgSQL
-- This file contains utility functions to get the relation size
|
|
-- of hypertables, chunks, and indexes on hypertables.
|
|
|
|
-- Get relation size of hypertable
|
|
-- like pg_relation_size(hypertable)
|
|
-- (https://www.postgresql.org/docs/9.6/static/functions-admin.html#FUNCTIONS-ADMIN-DBSIZE)
|
|
--
|
|
-- main_table - hypertable to get size of
|
|
--
|
|
-- Returns:
|
|
-- table_bytes - Disk space used by main_table (like pg_relation_size(main_table))
|
|
-- index_bytes - Disc space used by indexes
|
|
-- toast_bytes - Disc space of toast tables
|
|
-- total_bytes - Total disk space used by the specified table, including all indexes and TOAST data
|
|
|
|
CREATE OR REPLACE FUNCTION hypertable_relation_size(
|
|
main_table REGCLASS
|
|
)
|
|
RETURNS TABLE (table_bytes BIGINT,
|
|
index_bytes BIGINT,
|
|
toast_bytes BIGINT,
|
|
total_bytes BIGINT
|
|
) LANGUAGE PLPGSQL STABLE
|
|
AS
|
|
$BODY$
|
|
DECLARE
|
|
table_name NAME;
|
|
schema_name NAME;
|
|
BEGIN
|
|
SELECT relname, nspname
|
|
INTO STRICT table_name, schema_name
|
|
FROM pg_class c
|
|
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
|
|
WHERE c.OID = main_table;
|
|
|
|
RETURN QUERY EXECUTE format(
|
|
$$
|
|
SELECT table_bytes,
|
|
index_bytes,
|
|
toast_bytes,
|
|
total_bytes
|
|
FROM (
|
|
SELECT *, total_bytes-index_bytes-COALESCE(toast_bytes,0) AS table_bytes FROM (
|
|
SELECT
|
|
sum(pg_total_relation_size('"' || c.schema_name || '"."' || c.table_name || '"'))::bigint as total_bytes,
|
|
sum(pg_indexes_size('"' || c.schema_name || '"."' || c.table_name || '"'))::bigint AS index_bytes,
|
|
sum(pg_total_relation_size(reltoastrelid))::bigint AS toast_bytes
|
|
FROM
|
|
_timescaledb_catalog.hypertable h,
|
|
_timescaledb_catalog.chunk c,
|
|
pg_class pgc,
|
|
pg_namespace pns
|
|
WHERE h.schema_name = %L
|
|
AND h.table_name = %L
|
|
AND c.hypertable_id = h.id
|
|
AND pgc.relname = h.table_name
|
|
AND pns.oid = pgc.relnamespace
|
|
AND pns.nspname = h.schema_name
|
|
AND relkind = 'r'
|
|
) sub1
|
|
) sub2;
|
|
$$,
|
|
schema_name, table_name);
|
|
|
|
END;
|
|
$BODY$;
|
|
|
|
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 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$;
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.partitioning_column_to_pretty(
|
|
d _timescaledb_catalog.dimension
|
|
)
|
|
RETURNS TEXT LANGUAGE PLPGSQL STABLE AS
|
|
$BODY$
|
|
DECLARE
|
|
BEGIN
|
|
IF d.partitioning_func IS NULL THEN
|
|
RETURN d.column_name;
|
|
ELSE
|
|
RETURN d.partitioning_func_schema || '.' || d.partitioning_func
|
|
|| '(' || d.column_name || ')';
|
|
END IF;
|
|
END
|
|
$BODY$;
|
|
|
|
|
|
-- Get relation size of hypertable
|
|
-- like pg_relation_size(hypertable)
|
|
-- (https://www.postgresql.org/docs/9.6/static/functions-admin.html#FUNCTIONS-ADMIN-DBSIZE)
|
|
--
|
|
-- main_table - hypertable to get size of
|
|
--
|
|
-- Returns:
|
|
-- table_size - Pretty output of table_bytes
|
|
-- index_bytes - Pretty output of index_bytes
|
|
-- toast_bytes - Pretty output of toast_bytes
|
|
-- total_size - Pretty output of total_bytes
|
|
|
|
CREATE OR REPLACE FUNCTION hypertable_relation_size_pretty(
|
|
main_table REGCLASS
|
|
)
|
|
RETURNS TABLE (table_size TEXT,
|
|
index_size TEXT,
|
|
toast_size TEXT,
|
|
total_size TEXT) LANGUAGE PLPGSQL STABLE
|
|
AS
|
|
$BODY$
|
|
DECLARE
|
|
table_name NAME;
|
|
schema_name NAME;
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT pg_size_pretty(table_bytes) as table,
|
|
pg_size_pretty(index_bytes) as index,
|
|
pg_size_pretty(toast_bytes) as toast,
|
|
pg_size_pretty(total_bytes) as total
|
|
FROM hypertable_relation_size(main_table);
|
|
|
|
END;
|
|
$BODY$;
|
|
|
|
|
|
-- Get relation size of the chunks of an hypertable
|
|
-- like pg_relation_size
|
|
-- (https://www.postgresql.org/docs/9.6/static/functions-admin.html#FUNCTIONS-ADMIN-DBSIZE)
|
|
--
|
|
-- main_table - hypertable to get size of
|
|
--
|
|
-- Returns:
|
|
-- chunk_id - Timescaledb id of a chunk
|
|
-- chunk_table - Table used for the chunk
|
|
-- partitioning_columns - Partitioning column names
|
|
-- partitioning_column_types - Type of partitioning columns
|
|
-- partitioning_hash_functions - Hash functions of partitioning columns
|
|
-- ranges - Partition ranges for each dimension of the chunk
|
|
-- table_bytes - Disk space used by main_table
|
|
-- index_bytes - Disk space used by indexes
|
|
-- toast_bytes - Disc space of toast tables
|
|
-- total_bytes - Disk space used in total
|
|
|
|
CREATE OR REPLACE FUNCTION chunk_relation_size(
|
|
main_table REGCLASS
|
|
)
|
|
RETURNS TABLE (chunk_id INT,
|
|
chunk_table TEXT,
|
|
partitioning_columns NAME[],
|
|
partitioning_column_types REGTYPE[],
|
|
partitioning_hash_functions TEXT[],
|
|
ranges int8range[],
|
|
table_bytes BIGINT,
|
|
index_bytes BIGINT,
|
|
toast_bytes BIGINT,
|
|
total_bytes BIGINT)
|
|
LANGUAGE PLPGSQL STABLE
|
|
AS
|
|
$BODY$
|
|
DECLARE
|
|
table_name NAME;
|
|
schema_name NAME;
|
|
BEGIN
|
|
SELECT relname, nspname
|
|
INTO STRICT table_name, schema_name
|
|
FROM pg_class c
|
|
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
|
|
WHERE c.OID = main_table;
|
|
|
|
RETURN QUERY EXECUTE format(
|
|
$$
|
|
|
|
SELECT chunk_id,
|
|
chunk_table,
|
|
partitioning_columns,
|
|
partitioning_column_types,
|
|
partitioning_hash_functions,
|
|
ranges,
|
|
table_bytes,
|
|
index_bytes,
|
|
toast_bytes,
|
|
total_bytes
|
|
FROM (
|
|
SELECT *,
|
|
total_bytes-index_bytes-COALESCE(toast_bytes,0) AS table_bytes
|
|
FROM (
|
|
SELECT c.id as chunk_id,
|
|
'"' || c.schema_name || '"."' || c.table_name || '"' as chunk_table,
|
|
pg_total_relation_size('"' || c.schema_name || '"."' || c.table_name || '"') AS total_bytes,
|
|
pg_indexes_size('"' || c.schema_name || '"."' || c.table_name || '"') AS index_bytes,
|
|
pg_total_relation_size(reltoastrelid) AS toast_bytes,
|
|
array_agg(d.column_name ORDER BY d.interval_length, d.column_name ASC) as partitioning_columns,
|
|
array_agg(d.column_type ORDER BY d.interval_length, d.column_name ASC) as partitioning_column_types,
|
|
array_agg(d.partitioning_func_schema || '.' || d.partitioning_func ORDER BY d.interval_length, d.column_name ASC) as partitioning_hash_functions,
|
|
array_agg(int8range(range_start, range_end) ORDER BY d.interval_length, d.column_name ASC) as ranges
|
|
FROM
|
|
_timescaledb_catalog.hypertable h,
|
|
_timescaledb_catalog.chunk c,
|
|
_timescaledb_catalog.chunk_constraint cc,
|
|
_timescaledb_catalog.dimension d,
|
|
_timescaledb_catalog.dimension_slice ds,
|
|
pg_class pgc,
|
|
pg_namespace pns
|
|
WHERE h.schema_name = %L
|
|
AND h.table_name = %L
|
|
AND pgc.relname = h.table_name
|
|
AND pns.oid = pgc.relnamespace
|
|
AND pns.nspname = h.schema_name
|
|
AND relkind = 'r'
|
|
AND c.hypertable_id = h.id
|
|
AND c.id = cc.chunk_id
|
|
AND cc.dimension_slice_id = ds.id
|
|
AND ds.dimension_id = d.id
|
|
GROUP BY c.id, pgc.reltoastrelid, pgc.oid ORDER BY c.id
|
|
) sub1
|
|
) sub2;
|
|
$$,
|
|
schema_name, table_name);
|
|
|
|
END;
|
|
$BODY$;
|
|
|
|
-- Get relation size of the chunks of an hypertable
|
|
-- like pg_relation_size
|
|
-- (https://www.postgresql.org/docs/9.6/static/functions-admin.html#FUNCTIONS-ADMIN-DBSIZE)
|
|
--
|
|
-- main_table - hypertable to get size of
|
|
--
|
|
-- Returns:
|
|
-- chunk_id - Timescaledb id of a chunk
|
|
-- chunk_table - Table used for the chunk
|
|
-- partitioning_columns - Partitioning column names
|
|
-- partitioning_column_types - Type of partitioning columns
|
|
-- partitioning_hash_functions - Hash functions of partitioning columns
|
|
-- ranges - Partition ranges for each dimension of the chunk
|
|
-- table_size - Pretty output of table_bytes
|
|
-- index_size - Pretty output of index_bytes
|
|
-- toast_size - Pretty output of toast_bytes
|
|
-- total_size - Pretty output of total_bytes
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION chunk_relation_size_pretty(
|
|
main_table REGCLASS
|
|
)
|
|
RETURNS TABLE (chunk_id INT,
|
|
chunk_table TEXT,
|
|
partitioning_columns NAME[],
|
|
partitioning_column_types REGTYPE[],
|
|
partitioning_hash_functions TEXT[],
|
|
ranges TEXT[],
|
|
table_size TEXT,
|
|
index_size TEXT,
|
|
toast_size TEXT,
|
|
total_size TEXT
|
|
)
|
|
LANGUAGE PLPGSQL STABLE
|
|
AS
|
|
$BODY$
|
|
DECLARE
|
|
table_name NAME;
|
|
schema_name NAME;
|
|
BEGIN
|
|
SELECT relname, nspname
|
|
INTO STRICT table_name, schema_name
|
|
FROM pg_class c
|
|
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
|
|
WHERE c.OID = main_table;
|
|
|
|
RETURN QUERY EXECUTE format(
|
|
$$
|
|
|
|
SELECT chunk_id,
|
|
chunk_table,
|
|
partitioning_columns,
|
|
partitioning_column_types,
|
|
partitioning_functions,
|
|
ranges,
|
|
pg_size_pretty(table_bytes) AS table,
|
|
pg_size_pretty(index_bytes) AS index,
|
|
pg_size_pretty(toast_bytes) AS toast,
|
|
pg_size_pretty(total_bytes) AS total
|
|
FROM (
|
|
SELECT *,
|
|
total_bytes-index_bytes-COALESCE(toast_bytes,0) AS table_bytes
|
|
FROM (
|
|
SELECT c.id as chunk_id,
|
|
'"' || c.schema_name || '"."' || c.table_name || '"' as chunk_table,
|
|
pg_total_relation_size('"' || c.schema_name || '"."' || c.table_name || '"') AS total_bytes,
|
|
pg_indexes_size('"' || c.schema_name || '"."' || c.table_name || '"') AS index_bytes,
|
|
pg_total_relation_size(reltoastrelid) AS toast_bytes,
|
|
array_agg(d.column_name ORDER BY d.interval_length, d.column_name ASC) as partitioning_columns,
|
|
array_agg(d.column_type ORDER BY d.interval_length, d.column_name ASC) as partitioning_column_types,
|
|
array_agg(d.partitioning_func_schema || '.' || d.partitioning_func ORDER BY d.interval_length, d.column_name ASC) as partitioning_functions,
|
|
array_agg('[' || _timescaledb_internal.range_value_to_pretty(range_start, column_type) ||
|
|
',' ||
|
|
_timescaledb_internal.range_value_to_pretty(range_end, column_type) || ')' ORDER BY d.interval_length, d.column_name ASC) as ranges
|
|
FROM
|
|
_timescaledb_catalog.hypertable h,
|
|
_timescaledb_catalog.chunk c,
|
|
_timescaledb_catalog.chunk_constraint cc,
|
|
_timescaledb_catalog.dimension d,
|
|
_timescaledb_catalog.dimension_slice ds,
|
|
pg_class pgc,
|
|
pg_namespace pns
|
|
WHERE h.schema_name = %L
|
|
AND h.table_name = %L
|
|
AND pgc.relname = h.table_name
|
|
AND pns.oid = pgc.relnamespace
|
|
AND pns.nspname = h.schema_name
|
|
AND relkind = 'r'
|
|
AND c.hypertable_id = h.id
|
|
AND c.id = cc.chunk_id
|
|
AND cc.dimension_slice_id = ds.id
|
|
AND ds.dimension_id = d.id
|
|
GROUP BY c.id, pgc.reltoastrelid, pgc.oid ORDER BY c.id
|
|
) sub1
|
|
) sub2;
|
|
$$,
|
|
schema_name, table_name);
|
|
|
|
END;
|
|
$BODY$;
|
|
|
|
|
|
-- Get sizes of indexes on a hypertable
|
|
--
|
|
-- main_table - hypertable to get index sizes of
|
|
--
|
|
-- Returns:
|
|
-- index_name - index on hyper table
|
|
-- total_bytes - size of index on disk
|
|
|
|
CREATE OR REPLACE FUNCTION indexes_relation_size(
|
|
main_table REGCLASS
|
|
)
|
|
RETURNS TABLE (index_name TEXT,
|
|
total_bytes BIGINT)
|
|
LANGUAGE PLPGSQL STABLE
|
|
AS
|
|
$BODY$
|
|
<<main>>
|
|
DECLARE
|
|
table_name NAME;
|
|
schema_name NAME;
|
|
BEGIN
|
|
SELECT relname, nspname
|
|
INTO STRICT table_name, schema_name
|
|
FROM pg_class c
|
|
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
|
|
WHERE c.OID = main_table;
|
|
|
|
RETURN QUERY
|
|
SELECT h.schema_name || '.' || ci.hypertable_index_name,
|
|
sum(pg_relation_size(c.oid))::bigint
|
|
FROM
|
|
pg_class c,
|
|
pg_namespace n,
|
|
_timescaledb_catalog.hypertable h,
|
|
_timescaledb_catalog.chunk ch,
|
|
_timescaledb_catalog.chunk_index ci
|
|
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 = main.schema_name
|
|
AND h.table_name = main.table_name
|
|
GROUP BY h.schema_name, ci.hypertable_index_name;
|
|
END;
|
|
$BODY$;
|
|
|
|
|
|
-- Get sizes of indexes on a hypertable
|
|
--
|
|
-- main_table - hypertable to get index sizes of
|
|
--
|
|
-- Returns:
|
|
-- index_name - index on hyper table
|
|
-- total_size - pretty output of total_bytes
|
|
|
|
CREATE OR REPLACE FUNCTION indexes_relation_size_pretty(
|
|
main_table REGCLASS
|
|
)
|
|
RETURNS TABLE (index_name TEXT,
|
|
total_size TEXT) LANGUAGE PLPGSQL STABLE
|
|
AS
|
|
$BODY$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT s.index_name,
|
|
pg_size_pretty(s.total_bytes)
|
|
FROM indexes_relation_size(main_table) s;
|
|
END;
|
|
$BODY$;
|