Last week we had some performance issues in a bitemporal model, which by the looks of it was the result of a poorly selected execution plan in SQL Server. The reasoning behind this conclusion was that if parts of the query were first run separately with results stored in temp tables, and these later used, the issues were gone. This had me thinking though: Could something be done in order to get a better plan through the point-in-time views?
I first set about testing different methods of finding the row in effect in a unitemporal solution. In order to do so, a script was put together that creates a test bench along with a number of functions utilizing different methods. This is the script in case you would like to reproduce the test. Note that some tricks had to be employed for some methods in order to retain table elimination, a crucial feature, that may very well have skewed those results towards the negative.
The best performers in this test are the “OUTER APPLY” and “TOP 1 SUBSELECT”. We are already using the “TOP 1 SUBSELECT” variant, and they are almost tied for first place, so perhaps not much can be gained after all. That said, the execution pattern is very different between the two, so it’s hard to draw any conclusions without proper testing for the bitemporal case.
In the bitemporal point-in-time views, the rows in effect method has to be used twice. First to find the latest asserted posits, and then from those, the ones with the latest appearance time. So, I set about testing the four possible combinations of the two best approaches on one million rows in an example model. The results are summarized below (you may need to click to enlarge the images unless you have a really good monitor and incredible eye sight).
TOP 1 SUBSELECT appearance TOP 1 SUBSELECT assertion
Time to run: 8.0 seconds. This is the current approach.
OUTER APPLY appearance OUTER APPLY assertion
Time to run: 5.1 seconds. Better than current, even if the estimated cost is worse.
TOP 1 SUBSELECT appearance OUTER APPLY assertion
Time to run: 9.5 seconds. Worse than current.
OUTER APPLY appearance TOP 1 SUBSELECT assertion
Time to run: 3.9 seconds. Better than current, and lower estimated cost.
The last of the alternatives above cuts the execution time in half for the test we ran. It also has the simplest execution plan of them all. This seems promising, given that our goal was to get the optimizer to pick a good plan in a live and complex environment. I will be rewriting the logic in the generator for bitemporal models during the week to utilize this hybrid method of OUTER APPLY and TOP 1 SUBSELECT.