on 2022 Feb 08 6:13 PM
Dear developers,
Since we started building artifacts using cap framework quite quickly we came to performance issues.
Like for example I've created a large union of multiple events from different sources
entity events as select from source_1 {
'SOURCE_1' as source,
....
} union all select from source_2 {
'SOURCE_2' as source,
...
}
and so on
as a result I expect that whenever I select from such an entity, union node pruning must happen based on where source = ... condition.
However when we started testing it I've noticed such a behavior:
- if I use hardcoded values to query a view generated from such cds - pruning happens and it only selects data from one of union tables which is matching source filter
- however when handling odata request CAP generates quite generic statement
where source = ? and... and calling it with parameters.
Unfortunately for such a plan the behavior in our current Hana revision ( 2.0 rev56 ) is different and ESX engine starts pulling all the tables from the union. It dramatically increases memory and CPU consumtion, api's work poorly
So we have found a note pretty much close to the issue we face: https://launchpad.support.sap.com/#/notes/3133887
Of course there is a patch ( no fact that it will help ) but there is also immediate workaround by applying hints to the view.
So hint like NO_ESX_UNION_ALL works as expected however we cannot inject it to CDS/generated hdbview anyhow.
From our practice we have many more examples when hints were needed for some of our views therefore it would be nice if we could use them in CAP as well.
Please confirm if you have such a feature in your backlog.
Thank you!
Request clarification before answering.
For everybody landing on this page, this is now possible with CAP: https://cap.cloud.sap/docs/java/query-execution#hana-hints
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
johannesvogel so far here is my implementation of this feature:
odata.js
const cds = require("@sap/cds");
const enableHints = require("./pulgins/enable_hints");
cds
.connect("db")
.then(({ db }) =>
db?.before("READ", (req) => enableHints(req)
)
);
module.exports = class odata {};
and enable_hints.js
const SelectBuilder = require("@sap/cds/libx/_runtime/db/sql-builder/SelectBuilder");
const { build } = SelectBuilder.prototype;
// with hint support
Object.assign(SelectBuilder.prototype, {
build() {
const result = build.apply(this, arguments);
// to support also expands we will proxy all found hints to the end of the query
const hintsRegex = /(?<=WITH HINT\().*?(?=\))/g;
const foundHints = [result.sql.match(hintsRegex)]
.flat()
.filter((hints) => hints)
.flatMap((hints) => hints.split(","));
if (!this._obj.SELECT.withHint) {
this._obj.SELECT.withHint = foundHints;
// remove current hints to avoid duplicate definition
result.sql = result.sql.replace(/(WITH HINT\().*?(\))/g, "");
}
if (
Array.isArray(this._obj.SELECT.withHint) &&
this._obj.SELECT.withHint.length
) {
this._withHint(result);
}
return result;
},
_withHint(result) {
result.sql = result.sql.concat(
` WITH HINT(${this._obj.SELECT.withHint.join(",")})`
);
},
});
// query handler
module.exports = function enableHints({ target, query }) {
const withHint = target["@Consumption.dbHints"];
Array.isArray(withHint) && Object.assign(query.SELECT, { withHint });
};
I know it's kind of a hacky way to do this, but it works as a concept just perfectly. So now we are able to have a model like thisand it injects this hint not only to direct selects but also to quite deep navigations. So I've solved some issue which I've been trying to solve during couple weeks 😃
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
sorry for my late response.
As you already state, it's a hacky solution that uses internal information.
I'm happy if that solves your problem but be aware that this might break with future releases.
When implementing this feature in general, we'll strive for an ABAP independent solution.
Best regards,
Johannes
Hi @Petr_Plenkov,
We have a similar use case with big unions and virtual tables and currently use CAP v8. I am going to dig into the framework to try implement this with CAP v8.
My only query is that is the file odata.js a service handler that intercepts all db calls?
Also, have you tried with a recent CAP version. We really need this feature as annotations on the service entities to optimize the query performance.
BR,
Abhishek
User | Count |
---|---|
41 | |
15 | |
10 | |
9 | |
7 | |
6 | |
6 | |
5 | |
5 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.