|
2 | 2 |
|
3 | 3 | #include <ydb/core/kqp/opt/kqp_opt_impl.h> |
4 | 4 | #include <ydb/core/kqp/common/kqp_yql.h> |
| 5 | +#include <ydb/library/yql/core/yql_opt_utils.h> |
| 6 | + |
| 7 | +namespace { |
| 8 | + |
| 9 | +bool CanPushFlatMap(const NYql::NNodes::TCoFlatMapBase& flatMap, const NYql::TKikimrTableDescription& tableDesc, const NYql::TParentsMap& parentsMap, TVector<TString> & extraColumns) { |
| 10 | + auto flatMapLambda = flatMap.Lambda(); |
| 11 | + if (!NYql::IsFilterFlatMap(flatMapLambda)) { |
| 12 | + return false; |
| 13 | + } |
| 14 | + |
| 15 | + const auto & flatMapLambdaArgument = flatMapLambda.Args().Arg(0).Ref(); |
| 16 | + auto flatMapLambdaConditional = flatMapLambda.Body().Cast<NYql::NNodes::TCoConditionalValueBase>(); |
| 17 | + |
| 18 | + TSet<TString> lambdaSubset; |
| 19 | + auto isSubSet = HaveFieldsSubset(flatMapLambdaConditional.Predicate().Ptr(), flatMapLambdaArgument, lambdaSubset, parentsMap, true); |
| 20 | + auto argType = NYql::RemoveOptionalType(flatMapLambdaArgument.GetTypeAnn()); |
| 21 | + if (argType->GetKind() != NYql::ETypeAnnotationKind::Struct) { |
| 22 | + return false; |
| 23 | + } |
| 24 | + // helper doesn't accept if all columns are used |
| 25 | + if (!isSubSet && lambdaSubset.size() != argType->Cast<NYql::TStructExprType>()->GetSize()) { |
| 26 | + return false; |
| 27 | + } |
| 28 | + |
| 29 | + for (auto & lambdaColumn : lambdaSubset) { |
| 30 | + auto columnIndex = tableDesc.GetKeyColumnIndex(lambdaColumn); |
| 31 | + if (!columnIndex) { |
| 32 | + return false; |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + extraColumns.insert(extraColumns.end(), lambdaSubset.begin(), lambdaSubset.end()); |
| 37 | + return true; |
| 38 | +} |
| 39 | + |
| 40 | +} |
5 | 41 |
|
6 | 42 | namespace NKikimr::NKqp::NOpt { |
7 | 43 |
|
8 | 44 | using namespace NYql; |
9 | 45 | using namespace NYql::NNodes; |
10 | 46 |
|
11 | | -TExprBase KqpDeleteOverLookup(const TExprBase& node, TExprContext& ctx, const TKqpOptimizeContext &kqpCtx) { |
| 47 | +TExprBase KqpDeleteOverLookup(const TExprBase& node, TExprContext& ctx, const TKqpOptimizeContext &kqpCtx, const NYql::TParentsMap& parentsMap) { |
12 | 48 | if (!node.Maybe<TKqlDeleteRows>()) { |
13 | 49 | return node; |
14 | 50 | } |
15 | 51 |
|
16 | 52 | auto deleteRows = node.Cast<TKqlDeleteRows>(); |
17 | 53 |
|
| 54 | + TMaybeNode<TCoFlatMap> filter; |
| 55 | + |
18 | 56 | TMaybeNode<TKqlLookupTableBase> lookup; |
| 57 | + TMaybeNode<TKqlReadTable> read; |
19 | 58 | TMaybeNode<TCoSkipNullMembers> skipNulMembers; |
| 59 | + TMaybeNode<TKqlReadTableRanges> readranges; |
20 | 60 |
|
21 | 61 | if (deleteRows.Input().Maybe<TKqlLookupTableBase>()) { |
22 | 62 | lookup = deleteRows.Input().Cast<TKqlLookupTableBase>(); |
23 | 63 | } else if (deleteRows.Input().Maybe<TCoSkipNullMembers>().Input().Maybe<TKqlLookupTableBase>()) { |
24 | 64 | skipNulMembers = deleteRows.Input().Cast<TCoSkipNullMembers>(); |
25 | 65 | lookup = skipNulMembers.Input().Cast<TKqlLookupTableBase>(); |
| 66 | + } else if (deleteRows.Input().Maybe<TKqlReadTable>()) { |
| 67 | + read = deleteRows.Input().Cast<TKqlReadTable>(); |
26 | 68 | } else { |
27 | | - return node; |
28 | | - } |
29 | | - |
30 | | - YQL_ENSURE(lookup); |
31 | | - if (deleteRows.Table().Raw() != lookup.Cast().Table().Raw()) { |
32 | | - return node; |
| 69 | + TMaybeNode<TExprBase> input = deleteRows.Input(); |
| 70 | + if (input.Maybe<TCoFlatMap>()) { |
| 71 | + filter = deleteRows.Input().Cast<TCoFlatMap>(); |
| 72 | + input = filter.Input(); |
| 73 | + } |
| 74 | + readranges = input.Maybe<TKqlReadTableRanges>(); |
| 75 | + if (!readranges) { |
| 76 | + return node; |
| 77 | + } |
33 | 78 | } |
34 | 79 |
|
35 | | - auto lookupKeysType = lookup.Cast().LookupKeys().Ref().GetTypeAnn(); |
36 | | - auto lookupKeyType = lookupKeysType->Cast<TListExprType>()->GetItemType()->Cast<TStructExprType>(); |
37 | | - YQL_ENSURE(lookupKeyType); |
38 | | - |
39 | | - // Only consider complete PK lookups |
| 80 | + TMaybeNode<TExprBase> deleteInput; |
40 | 81 | const auto& tableDesc = GetTableData(*kqpCtx.Tables, kqpCtx.Cluster, deleteRows.Table().Path()); |
41 | | - if (lookupKeyType->GetSize() != tableDesc.Metadata->KeyColumnNames.size()) { |
42 | | - return node; |
43 | | - } |
44 | | - |
45 | | - TExprBase deleteInput = lookup.Cast().LookupKeys(); |
46 | | - if (skipNulMembers) { |
47 | | - deleteInput = Build<TCoSkipNullMembers>(ctx, skipNulMembers.Cast().Pos()) |
48 | | - .Input(deleteInput) |
49 | | - .Members(skipNulMembers.Cast().Members()) |
| 82 | + if (lookup) { |
| 83 | + if (deleteRows.Table().Raw() != lookup.Cast().Table().Raw()) { |
| 84 | + return node; |
| 85 | + } |
| 86 | + |
| 87 | + auto lookupKeysType = lookup.Cast().LookupKeys().Ref().GetTypeAnn(); |
| 88 | + auto lookupKeyType = lookupKeysType->Cast<TListExprType>()->GetItemType()->Cast<TStructExprType>(); |
| 89 | + YQL_ENSURE(lookupKeyType); |
| 90 | + |
| 91 | + // Only consider complete PK lookups |
| 92 | + if (lookupKeyType->GetSize() != tableDesc.Metadata->KeyColumnNames.size()) { |
| 93 | + return node; |
| 94 | + } |
| 95 | + |
| 96 | + deleteInput = lookup.Cast().LookupKeys(); |
| 97 | + if (skipNulMembers) { |
| 98 | + deleteInput = Build<TCoSkipNullMembers>(ctx, skipNulMembers.Cast().Pos()) |
| 99 | + .Input(deleteInput.Cast()) |
| 100 | + .Members(skipNulMembers.Cast().Members()) |
| 101 | + .Done(); |
| 102 | + } |
| 103 | + } else if (read) { |
| 104 | + if (deleteRows.Table().Raw() != read.Cast().Table().Raw()) { |
| 105 | + return node; |
| 106 | + } |
| 107 | + |
| 108 | + const auto& rangeFrom = read.Cast().Range().From(); |
| 109 | + const auto& rangeTo = read.Cast().Range().To(); |
| 110 | + |
| 111 | + if (!rangeFrom.Maybe<TKqlKeyInc>() || !rangeTo.Maybe<TKqlKeyInc>()) { |
| 112 | + return node; |
| 113 | + } |
| 114 | + |
| 115 | + if (rangeFrom.Raw() != rangeTo.Raw()) { |
| 116 | + return node; |
| 117 | + } |
| 118 | + |
| 119 | + if (rangeFrom.ArgCount() != tableDesc.Metadata->KeyColumnNames.size()) { |
| 120 | + return node; |
| 121 | + } |
| 122 | + |
| 123 | + TVector<TExprBase> structMembers; |
| 124 | + for (ui32 i = 0; i < rangeFrom.ArgCount(); ++i) { |
| 125 | + TCoAtom columnNameAtom(ctx.NewAtom(node.Pos(), tableDesc.Metadata->KeyColumnNames[i])); |
| 126 | + |
| 127 | + auto member = Build<TCoNameValueTuple>(ctx, node.Pos()) |
| 128 | + .Name(columnNameAtom) |
| 129 | + .Value(rangeFrom.Arg(i)) |
| 130 | + .Done(); |
| 131 | + |
| 132 | + structMembers.push_back(member); |
| 133 | + } |
| 134 | + |
| 135 | + deleteInput = Build<TCoAsList>(ctx, node.Pos()) |
| 136 | + .Add<TCoAsStruct>() |
| 137 | + .Add(structMembers) |
| 138 | + .Build() |
50 | 139 | .Done(); |
| 140 | + } else if (readranges) { |
| 141 | + if (deleteRows.Table().Raw() != readranges.Cast().Table().Raw()) { |
| 142 | + return node; |
| 143 | + } |
| 144 | + |
| 145 | + if (!readranges.Cast().PrefixPointsExpr()) { |
| 146 | + return node; |
| 147 | + } |
| 148 | + |
| 149 | + const auto& tableDesc = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, readranges.Cast().Table().Path().Value()); |
| 150 | + auto hint = TKqpReadTableExplainPrompt::Parse(readranges.Cast().ExplainPrompt()); |
| 151 | + if (hint.PointPrefixLen != tableDesc.Metadata->KeyColumnNames.size()) { |
| 152 | + return node; |
| 153 | + } |
| 154 | + |
| 155 | + if (filter) { |
| 156 | + TVector<TString> extraColumns; |
| 157 | + if (!CanPushFlatMap(filter.Cast(), tableDesc, parentsMap, extraColumns)) { |
| 158 | + return node; |
| 159 | + } |
| 160 | + deleteInput = Build<TCoFlatMap>(ctx, node.Pos()) |
| 161 | + .Lambda(filter.Lambda().Cast()) |
| 162 | + .Input(readranges.PrefixPointsExpr().Cast()) |
| 163 | + .Done(); |
| 164 | + } else { |
| 165 | + deleteInput = readranges.PrefixPointsExpr(); |
| 166 | + } |
51 | 167 | } |
52 | 168 |
|
| 169 | + YQL_ENSURE(deleteInput); |
| 170 | + |
53 | 171 | return Build<TKqlDeleteRows>(ctx, deleteRows.Pos()) |
54 | 172 | .Table(deleteRows.Table()) |
55 | | - .Input(deleteInput) |
| 173 | + .Input(deleteInput.Cast()) |
56 | 174 | .Done(); |
57 | 175 | } |
58 | 176 |
|
|
0 commit comments