mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 01:25:21 +00:00
allow multiple rows TTL with WHERE expression
This commit is contained in:
parent
a8f1786d95
commit
5822ee1f01
@ -44,6 +44,10 @@ TTLBlockInputStream::TTLBlockInputStream(
|
||||
algorithms.emplace_back(std::move(algorithm));
|
||||
}
|
||||
|
||||
for (const auto & where_ttl : metadata_snapshot_->getRowsWhereTTL())
|
||||
algorithms.emplace_back(std::make_unique<TTLDeleteAlgorithm>(
|
||||
where_ttl, old_ttl_infos.rows_where_ttl[where_ttl.result_column], current_time_, force_));
|
||||
|
||||
for (const auto & group_by_ttl : metadata_snapshot_->getGroupByTTLs())
|
||||
algorithms.emplace_back(std::make_unique<TTLAggregationAlgorithm>(
|
||||
group_by_ttl, old_ttl_infos.group_by_ttl[group_by_ttl.result_column], current_time_, force_, header, storage_));
|
||||
|
@ -51,7 +51,11 @@ void TTLDeleteAlgorithm::execute(Block & block)
|
||||
|
||||
void TTLDeleteAlgorithm::finalize(const MutableDataPartPtr & data_part) const
|
||||
{
|
||||
data_part->ttl_infos.table_ttl = new_ttl_info;
|
||||
if (description.where_expression)
|
||||
data_part->ttl_infos.rows_where_ttl[description.result_column] = new_ttl_info;
|
||||
else
|
||||
data_part->ttl_infos.table_ttl = new_ttl_info;
|
||||
|
||||
data_part->ttl_infos.updatePartMinMaxTTL(new_ttl_info.min, new_ttl_info.max);
|
||||
}
|
||||
|
||||
|
@ -1142,6 +1142,12 @@ bool IMergeTreeDataPart::checkAllTTLCalculated(const StorageMetadataPtr & metada
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto & rows_where_desc : metadata_snapshot->getRowsWhereTTL())
|
||||
{
|
||||
if (!ttl_infos.rows_where_ttl.count(rows_where_desc.result_column))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,12 @@ void MergeTreeDataPartTTLInfos::update(const MergeTreeDataPartTTLInfos & other_i
|
||||
updatePartMinMaxTTL(ttl_info.min, ttl_info.max);
|
||||
}
|
||||
|
||||
for (const auto & [name, ttl_info] : other_infos.rows_where_ttl)
|
||||
{
|
||||
rows_where_ttl[name].update(ttl_info);
|
||||
updatePartMinMaxTTL(ttl_info.min, ttl_info.max);
|
||||
}
|
||||
|
||||
for (const auto & [name, ttl_info] : other_infos.group_by_ttl)
|
||||
{
|
||||
group_by_ttl[name].update(ttl_info);
|
||||
@ -91,6 +97,11 @@ void MergeTreeDataPartTTLInfos::read(ReadBuffer & in)
|
||||
const JSON & group_by = json["group_by"];
|
||||
fill_ttl_info_map(group_by, group_by_ttl);
|
||||
}
|
||||
if (json.has("rows_where"))
|
||||
{
|
||||
const JSON & rows_where = json["rows_where"];
|
||||
fill_ttl_info_map(rows_where, rows_where_ttl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -127,61 +138,41 @@ void MergeTreeDataPartTTLInfos::write(WriteBuffer & out) const
|
||||
writeString("}", out);
|
||||
}
|
||||
|
||||
auto write_info_for_expression = [&out](const auto & name, const auto & info)
|
||||
auto write_infos = [&out](const auto & infos, const auto & type, bool is_first)
|
||||
{
|
||||
writeString(R"({"expression":)", out);
|
||||
writeString(doubleQuoteString(name), out);
|
||||
writeString(R"(,"min":)", out);
|
||||
writeIntText(info.min, out);
|
||||
writeString(R"(,"max":)", out);
|
||||
writeIntText(info.max, out);
|
||||
writeString("}", out);
|
||||
if (!is_first)
|
||||
writeString(",", out);
|
||||
|
||||
writeString(type, out);
|
||||
writeString(R"(:[)", out);
|
||||
for (auto it = infos.begin(); it != infos.end(); ++it)
|
||||
{
|
||||
if (it != infos.begin())
|
||||
writeString(",", out);
|
||||
|
||||
writeString(R"({"expression":)", out);
|
||||
writeString(doubleQuoteString(it->first), out);
|
||||
writeString(R"(,"min":)", out);
|
||||
writeIntText(it->second.min, out);
|
||||
writeString(R"(,"max":)", out);
|
||||
writeIntText(it->second.max, out);
|
||||
writeString("}", out);
|
||||
}
|
||||
writeString("]", out);
|
||||
};
|
||||
|
||||
if (!moves_ttl.empty())
|
||||
{
|
||||
if (!columns_ttl.empty() || table_ttl.min)
|
||||
writeString(",", out);
|
||||
writeString(R"("moves":[)", out);
|
||||
for (auto it = moves_ttl.begin(); it != moves_ttl.end(); ++it)
|
||||
{
|
||||
if (it != moves_ttl.begin())
|
||||
writeString(",", out);
|
||||
bool is_first = columns_ttl.empty() && !table_ttl.min;
|
||||
write_infos(moves_ttl, "moves", is_first);
|
||||
|
||||
write_info_for_expression(it->first, it->second);
|
||||
}
|
||||
writeString("]", out);
|
||||
}
|
||||
if (!recompression_ttl.empty())
|
||||
{
|
||||
if (!moves_ttl.empty() || !columns_ttl.empty() || table_ttl.min)
|
||||
writeString(",", out);
|
||||
is_first &= moves_ttl.empty();
|
||||
write_infos(recompression_ttl, "recompression", is_first);
|
||||
|
||||
writeString(R"("recompression":[)", out);
|
||||
for (auto it = recompression_ttl.begin(); it != recompression_ttl.end(); ++it)
|
||||
{
|
||||
if (it != recompression_ttl.begin())
|
||||
writeString(",", out);
|
||||
is_first &= recompression_ttl.empty();
|
||||
write_infos(group_by_ttl, "group_by", is_first);
|
||||
|
||||
write_info_for_expression(it->first, it->second);
|
||||
}
|
||||
writeString("]", out);
|
||||
}
|
||||
if (!group_by_ttl.empty())
|
||||
{
|
||||
if (!moves_ttl.empty() || !columns_ttl.empty() || !recompression_ttl.empty() || table_ttl.min)
|
||||
writeString(",", out);
|
||||
is_first &= group_by_ttl.empty();
|
||||
write_infos(rows_where_ttl, "rows_where", is_first);
|
||||
|
||||
writeString(R"("group_by":[)", out);
|
||||
for (auto it = group_by_ttl.begin(); it != group_by_ttl.end(); ++it)
|
||||
{
|
||||
if (it != group_by_ttl.begin())
|
||||
writeString(",", out);
|
||||
|
||||
write_info_for_expression(it->first, it->second);
|
||||
}
|
||||
writeString("]", out);
|
||||
}
|
||||
writeString("}", out);
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@ struct MergeTreeDataPartTTLInfos
|
||||
time_t part_min_ttl = 0;
|
||||
time_t part_max_ttl = 0;
|
||||
|
||||
TTLInfoMap rows_where_ttl;
|
||||
|
||||
TTLInfoMap moves_ttl;
|
||||
|
||||
TTLInfoMap recompression_ttl;
|
||||
|
@ -379,6 +379,9 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithPa
|
||||
for (const auto & ttl_entry : metadata_snapshot->getGroupByTTLs())
|
||||
updateTTL(ttl_entry, new_data_part->ttl_infos, new_data_part->ttl_infos.group_by_ttl[ttl_entry.result_column], block, true);
|
||||
|
||||
for (const auto & ttl_entry : metadata_snapshot->getRowsWhereTTL())
|
||||
updateTTL(ttl_entry, new_data_part->ttl_infos, new_data_part->ttl_infos.rows_where_ttl[ttl_entry.result_column], block, true);
|
||||
|
||||
for (const auto & [name, ttl_entry] : metadata_snapshot->getColumnTTLs())
|
||||
updateTTL(ttl_entry, new_data_part->ttl_infos, new_data_part->ttl_infos.columns_ttl[name], block, true);
|
||||
|
||||
|
@ -148,6 +148,16 @@ bool StorageInMemoryMetadata::hasRowsTTL() const
|
||||
return table_ttl.rows_ttl.expression != nullptr;
|
||||
}
|
||||
|
||||
TTLDescriptions StorageInMemoryMetadata::getRowsWhereTTL() const
|
||||
{
|
||||
return table_ttl.rows_where_ttl;
|
||||
}
|
||||
|
||||
bool StorageInMemoryMetadata::hasRowsWhereTTL() const
|
||||
{
|
||||
return !table_ttl.rows_where_ttl.empty();
|
||||
}
|
||||
|
||||
TTLDescriptions StorageInMemoryMetadata::getMoveTTLs() const
|
||||
{
|
||||
return table_ttl.move_ttl;
|
||||
|
@ -109,6 +109,9 @@ struct StorageInMemoryMetadata
|
||||
TTLDescription getRowsTTL() const;
|
||||
bool hasRowsTTL() const;
|
||||
|
||||
TTLDescriptions getRowsWhereTTL() const;
|
||||
bool hasRowsWhereTTL() const;
|
||||
|
||||
/// Just wrapper for table TTLs, return moves (to disks or volumes) parts of
|
||||
/// table TTL.
|
||||
TTLDescriptions getMoveTTLs() const;
|
||||
|
@ -260,6 +260,7 @@ TTLDescription TTLDescription::getTTLFromAST(
|
||||
TTLTableDescription::TTLTableDescription(const TTLTableDescription & other)
|
||||
: definition_ast(other.definition_ast ? other.definition_ast->clone() : nullptr)
|
||||
, rows_ttl(other.rows_ttl)
|
||||
, rows_where_ttl(other.rows_where_ttl)
|
||||
, move_ttl(other.move_ttl)
|
||||
, recompression_ttl(other.recompression_ttl)
|
||||
, group_by_ttl(other.group_by_ttl)
|
||||
@ -277,6 +278,7 @@ TTLTableDescription & TTLTableDescription::operator=(const TTLTableDescription &
|
||||
definition_ast.reset();
|
||||
|
||||
rows_ttl = other.rows_ttl;
|
||||
rows_where_ttl = other.rows_where_ttl;
|
||||
move_ttl = other.move_ttl;
|
||||
recompression_ttl = other.recompression_ttl;
|
||||
group_by_ttl = other.group_by_ttl;
|
||||
@ -296,16 +298,24 @@ TTLTableDescription TTLTableDescription::getTTLForTableFromAST(
|
||||
|
||||
result.definition_ast = definition_ast->clone();
|
||||
|
||||
bool seen_delete_ttl = false;
|
||||
bool have_unconditional_delete_ttl = false;
|
||||
for (const auto & ttl_element_ptr : definition_ast->children)
|
||||
{
|
||||
auto ttl = TTLDescription::getTTLFromAST(ttl_element_ptr, columns, context, primary_key);
|
||||
if (ttl.mode == TTLMode::DELETE)
|
||||
{
|
||||
if (seen_delete_ttl)
|
||||
throw Exception("More than one DELETE TTL expression is not allowed", ErrorCodes::BAD_TTL_EXPRESSION);
|
||||
result.rows_ttl = ttl;
|
||||
seen_delete_ttl = true;
|
||||
if (!ttl.where_expression)
|
||||
{
|
||||
if (have_unconditional_delete_ttl)
|
||||
throw Exception("More than one DELETE TTL expression without WHERE expression is not allowed", ErrorCodes::BAD_TTL_EXPRESSION);
|
||||
|
||||
have_unconditional_delete_ttl = true;
|
||||
result.rows_ttl = ttl;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.rows_where_ttl.emplace_back(std::move(ttl));
|
||||
}
|
||||
}
|
||||
else if (ttl.mode == TTLMode::RECOMPRESS)
|
||||
{
|
||||
|
@ -99,9 +99,12 @@ struct TTLTableDescription
|
||||
/// ^~~~~~~~~~~~~~~definition~~~~~~~~~~~~~~~^
|
||||
ASTPtr definition_ast;
|
||||
|
||||
/// Rows removing TTL
|
||||
/// Unconditional main removing rows TTL. Can be only one for table.
|
||||
TTLDescription rows_ttl;
|
||||
|
||||
/// Conditional removing rows TTLs.
|
||||
TTLDescriptions rows_where_ttl;
|
||||
|
||||
/// Moving data TTL (to other disks or volumes)
|
||||
TTLDescriptions move_ttl;
|
||||
|
||||
|
9
tests/queries/0_stateless/01622_multiple_ttls.reference
Normal file
9
tests/queries/0_stateless/01622_multiple_ttls.reference
Normal file
@ -0,0 +1,9 @@
|
||||
1970-10-10 2
|
||||
1970-10-10 5
|
||||
1970-10-10 8
|
||||
2000-10-10 1
|
||||
2000-10-10 2
|
||||
2000-10-10 4
|
||||
2000-10-10 5
|
||||
2000-10-10 7
|
||||
2000-10-10 8
|
20
tests/queries/0_stateless/01622_multiple_ttls.sql
Normal file
20
tests/queries/0_stateless/01622_multiple_ttls.sql
Normal file
@ -0,0 +1,20 @@
|
||||
DROP TABLE IF EXISTS ttl_where;
|
||||
|
||||
CREATE TABLE ttl_where
|
||||
(
|
||||
`d` Date,
|
||||
`i` UInt32
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY tuple()
|
||||
TTL d + toIntervalYear(10) DELETE WHERE i % 3 = 0,
|
||||
d + toIntervalYear(40) DELETE WHERE i % 3 = 1;
|
||||
|
||||
INSERT INTO ttl_where SELECT toDate('2000-10-10'), number FROM numbers(10);
|
||||
INSERT INTO ttl_where SELECT toDate('1970-10-10'), number FROM numbers(10);
|
||||
|
||||
OPTIMIZE TABLE ttl_where FINAL;
|
||||
|
||||
SELECT * FROM ttl_where ORDER BY d, i;
|
||||
|
||||
DROP TABLE ttl_where;
|
Loading…
Reference in New Issue
Block a user