This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Using LightSpeed 5.0.2872, specifically when paging, LightSpeed generates code (in my project) as follows:
The Reads count is 106106 (from SQL profiler), or approximately 829MB This appears to be projecting first and then filtering, because if I re-write it as follows:
the number of reads drops to 203, or approximately 1.6MB. This is 0.2% of the original number of reads (CPU and Duration are also greatly decreased, even with the potential double sorting to maintain proper ordering). Am I missing something, or could LightSpeed's paging implementation be greatly improved? Of course many other factors may be coming into play here (Indexes, Statistics, etc etc etc)... However, LightSpeed's query text appears to be projecting all of the resultant columns into the derived table in addition to RowNumber, from which only one page's worth is actually selected (however large that page may be). Using a CTE, I'm able to project just the Primary Key and RowNumber, and then, perform the paging operation (and re-sort to maintain the order over the "in" clause, though even that seems to be unnecessary). (SQL Version: SQL Server 2012 Service Pack 2, LightSpeed dataProvider="SqlServer2008") Thanks, ~Bill |
|
|
What is the query you are running in your code? The first query would be generated if we cannot translate the query into a server side projection so have to select the whole table to perform a client side projection. Note: We will never produce a CTE as part of the SQL translation as this is not an available syntax across all providers.
|
|
|
This is my code:
LightSpeed generates the following SQL:
If I run just the following (manually replacing @p0 and @p1):
Reads are 80,591. If I convert the above as follows:
Reads are 256. I understand CTE's are not available across all providers, but I'm specifically using the LightSpeed "SqlServer2008" provider, and SQL Server 2008 supports CTE's (actually, SQL 2005-2014 as far as I can tell). I would have thought specific providers would be coded specifically for their target databases... It just so happens that I have an index that contains "EndDTTM", "DeletedOn", and implicitly "Id," which is where the performance comes from, but projecting all columns in the derived table forces SQL to never use this index (whether it exists or not) and incurs a very costly clustered key lookup to fulfill the projection... I don't think mine is that much of an edge case, I'm simply sorting and paging entities from LightSpeed... Please don't misunderstand, I'm not trying to criticize MindScape or LightSpeed (it is, after all, my OR/M tool of choice), however, if I did stumble on an area for (potentially great, 314 times fewer reads in my case) performance improvement, I'd like to see it built into LightSpeed :) Thanks, ~Bill |
|
|
Hi Bill, Thanks for the clarification. We select all columns because they are needed when populating the entity for hydrating the result set. If you approached this with 2 queries (e.g. first select the Ids, then select the entities which matched those id's) I am guessing you would see similar results in terms of the number of reads. I certainly know what you are meaning about CTEs being something we could leverage when using the SQL 2005 or higher providers (clearly they do perform a lot better for this type of case!). Its not really supportable in our current query pipeline but Ill do some investigation into how we might be able to approach something like this and let you know if we can make an improvement here.
|
|
|
I understand the need to select all columns to hydrate the entity, which is why I have the following in my code:
Also, my revised query:
appears to actually be considered a single Query (both by actual execution plan, and by Profiler as a complete SQL Batch), and this part:
cannot be run independent of this part:
The total reads remains ~200. What I believe is happening, is that your derived table, the inner:
is reading the entirety of the RWXListings table (WHERE RWXListings.DeletedOn IS NULL) simply to prepare for the final select, filtered by RowNumber:
I understand your current query pipeline wouldn't really support a modification like this, and you therefore may never implement it, but I appreciate the consideration. Thanks, ~Bill |
|
|
Additionally, you mentioned:
This is very true if I didn't just so happen to have an index on "EndDTTM", "DeletedOn", and implicitly "Id." But by virtue of having such a small index, the reads are MUCH lower to get the PK's (Id) for the final result set. (Index Scan for a small index, vs. Table Scan for a large table). The performance gap between the two queries (LightSpeed's, and my proposal) is greatly amplified the larger (or wider) the Entity table is vs. the requested page size. i.e. Say my RWX_Listings table contained a billion rows, and I wanted to return the 600th page (of size 1). As written, SQL would read and fully project all columns for a billion rows (potentially spilling to tempdb, etc...) to return only a single row's worth of data. Again, I thank you for the consideration. Thanks again, ~Bill |
|