My team is building a C # web application that can generate custom reports that recombine data from the same basic set of SQL Server 2008 R2 tables in different ways. For example, a single dashboard page can combine a list of today's sales in each region, a list of the least-selling products and their trends over the past week, a list of top sales managers and 20 other indicators and charts. Under covers, a typical dashboard page will require at least 30 queries in 20+ different tables.
Unfortunately, it is impractical to “freeze” this data and pre-calculate it - we need to receive data in real time on the fly.
To make these pages fast, our trick was to identify different queries that retrieve the same underlying data. Then we compute the intermediate results from those base tables, cache these results in temporary tables, and then attach this temporary table to other tables to calculate the final results. Using this approach, we can reduce the I / O time and the time required for a particular panel by 10 times.
Our team would like to apply the same template to a similar page that uses LINQ-to-SQL to access data. We like LINQ for easy use in programming, for unit testing, etc. But performance stinks for the application described above, where we execute multiple queries, which may partially depend on the same underlying data.
Of course, I can call AsEnumerable()
to materialize the intermediate results of the query, but if the intermediate results are large, then getting the results to and from SQL denies the performance gain and creates inefficient parameterized queries using hundreds of elements of length IN (@p1, ... )
.
In an ideal world, LINQ-to-SQL will offer the AsServerEnumerable()
method, which will create a temporary table of intermediate results that I could reuse downstream without leaving the database.
Is there something similar?
If not, have you received any suggestions on how to make our server side “intermediate materialization” template work well on LINQ?
PS - I say "temporary table" and not "table variable" above, because temporary tables tend to work better with more expensive queries (parallel query plans, non-clustered indexes, etc.). But otherwise, all of the above applies to table variables.