1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-11-21 09:20:51 +03:00

chore(QA,rules): Added sign-aware getters for min/max PK statistics values and a test for QA with PK-only statistics.

This commit is contained in:
drrtuy
2025-10-22 11:36:43 +00:00
parent 891e97e8c2
commit ca3c797d30
5 changed files with 215 additions and 22 deletions

View File

@@ -333,7 +333,6 @@ int fetchNextRow(uchar* buf, cal_table_info& ti, cal_connection_info* ci, long t
if (ti.tpl_scan_ctx->rowsreturned == 0 &&
(ti.tpl_scan_ctx->traceFlags & execplan::CalpontSelectExecutionPlan::TRACE_TUPLE_OFF))
{
std::cout << "rowGroup->toString() " << rowGroup->toString() << std::endl;
for (uint32_t i = 0; i < rowGroup->getColumnCount(); i++)
{
int oid = rowGroup->getOIDs()[i];

View File

@@ -146,16 +146,36 @@ struct ColumnStatistics
return column;
}
bool hasMinValue() const
{
return minValue != nullptr;
}
bool hasMaxValue() const
{
return maxValue != nullptr;
}
std::optional<int64_t> getIntMinValue() const
{
return (minValue) ? std::optional<int64_t>(minValue->val_int()) : std::nullopt;
}
std::optional<uint64_t> getUIntMinValue() const
{
return (minValue) ? std::optional<uint64_t>(minValue->val_uint()) : std::nullopt;
}
std::optional<int64_t> getIntMaxValue() const
{
return (maxValue) ? std::optional<int64_t>(maxValue->val_int()) : std::nullopt;
}
std::optional<uint64_t> getUIntMaxValue() const
{
return (maxValue) ? std::optional<uint64_t>(maxValue->val_uint()) : std::nullopt;
}
private:
execplan::SimpleColumn column;
std::vector<Histogram_json_hb*> histograms;

View File

@@ -36,6 +36,7 @@
#include "returnedcolumn.h"
#include "simplefilter.h"
#include "existsfilter.h"
#include "sql_statistics.h"
namespace optimizer
{
@@ -180,7 +181,7 @@ execplan::ParseTree* filtersWithNewRange(execplan::SCSEP& csep, execplan::Simple
// Looking for a projected column that comes first in an available index and has EI statistics
// INV nullptr signifies that no suitable column was found
cal_impl_if::ColumnStatistics* chooseKeyColumnAndStatistics(
std::optional<cal_impl_if::ColumnStatistics*> chooseKeyColumnAndStatistics(
execplan::CalpontSystemCatalog::TableAliasName& targetTable, optimizer::RBOptimizerContext& ctx)
{
cal_impl_if::SchemaAndTableName schemaAndTableName = {targetTable.schema, targetTable.table};
@@ -188,19 +189,19 @@ cal_impl_if::ColumnStatistics* chooseKeyColumnAndStatistics(
auto tableColumnsStatisticsOpt = ctx.getGwi().tableStatistics.findStatisticsForATable(schemaAndTableName);
if (!tableColumnsStatisticsOpt)
{
return nullptr;
return std::nullopt;
}
auto tableColumnsStatistics = tableColumnsStatisticsOpt.value();
// TODO this algo now returns the first column and stats
// for it but it should consider all column available
// for it but it should consider all columns available
for (auto& [columnName, columnStatistics] : *tableColumnsStatistics)
{
return &columnStatistics;
return {&columnStatistics};
}
return nullptr;
return std::nullopt;
}
} // namespace details
@@ -222,6 +223,8 @@ uint64_t decodeU64(const std::string& bytes)
return v;
}
// Populates range bounds based on histogram.
// INV histogram != nullptr && histogram->get_json_histogram().empty() is enforced in the caller.
template <typename T>
std::optional<details::FilterRangeBounds<T>> populateRangeBoundsFromHistogram(
cal_impl_if::ColumnStatistics& columnStatistics, size_t maxParallelFactor)
@@ -230,6 +233,7 @@ std::optional<details::FilterRangeBounds<T>> populateRangeBoundsFromHistogram(
auto* histogram = columnStatistics.getHistogram();
// Get parallel factor from context
// TODO These calls are abstraction leak from MDB so better replace with own structs.
size_t numberOfUnionUnits = std::min(histogram->get_json_histogram().size(), maxParallelFactor);
size_t numberOfBucketsPerUnionUnit = histogram->get_json_histogram().size() / numberOfUnionUnits;
@@ -271,14 +275,34 @@ std::optional<details::FilterRangeBounds<T>> populateRangeBoundsFromHistogram(
return bounds;
}
// Populates range bounds based on min/max assuming that the column values are uniformly distributed.
// This statistics is used for PK columns in engine-independent stats in MDB.
// NB The current version supports only numeric columns up to BIGNT.
template <typename T>
std::optional<details::FilterRangeBounds<T>> populateRangeBoundsFromEquallyDistributedRange(
cal_impl_if::ColumnStatistics& columnStatistics, size_t maxParallelFactor)
{
auto minValue = columnStatistics.getIntMinValue().value();
auto maxValue = columnStatistics.getIntMaxValue().value();
// TODOThis should be protected by constexpr checks on types, mb concepts.
T minValue = 0;
T maxValue = 0;
// TODO consider to move into a ColumnStatistics method.
if constexpr (std::is_integral_v<T> && std::is_unsigned_v<T>)
{
minValue = columnStatistics.getUIntMinValue().value();
maxValue = columnStatistics.getUIntMaxValue().value();
}
else if constexpr (std::is_integral_v<T> && std::is_signed_v<T>)
{
minValue = columnStatistics.getIntMinValue().value();
maxValue = columnStatistics.getIntMaxValue().value();
}
if (minValue >= maxValue)
{
return std::nullopt;
}
assert(maxValue >= minValue);
auto distance = maxValue - minValue;
auto step = distance / maxParallelFactor;
@@ -306,14 +330,12 @@ std::optional<details::FilterRangeBounds<T>> populateRangeBounds(
auto* histogram = columnStatistics.getHistogram();
// Guard: empty histogram or no min/max values
if (histogram && histogram->get_json_histogram().empty())
if (histogram && !histogram->get_json_histogram().empty())
{
return populateRangeBoundsFromHistogram<T>(columnStatistics, maxParallelFactor);
}
auto minValue = columnStatistics.getIntMinValue();
auto maxValue = columnStatistics.getIntMaxValue();
if (minValue && maxValue)
if (columnStatistics.hasMinValue() && columnStatistics.hasMaxValue())
{
return populateRangeBoundsFromEquallyDistributedRange<T>(columnStatistics, maxParallelFactor);
}
@@ -330,28 +352,27 @@ execplan::CalpontSelectExecutionPlan::SelectList makeUnionFromTable(
// SC type controls an integral type used to produce suitable filters. The continuation of this function
// should become a template function based on SC type.
auto columnStatisticsPtr = chooseKeyColumnAndStatistics(table, ctx);
if (!columnStatisticsPtr)
auto columnStatisticsOpt = chooseKeyColumnAndStatistics(table, ctx);
if (!columnStatisticsOpt)
{
return unionVec;
}
auto& columnStatistics = *columnStatisticsPtr;
auto& columnStatistics = *columnStatisticsOpt.value();
auto& keyColumn = columnStatistics.getColumn();
// std::cout << "makeUnionFromTable keyColumn " << keyColumn.toString() << std::endl;
std::cout << "makeUnionFromTable RC front " << csep.returnedCols().front()->toString() << std::endl;
size_t configuredMaxParallelFactor = ctx.getCesOptimizationParallelFactor();
// TODO char and other numerical types support
size_t configuredMaxParallelFactor = ctx.getCesOptimizationParallelFactor();
auto boundsOpt = populateRangeBounds<uint64_t>(columnStatistics, configuredMaxParallelFactor);
// TODO signed numerical types support
using SCIntegralType = uint64_t;
auto boundsOpt = populateRangeBounds<SCIntegralType>(columnStatistics, configuredMaxParallelFactor);
if (!boundsOpt.has_value())
{
return unionVec;
}
auto& bounds = boundsOpt.value();
std::cout << "Bounds generated: " << bounds.size() << std::endl;
// These bounds produce low <= col < high
if (bounds.size() > 1)
@@ -377,7 +398,6 @@ execplan::CalpontSelectExecutionPlan::SelectList makeUnionFromTable(
clonedCSEP->filters(filter);
unionVec.push_back(clonedCSEP);
}
std::cout << "Union units created: " << unionVec.size() << std::endl;
return unionVec;
}

View File

@@ -0,0 +1,106 @@
DROP DATABASE IF EXISTS rbo_parallel_ces_using_pk;
CREATE DATABASE rbo_parallel_ces_using_pk;
USE rbo_parallel_ces_using_pk;
SELECT calsettrace(1);
calsettrace(1)
0
CREATE TABLE `lineitem` (
`L_ORDERKEY` int(11) NOT NULL,
`L_PARTKEY` int(11) NOT NULL,
`L_SUPPKEY` int(11) NOT NULL,
`L_LINENUMBER` int(11) NOT NULL,
`L_QUANTITY` decimal(15,2) NOT NULL,
`L_EXTENDEDPRICE` decimal(15,2) NOT NULL,
`L_DISCOUNT` decimal(15,2) NOT NULL,
`L_TAX` decimal(15,2) NOT NULL,
`L_RETURNFLAG` char(1) NOT NULL,
`L_LINESTATUS` char(1) NOT NULL,
`L_SHIPDATE` date NOT NULL,
`L_COMMITDATE` date NOT NULL,
`L_RECEIPTDATE` date NOT NULL,
`L_SHIPINSTRUCT` char(25) NOT NULL,
`L_SHIPMODE` char(10) NOT NULL,
`L_COMMENT` varchar(44) NOT NULL,
`recdate_gt_commitdate` tinyint(4) NOT NULL DEFAULT 0,
KEY `L_ORDERKEY` (`L_ORDERKEY`,`L_SUPPKEY`,`recdate_gt_commitdate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
INSERT INTO `lineitem` (
`L_ORDERKEY`, `L_PARTKEY`, `L_SUPPKEY`, `L_LINENUMBER`,
`L_QUANTITY`, `L_EXTENDEDPRICE`, `L_DISCOUNT`, `L_TAX`,
`L_RETURNFLAG`, `L_LINESTATUS`, `L_SHIPDATE`, `L_COMMITDATE`, `L_RECEIPTDATE`,
`L_SHIPINSTRUCT`, `L_SHIPMODE`, `L_COMMENT`, `recdate_gt_commitdate`
) VALUES
(32, 197921, 441, 2, 32.00, 64605.44, 0.02, 0.00, 'N', 'O', '1995-08-14', '1995-10-07', '1995-08-27', 'COLLECT COD', 'AIR', 'lithely regular deposits. fluffily', 0),
(3, 128449, 3474, 3, 27.00, 39890.88, 0.06, 0.07, 'A', 'F', '1994-01-16', '1993-11-22', '1994-01-23', 'DELIVER IN PERSON', 'SHIP', 'nal foxes wake. ', 1),
(4, 88035, 5560, 1, 30.00, 30690.90, 0.03, 0.08, 'N', 'O', '1996-01-10', '1995-12-14', '1996-01-18', 'DELIVER IN PERSON', 'REG AIR', '- quickly regular packages sleep. idly', 1),
(5, 123927, 3928, 2, 26.00, 50723.92, 0.07, 0.08, 'R', 'F', '1994-10-16', '1994-09-25', '1994-10-19', 'NONE', 'FOB', 'sts use slyly quickly special instruc', 1),
(7, 182052, 9607, 1, 12.00, 13608.60, 0.07, 0.03, 'N', 'O', '1996-05-07', '1996-03-13', '1996-06-03', 'TAKE BACK RETURN', 'FOB', 'ss pinto beans wake against th', 1),
(34, 88362, 871, 1, 13.00, 17554.68, 0.00, 0.07, 'N', 'O', '1998-10-23', '1998-09-14', '1998-11-06', 'NONE', 'REG AIR', 'nic accounts. deposits are alon', 1),
(1, 155190, 7706, 1, 17.00, 21168.23, 0.04, 0.02, 'N', 'O', '1996-03-13', '1996-02-12', '1996-03-22', 'DELIVER IN PERSON', 'TRUCK', 'egular courts above the', 1),
(33, 137469, 9983, 3, 5.00, 7532.30, 0.05, 0.03, 'A', 'F', '1993-12-09', '1993-12-25', '1993-12-23', 'TAKE BACK RETURN', 'AIR', '. stealthily bold exc', 0),
(151872, 939, 940, 2, 42.00, 77277.06, 0.01, 0.00, 'N', 'O', '1995-09-30', '1995-09-28', '1995-10-27', 'TAKE BACK RETURN', 'TRUCK', 'ly slyly fina', 1),
(77632, 966, 967, 4, 11.00, 20536.56, 0.04, 0.03, 'N', 'O', '1995-09-28', '1995-09-22', '1995-10-24', 'NONE', 'FOB', 'nts was furi', 1),
(26439, 1085, 1086, 3, 3.00, 2958.24, 0.03, 0.00, 'N', 'O', '1995-09-30', '1995-12-04', '1995-10-22', 'DELIVER IN PERSON', 'TRUCK', 'ackages wake slyly a', 0),
(98599, 1239, 8740, 2, 48.00, 54731.04, 0.09, 0.06, 'N', 'O', '1995-09-24', '1995-08-26', '1995-10-02', 'TAKE BACK RETURN', 'TRUCK', 'ake always p', 1),
(95301, 1343, 8844, 2, 33.00, 41063.22, 0.00, 0.01, 'N', 'O', '1995-09-09', '1995-11-01', '1995-09-28', 'TAKE BACK RETURN', 'FOB', 'carefully regular requests. requests', 0),
(83008, 2988, 2989, 2, 12.00, 22691.76, 0.06, 0.07, 'N', 'O', '1995-09-15', '1995-09-24', '1995-10-09', 'NONE', 'RAIL', 'into beans do', 1),
(117665, 3024, 3025, 4, 10.00, 9270.20, 0.02, 0.01, 'N', 'O', '1995-09-17', '1995-08-26', '1995-10-12', 'COLLECT COD', 'AIR', 'about the slyly even req', 1),
(163746, 3126, 8127, 4, 45.00, 46310.40, 0.02, 0.00, 'N', 'O', '1995-09-21', '1995-09-17', '1995-10-01', 'DELIVER IN PERSON', 'RAIL', 'ggle. regular de', 1),
(161669, 3142, 8143, 3, 42.00, 43895.88, 0.06, 0.06, 'N', 'O', '1995-09-29', '1995-09-09', '1995-10-29', 'COLLECT COD', 'RAIL', 'ts. unusual accounts gro', 1),
(81826, 3357, 8358, 5, 5.00, 6301.75, 0.05, 0.04, 'N', 'O', '1995-09-06', '1995-06-14', '1995-09-19', 'TAKE BACK RETURN', 'FOB', 'y final pains x-ray blithely. pen', 1),
(118849, 3625, 6126, 5, 24.00, 36686.88, 0.09, 0.01, 'N', 'O', '1995-09-24', '1995-09-23', '1995-09-27', 'COLLECT COD', 'RAIL', 'c requests. furiously stealthy theodoli', 1),
(135239, 4119, 1620, 5, 36.00, 36831.96, 0.05, 0.03, 'N', 'O', '1995-09-06', '1995-07-16', '1995-09-09', 'COLLECT COD', 'AIR', ' after the accounts. qu', 1),
(30944, 4466, 9467, 1, 47.00, 64411.62, 0.02, 0.02, 'N', 'O', '1995-09-27', '1995-08-03', '1995-10-11', 'COLLECT COD', 'FOB', 'k platelets nag. slyly regular instructio', 1),
(1001, 2217, 2218, 1, 500.00, 5000.00, 0.05, 0.02, 'A', 'F', '1994-03-15', '1994-02-10', '1994-03-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1002, 2217, 2218, 2, 500.00, 5000.00, 0.05, 0.02, 'A', 'F', '1994-06-15', '1994-05-10', '1994-06-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1003, 2217, 9718, 1, 100.00, 1000.00, 0.05, 0.02, 'A', 'F', '1994-04-15', '1994-03-10', '1994-04-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1004, 2217, 9718, 2, 100.00, 1000.00, 0.05, 0.02, 'A', 'F', '1994-07-15', '1994-06-10', '1994-07-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1005, 4668, 7169, 1, 750.00, 7500.00, 0.05, 0.02, 'A', 'F', '1994-05-15', '1994-04-10', '1994-05-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1006, 4668, 7169, 2, 750.00, 7500.00, 0.05, 0.02, 'A', 'F', '1994-08-15', '1994-07-10', '1994-08-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1007, 4918, 2419, 1, 400.00, 4000.00, 0.05, 0.02, 'A', 'F', '1994-09-15', '1994-08-10', '1994-09-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1008, 4918, 2419, 2, 400.00, 4000.00, 0.05, 0.02, 'A', 'F', '1994-10-15', '1994-09-10', '1994-10-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1009, 6092, 6093, 1, 600.00, 6000.00, 0.05, 0.02, 'A', 'F', '1994-11-15', '1994-10-10', '1994-11-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1010, 6092, 6093, 2, 600.00, 6000.00, 0.05, 0.02, 'A', 'F', '1994-12-15', '1994-11-10', '1994-12-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1011, 7281, 2282, 1, 140.00, 1400.00, 0.05, 0.02, 'A', 'F', '1994-01-15', '1994-01-10', '1994-01-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1012, 7281, 2282, 2, 140.00, 1400.00, 0.05, 0.02, 'A', 'F', '1994-02-15', '1994-02-10', '1994-02-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1013, 8184, 3185, 1, 500.00, 5000.00, 0.05, 0.02, 'A', 'F', '1994-03-15', '1994-02-10', '1994-03-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1014, 8184, 3185, 2, 500.00, 5000.00, 0.05, 0.02, 'A', 'F', '1994-04-15', '1994-03-10', '1994-04-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1015, 9703, 2204, 1, 550.00, 5500.00, 0.05, 0.02, 'A', 'F', '1994-05-15', '1994-04-10', '1994-05-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1016, 9703, 2204, 2, 550.00, 5500.00, 0.05, 0.02, 'A', 'F', '1994-06-15', '1994-05-10', '1994-06-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1017, 10297, 2799, 1, 250.00, 2500.00, 0.05, 0.02, 'A', 'F', '1994-07-15', '1994-06-10', '1994-07-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1018, 10297, 2799, 2, 250.00, 2500.00, 0.05, 0.02, 'A', 'F', '1994-08-15', '1994-07-10', '1994-08-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1019, 10297, 5300, 1, 35.00, 350.00, 0.05, 0.02, 'A', 'F', '1994-09-15', '1994-08-10', '1994-09-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0),
(1020, 10297, 5300, 2, 35.00, 350.00, 0.05, 0.02, 'A', 'F', '1994-10-15', '1994-09-10', '1994-10-20', 'DELIVER IN PERSON', 'TRUCK', 'forest part delivery', 0);
ALTER TABLE lineitem DROP INDEX `L_ORDERKEY`;
ALTER TABLE lineitem ADD PRIMARY KEY (`l_orderkey`);
set histogram_size=4;
ANALYZE TABLE lineitem PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
rbo_parallel_ces_using_pk.lineitem analyze status Engine-independent statistics collected
rbo_parallel_ces_using_pk.lineitem analyze status OK
set columnstore_unstable_optimizer=on;
set optimizer_switch="index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off,index_merge_sort_intersection=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=on,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=on,split_materialized=off,condition_pushdown_for_subquery=off,rowid_filter=off,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=off,cset_narrowing=off,sargable_casefold=off";
set columnstore_query_accel_parallel_factor=2;
select count(*) from lineitem ;
count(*)
41
SET @opt_plan := mcs_get_plan('optimized');
SET @rbo_rules := mcs_get_plan('rules');
SELECT @rbo_rules LIKE '%parallel_ces%' AS rule_parallel_ces_applied;
rule_parallel_ces_applied
1
SET @opt_plan := mcs_get_plan('optimized');
set @rewritten_derived_name = 'derived table - $added_sub_rbo_parallel_ces_using_pk_lineitem_0';
set @original_table_name = '.lineitem(lineitem/) engineType=ForeignEngine';
SELECT (CHAR_LENGTH(@opt_plan) - CHAR_LENGTH(REPLACE(@opt_plan, @rewritten_derived_name, ''))) / CHAR_LENGTH(@rewritten_derived_name) AS rewritten_derived_table_count;
rewritten_derived_table_count
1.0000
SELECT (CHAR_LENGTH(@opt_plan) - CHAR_LENGTH(REPLACE(@opt_plan, @original_table_name, ''))) / CHAR_LENGTH(@original_table_name) AS original_table_count;
original_table_count
3.0000
SELECT calsettrace(0);
calsettrace(0)
1
DROP DATABASE rbo_parallel_ces_using_pk;
set columnstore_unstable_optimizer=off;
set optimizer_switch=default;

View File

@@ -0,0 +1,48 @@
--source ../include/have_columnstore.inc
--source include/have_innodb.inc
--source ../include/functions.inc
--source ../include/cross_engine.inc
--disable_warnings
DROP DATABASE IF EXISTS rbo_parallel_ces_using_pk;
--enable_warnings
CREATE DATABASE rbo_parallel_ces_using_pk;
USE rbo_parallel_ces_using_pk;
# Turn on plan logging to capture CSEP strings
SELECT calsettrace(1);
--source ../include/create_tpch_lineitem.inc
ALTER TABLE lineitem DROP INDEX `L_ORDERKEY`;
ALTER TABLE lineitem ADD PRIMARY KEY (`l_orderkey`);
set histogram_size=4;
ANALYZE TABLE lineitem PERSISTENT FOR ALL;
--source ../include/enable_rbo_parallel_ces.inc
set columnstore_query_accel_parallel_factor=2;
select count(*) from lineitem ;
# Snapshot plans into variables for readability
SET @opt_plan := mcs_get_plan('optimized');
SET @rbo_rules := mcs_get_plan('rules');
# Ensure rule was applied
SELECT @rbo_rules LIKE '%parallel_ces%' AS rule_parallel_ces_applied;
SET @opt_plan := mcs_get_plan('optimized');
set @rewritten_derived_name = 'derived table - $added_sub_rbo_parallel_ces_using_pk_lineitem_0';
set @original_table_name = '.lineitem(lineitem/) engineType=ForeignEngine';
SELECT (CHAR_LENGTH(@opt_plan) - CHAR_LENGTH(REPLACE(@opt_plan, @rewritten_derived_name, ''))) / CHAR_LENGTH(@rewritten_derived_name) AS rewritten_derived_table_count;
SELECT (CHAR_LENGTH(@opt_plan) - CHAR_LENGTH(REPLACE(@opt_plan, @original_table_name, ''))) / CHAR_LENGTH(@original_table_name) AS original_table_count;
# Cleanup
SELECT calsettrace(0);
DROP DATABASE rbo_parallel_ces_using_pk;
--source ../include/disable_rbo_parallel_ces.inc
--source ../include/drop_functions.inc
--source ../include/drop_cross_engine.inc