From 1d7314b9efdd4e9b89690e5384bb73e41f11ecc0 Mon Sep 17 00:00:00 2001 From: vkonagar Date: Tue, 17 Apr 2018 13:23:21 -0400 Subject: [PATCH 1/3] Fix multi-column index rule in optimizer --- src/optimizer/rule_impls.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/optimizer/rule_impls.cpp b/src/optimizer/rule_impls.cpp index e540555c9e3..617e74446aa 100644 --- a/src/optimizer/rule_impls.cpp +++ b/src/optimizer/rule_impls.cpp @@ -386,17 +386,20 @@ void GetToIndexScan::Transform( std::vector index_key_column_id_list; std::vector index_expr_type_list; std::vector index_value_list; - std::unordered_set index_col_set( - index_object->GetKeyAttrs().begin(), - index_object->GetKeyAttrs().end()); - for (size_t offset = 0; offset < key_column_id_list.size(); offset++) { + + // Only pick the index if the query columns match the index's columns in order. + auto index_id_list = index_object->GetKeyAttrs(); + for (size_t offset = 0; (offset < key_column_id_list.size()) && (offset < index_id_list.size()); offset++) { auto col_id = key_column_id_list[offset]; - if (index_col_set.find(col_id) != index_col_set.end()) { + if (index_id_list[offset] == col_id) { index_key_column_id_list.push_back(col_id); index_expr_type_list.push_back(expr_type_list[offset]); index_value_list.push_back(value_list[offset]); + } else { + break; } } + // Add transformed plan if (!index_key_column_id_list.empty()) { auto index_scan_op = PhysicalIndexScan::make( From f7c40354e03b2de899e99a0faa15db7910b14b54 Mon Sep 17 00:00:00 2001 From: vkonagar Date: Tue, 17 Apr 2018 13:35:57 -0400 Subject: [PATCH 2/3] Fix formatting --- src/optimizer/rule_impls.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/optimizer/rule_impls.cpp b/src/optimizer/rule_impls.cpp index 617e74446aa..5b094252cf7 100644 --- a/src/optimizer/rule_impls.cpp +++ b/src/optimizer/rule_impls.cpp @@ -6,7 +6,7 @@ // // Identification: src/optimizer/rule_impls.cpp // -// Copyright (c) 2015-16, Carnegie Mellon University Database Group +// Copyright (c) 2015-2018, Carnegie Mellon University Database Group // //===----------------------------------------------------------------------===// @@ -387,12 +387,14 @@ void GetToIndexScan::Transform( std::vector index_expr_type_list; std::vector index_value_list; - // Only pick the index if the query columns match the index's columns in order. + // Only pick the index if the query columns match the index's columns in + // the same order. auto index_id_list = index_object->GetKeyAttrs(); - for (size_t offset = 0; (offset < key_column_id_list.size()) && (offset < index_id_list.size()); offset++) { - auto col_id = key_column_id_list[offset]; - if (index_id_list[offset] == col_id) { - index_key_column_id_list.push_back(col_id); + for (size_t offset = 0; (offset < key_column_id_list.size()) && + (offset < index_id_list.size()); + offset++) { + if (index_id_list[offset] == key_column_id_list[offset]) { + index_key_column_id_list.push_back(key_column_id_list[offset]); index_expr_type_list.push_back(expr_type_list[offset]); index_value_list.push_back(value_list[offset]); } else { From a7114280780c9850090e04ee287eb556ddcae115 Mon Sep 17 00:00:00 2001 From: vkonagar Date: Wed, 18 Apr 2018 20:43:35 -0400 Subject: [PATCH 3/3] Add test for multi-column index scan plans --- test/optimizer/optimizer_test.cpp | 86 +++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/test/optimizer/optimizer_test.cpp b/test/optimizer/optimizer_test.cpp index 99348b12b44..d17cb419324 100644 --- a/test/optimizer/optimizer_test.cpp +++ b/test/optimizer/optimizer_test.cpp @@ -28,6 +28,7 @@ #include "planner/update_plan.h" #include "sql/testing_sql_util.h" #include "planner/seq_scan_plan.h" +#include "planner/index_scan_plan.h" #include "planner/abstract_join_plan.h" #include "planner/hash_join_plan.h" #include "binder/bind_node_visitor.h" @@ -494,5 +495,90 @@ TEST_F(OptimizerTests, ExecuteTaskStackTest) { ASSERT_GT(timer.GetDuration(), start_time); } +TEST_F(OptimizerTests, MultiColumnIndexScanPlanTest) { + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + catalog::Catalog::GetInstance()->CreateDatabase(DEFAULT_DB_NAME, txn); + txn_manager.CommitTransaction(txn); + + auto tuple_count = 100; + + // Create table and insert tuples. + TestingSQLUtil::ExecuteSQLQuery( + "CREATE TABLE test(a INT, b INT, c INT, d INT, e INT);"); + + for (auto i = 0; i < tuple_count; i++) { + std::stringstream oss; + oss << "INSERT into test VALUES(" << i << "," << i + 1 << "," << i + 2 + << "," << i + 3 << "," << i + 4 << ");"; + TestingSQLUtil::ExecuteSQLQuery(oss.str()); + } + + // Create a multi-column index + TestingSQLUtil::ExecuteSQLQuery("CREATE INDEX Index1 on test(a, c, d, e);"); + + txn = txn_manager.BeginTransaction(); + optimizer::Optimizer optimizer; + auto &peloton_parser = parser::PostgresParser::GetInstance(); + + auto create_stmt = + peloton_parser.BuildParseTree("SELECT * FROM test where e = 8"); + auto plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::SEQSCAN); + + create_stmt = + peloton_parser.BuildParseTree("SELECT * FROM test where c = 4 and e = 6"); + plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::SEQSCAN); + + create_stmt = + peloton_parser.BuildParseTree("SELECT * FROM test where a = 4 and e = 8"); + plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::INDEXSCAN); + auto index_scan_plan = static_cast(plan.get()); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds().size(), 1); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[0], 0); + + create_stmt = + peloton_parser.BuildParseTree("SELECT * FROM test where a = 4 and c = 6"); + plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::INDEXSCAN); + index_scan_plan = static_cast(plan.get()); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds().size(), 2); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[0], 0); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[1], 2); + + create_stmt = peloton_parser.BuildParseTree( + "SELECT * FROM test where a = 4 and c = 6 and d = 7"); + plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::INDEXSCAN); + index_scan_plan = static_cast(plan.get()); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds().size(), 3); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[0], 0); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[1], 2); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[2], 3); + + create_stmt = peloton_parser.BuildParseTree( + "SELECT * FROM test where a = 4 and b = 5 and c = 6 and d = 7"); + plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::INDEXSCAN); + index_scan_plan = static_cast(plan.get()); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds().size(), 1); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[0], 0); + + create_stmt = peloton_parser.BuildParseTree( + "SELECT * FROM test where a = 4 and c = 6 and d = 7 and e = 8"); + plan = optimizer.BuildPelotonPlanTree(create_stmt, DEFAULT_DB_NAME, txn); + EXPECT_EQ(plan->GetPlanNodeType(), PlanNodeType::INDEXSCAN); + index_scan_plan = static_cast(plan.get()); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds().size(), 4); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[0], 0); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[1], 2); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[2], 3); + EXPECT_EQ(index_scan_plan->GetKeyColumnIds()[3], 4); + + txn_manager.CommitTransaction(txn); +} + } // namespace test } // namespace peloton