You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thanks @BobdenOs for bringing this up, I tried to summarize the findings in this issue for future discussions.
Take this view from sflight:
entityBookingsasprojectiononmy.Booking {
@UI.Hidden:falseBookingUUIDasID,
to_Travel.TravelID,
BookingID,
@title:'Travel/Booking ID'to_Travel.TravelID||'/'||BookingIDasCombinedID:String,
ConnectionID,
FlightDate,
// pretend all bookings have the same currency so the FlightPrice can be aggregated@title:'{i18n>CurrencyCode}''USD'asCurrencyCode_code:String(3),
//CurrencyCode.code as CurrencyCode_code,@Measures.ISOCurrency: CurrencyCode_codeFlightPrice,
@title:'{i18n>BookingStatus}'@Common.Text: statusName@Common.TextArrangement:#TextOnlyBookingStatus.codeasstatus,
BookingStatus.nameasstatusName,
@Common.Text: airlineNameto_Carrier.AirlineIDasairline,
to_Carrier.NameasairlineName,
BookingDate,
to_Travel,
to_Carrier,
// Java has a problem with this associationto_Flight,
// Workaround:to_Flight.PlaneType,
to_Flight.to_Connection.Distance,
to_Flight.to_Connection.DistanceUnit,
@Common.Label:'{i18n>DepartureAirport}'@Common.Text: DepCityto_Flight.to_Connection.DepartureAirport.AirportIDasDepAirport,
to_Flight.to_Connection.DepartureAirport.CityasDepCity,
@Common.Label:'{i18n>ArrivalAirport}'@Common.Text: DestCityto_Flight.to_Connection.DestinationAirport.AirportIDasDestAirport,
to_Flight.to_Connection.DestinationAirport.CityasDestCity,
};
which is transformed to the following sql, note that we have 8 query sources in the from clause:
CREATEVIEWAnalyticsService_BookingsASSELECTBooking_0.BookingUUIDAS ID,
to_Travel_1.TravelID,
Booking_0.BookingID,
to_Travel_1.TravelID||'/'||Booking_0.BookingIDAS CombinedID,
Booking_0.ConnectionID,
Booking_0.FlightDate,
'USD'AS CurrencyCode_code,
Booking_0.FlightPrice,
BookingStatus_2.codeAS status,
BookingStatus_2.nameAS statusName,
to_Carrier_3.AirlineIDAS airline,
to_Carrier_3.NameAS airlineName,
Booking_0.BookingDate,
Booking_0.to_Travel_TravelUUID,
Booking_0.to_Carrier_AirlineID,
to_Flight_4.PlaneType,
to_Connection_5.Distance,
to_Connection_5.DistanceUnit,
DepartureAirport_6.AirportIDAS DepAirport,
DepartureAirport_6.CityAS DepCity,
DestinationAirport_7.AirportIDAS DestAirport,
DestinationAirport_7.CityAS DestCity
FROM
(
(
(
(
(
(
(
sap_fe_cap_travel_Booking AS Booking_0
LEFT JOIN sap_fe_cap_travel_Travel AS to_Travel_1 ONBooking_0.to_Travel_TravelUUID=to_Travel_1.TravelUUID
)
LEFT JOIN sap_fe_cap_travel_BookingStatus AS BookingStatus_2 ONBooking_0.BookingStatus_code=BookingStatus_2.code
)
LEFT JOIN sap_fe_cap_travel_Airline AS to_Carrier_3 ONBooking_0.to_Carrier_AirlineID=to_Carrier_3.AirlineID
)
LEFT JOIN sap_fe_cap_travel_Flight AS to_Flight_4 ONto_Flight_4.AirlineID=Booking_0.to_Carrier_AirlineIDANDto_Flight_4.FlightDate=Booking_0.FlightDateANDto_Flight_4.ConnectionID=Booking_0.ConnectionID
)
LEFT JOIN sap_fe_cap_travel_FlightConnection AS to_Connection_5 ONto_Connection_5.AirlineID=to_Flight_4.AirlineIDANDto_Connection_5.ConnectionID=to_Flight_4.ConnectionID
)
LEFT JOIN sap_fe_cap_travel_Airport AS DepartureAirport_6 ONto_Connection_5.DepartureAirport_AirportID=DepartureAirport_6.AirportID
)
LEFT JOIN sap_fe_cap_travel_Airport AS DestinationAirport_7 ONto_Connection_5.DestinationAirport_AirportID=DestinationAirport_7.AirportID
);
if we now fire a common request as this one: Bookings[ID=7A757221A8E4645C17002DF03754AB66].to_Travel.to_Booking we create a runtime query like this:
SELECT
…
FROM
AnalyticsService_Bookings as to_Booking
WHERE
exists (
SELECT1as"1"FROM
AnalyticsService_Travels as to_Travel
WHEREto_Travel.TravelUUID=to_Booking.to_Travel_TravelUUIDand exists (
SELECT1as"1"FROM
AnalyticsService_Bookings as Bookings
WHEREBookings.to_Travel_TravelUUID=to_Travel.TravelUUIDandBookings.ID= 7A757221A8E4645C17002DF03754AB66
)
)
the issue is that all the 7 left joins of the original view definition are materialized before our where exists subquery is applied to narrow down the results to exactly one booking with the matching UUID. The query becomes slower with more data to be joined and the execution plan becomes unnecessary complex:
the blue box is the where exists subquery and the red box is the view's join
if we would push down the path expression to the join node where the Bookings.ID is matched, like in this query:
SELECTBooking_0.BookingUUIDAS ID,
to_Travel_1.TravelID,
Booking_0.BookingID,
to_Travel_1.TravelID||'/'||Booking_0.BookingIDAS CombinedID,
Booking_0.ConnectionID,
Booking_0.FlightDate,
'USD'AS CurrencyCode_code,
Booking_0.FlightPrice,
BookingStatus_2.codeAS status,
BookingStatus_2.nameAS statusName,
to_Carrier_3.AirlineIDAS airline,
to_Carrier_3.NameAS airlineName,
Booking_0.BookingDate,
Booking_0.to_Travel_TravelUUID,
Booking_0.to_Carrier_AirlineID,
to_Flight_4.PlaneType,
to_Connection_5.Distance,
to_Connection_5.DistanceUnit,
DepartureAirport_6.AirportIDAS DepAirport,
DepartureAirport_6.CityAS DepCity,
DestinationAirport_7.AirportIDAS DestAirport,
DestinationAirport_7.CityAS DestCityFROM (
(
(
(
(
(
(
(
SELECT*FROM
sap_fe_cap_travel_Booking AS to_Booking
WHERE
exists (
SELECT1FROM
sap_fe_cap_travel_Travel as to_Travel
WHEREto_Travel.TravelUUID=to_Booking.to_Travel_TravelUUIDand exists (
SELECT1FROM
sap_fe_cap_travel_Booking as Bookings
WHEREBookings.to_Travel_TravelUUID=to_Travel.TravelUUIDandBookings.BookingUUID='7A757221A8E4645C17002DF03754AB66'
)
)
) as Booking_0
LEFT JOIN sap_fe_cap_travel_Travel AS to_Travel_1 ONBooking_0.to_Travel_TravelUUID=to_Travel_1.TravelUUID
)
LEFT JOIN sap_fe_cap_travel_BookingStatus AS BookingStatus_2 ONBooking_0.BookingStatus_code=BookingStatus_2.code
)
LEFT JOIN sap_fe_cap_travel_Airline AS to_Carrier_3 ONBooking_0.to_Carrier_AirlineID=to_Carrier_3.AirlineID
)
LEFT JOIN sap_fe_cap_travel_Flight AS to_Flight_4 ONto_Flight_4.AirlineID=Booking_0.to_Carrier_AirlineIDANDto_Flight_4.FlightDate=Booking_0.FlightDateANDto_Flight_4.ConnectionID=Booking_0.ConnectionID
)
LEFT JOIN sap_fe_cap_travel_FlightConnection AS to_Connection_5 ONto_Connection_5.AirlineID=to_Flight_4.AirlineIDANDto_Connection_5.ConnectionID=to_Flight_4.ConnectionID
)
LEFT JOIN sap_fe_cap_travel_Airport AS DepartureAirport_6 ONto_Connection_5.DepartureAirport_AirportID=DepartureAirport_6.AirportID
)
LEFT JOIN sap_fe_cap_travel_Airport AS DestinationAirport_7 ONto_Connection_5.DestinationAirport_AirportID=DestinationAirport_7.AirportID
);
the query becomes (in the case of sflight with 9k records) more than 100x faster, the execution plan for this query looks different, too. As all the joins are only applied to the already-narrowed-down results which matched the Bookings.BookingUUID = '7A757221A8E4645C17002DF03754AB66'
The text was updated successfully, but these errors were encountered:
Here is some additional information for the same approach when using @cap-js/hana.
When the query is currently being fired to HANA the execution plan looks like the following and the highlighted node applies the filter. Which shows that HANA is also first materializing the whole view before filtering it.
When running the optimized query the execution plan looks much more similar to that of Postgres, but it is not yet exactly on par. As there is an hash join executed which skips an additional index scan optimization which could be applied.
There have been limitations in the past when using ? placeholders on HANA. So making sure to exclude this possibility I have flagged the key to be in lined with the SQL and this unlocked all the optimizations HANA provides. Directly applying the ID filter and only working on the single row it produces. Gaining an 100x performance improvement over the exact same SQL statement that leverages an ? placeholder for the ID compare. But this optimization is only possible if foreign keys are indexed as suggested by: #887
Thanks @BobdenOs for bringing this up, I tried to summarize the findings in this issue for future discussions.
Take this view from sflight:
which is transformed to the following sql, note that we have 8 query sources in the from clause:
if we now fire a common request as this one:
Bookings[ID=7A757221A8E4645C17002DF03754AB66].to_Travel.to_Booking
we create a runtime query like this:the issue is that all the 7 left joins of the original view definition are materialized before our
where exists
subquery is applied to narrow down the results to exactly one booking with the matching UUID. The query becomes slower with more data to be joined and the execution plan becomes unnecessary complex:the blue box is the where exists subquery and the red box is the view's join
if we would push down the path expression to the join node where the
Bookings.ID
is matched, like in this query:the query becomes (in the case of sflight with 9k records) more than 100x faster, the execution plan for this query looks different, too. As all the joins are only applied to the already-narrowed-down results which matched the
Bookings.BookingUUID = '7A757221A8E4645C17002DF03754AB66'
The text was updated successfully, but these errors were encountered: