From 0d3a41c33d40266a836773462c881f565a51bfea Mon Sep 17 00:00:00 2001 From: zz0 Date: Tue, 19 Oct 2021 21:03:41 +0800 Subject: [PATCH] disable join elimination for delete/update when the eliminated table is also a deleted/updated table --- .../rewrite/ob_transform_join_elimination.cpp | 38 +++++++++++++++++-- .../rewrite/ob_transform_join_elimination.h | 29 ++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/sql/rewrite/ob_transform_join_elimination.cpp b/src/sql/rewrite/ob_transform_join_elimination.cpp index ef25d96b85..dfc0ab9e99 100644 --- a/src/sql/rewrite/ob_transform_join_elimination.cpp +++ b/src/sql/rewrite/ob_transform_join_elimination.cpp @@ -60,7 +60,29 @@ int ObTransformJoinElimination::transform_one_stmt( return ret; } -int ObTransformJoinElimination::eliminate_join_self_foreign_key(ObDMLStmt* stmt, bool& trans_happened) +int ObTransformJoinElimination::check_table_can_be_eliminated(const ObDMLStmt *stmt, uint64_t table_id, bool &is_valid) +{ + int ret = OB_SUCCESS; + is_valid = true; + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null stmt", K(ret)); + } else if (stmt->is_delete_stmt() || stmt->is_update_stmt()) { + const ObDelUpdStmt *del_up_stmt = static_cast(stmt); + for (uint64_t i = 0; OB_SUCC(ret) && i < del_up_stmt->get_all_table_columns().count(); ++i) { + const TableColumns &tab_cols = del_up_stmt->get_all_table_columns().at(i); + const IndexDMLInfo &index_info = tab_cols.index_dml_infos_.at(0); + if (index_info.table_id_ == table_id) { + is_valid = false; + } + } + } else { + // TODO: add more cases if necessary + } + return ret; +} + +int ObTransformJoinElimination::eliminate_join_self_foreign_key(ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; bool from_happedend = false; @@ -1707,6 +1729,7 @@ int ObTransformJoinElimination::eliminate_candi_tables(ObDMLStmt* stmt, ObIArray trans_happened = false; EqualSets* equal_sets = &ctx_->equal_sets_; ObArenaAllocator allocator; + bool is_valid = true; if (conds.empty()) { /*do nothing*/ } else if (OB_FAIL(ObEqualAnalysis::compute_equal_set(&allocator, conds, *equal_sets))) { @@ -1721,6 +1744,10 @@ int ObTransformJoinElimination::eliminate_candi_tables(ObDMLStmt* stmt, ObIArray for (int64_t j = 0; OB_SUCC(ret) && j < candi_tables.count(); ++j) { if (i == j || removed_items.has_member(j)) { /*do nothing*/ + } else if (OB_FAIL(check_table_can_be_eliminated(stmt, candi_tables.at(j)->table_id_, is_valid))) { + LOG_WARN("check table can be eliminated failed", K(ret)); + } else if (!is_valid) { + // do nothing } else if (OB_FAIL(do_join_elimination_self_key( stmt, candi_tables.at(i), candi_tables.at(j), is_happened, equal_sets))) { LOG_WARN("failed to eliminate self key join in base table", K(ret)); @@ -1734,8 +1761,13 @@ int ObTransformJoinElimination::eliminate_candi_tables(ObDMLStmt* stmt, ObIArray } is_happened = false; for (int64_t j = 0; OB_SUCC(ret) && !is_happened && j < child_candi_tables.count(); ++j) { - if (OB_FAIL(do_join_elimination_self_key( - stmt, child_candi_tables.at(j), candi_tables.at(i), is_happened, equal_sets))) { + is_valid = true; + if (OB_FAIL(check_table_can_be_eliminated(stmt, candi_tables.at(i)->table_id_, is_valid))) { + LOG_WARN("check table can be eliminated failed", K(ret)); + } else if (!is_valid) { + // do nothing + } else if (OB_FAIL(do_join_elimination_self_key( + stmt, child_candi_tables.at(j), candi_tables.at(i), is_happened, equal_sets))) { LOG_WARN("failed to do join elimination erlf key", K(ret)); } else if (!is_happened) { /*do nothing*/ diff --git a/src/sql/rewrite/ob_transform_join_elimination.h b/src/sql/rewrite/ob_transform_join_elimination.h index 928eb174fb..f18b12f0dd 100644 --- a/src/sql/rewrite/ob_transform_join_elimination.h +++ b/src/sql/rewrite/ob_transform_join_elimination.h @@ -55,9 +55,32 @@ public: common::ObIArray& parent_stmts, ObDMLStmt*& stmt, bool& trans_happened) override; private: - int eliminate_join_self_foreign_key(ObDMLStmt* stmt, bool& trans_happened); - - int eliminate_join_in_from_base_table(ObDMLStmt* stmt, bool& trans_happened); + /** + * @brief + * check if a table can be eliminated + * delete p1, p2 FROM t1 as p1, t1 as p2 where p1.a=p2.a; + * p2 can not be eliminateed since it is going to be updated/deleted + * @param stmt + * @param table_id + * @param is_valid + * @return int + */ + int check_table_can_be_eliminated(const ObDMLStmt *stmt, uint64_t table_id, bool &is_valid); + + /** + * @brief eliminate_join_self_key + * cases that can be eliminated for self key join: + * basic_table or generate_table within STMT FROM ITEMS + * basic_table or generate_table within SEMI ITEMS + * inner join tables within SEMI ITEMS or STMT ITEMS + */ + int eliminate_join_self_foreign_key(ObDMLStmt *stmt, bool &trans_happened); + + /** + * @brief eliminate_SKJ_in_from_base_table + * eliminate self key loseless join existed in basic table or generate table within STMT FROM ITEMS + */ + int eliminate_join_in_from_base_table(ObDMLStmt *stmt, bool &trans_happened); int eliminate_join_in_from_item( ObDMLStmt* stmt, const ObIArray& from_items, SemiInfo* semi_info, bool& trans_happened); -- GitLab