6

I am trying to get 5 random number of rows from a large table (over 1 million rows) with a fast method.

So far what I have tested with these SQL queries:

Method 1

Select top 5 customer_id, customer_name 
from Customer TABLESAMPLE(1000 rows) 
order by newid()

This method estimated I/O cost is 0.0127546 so this is very fast (index scan nonclustered)

Method 2

select top 5 customer_id, customer_name 
from Customer 
order by newid()

This method's sort estimated I/O cost is 117.21189 and index scan nonclustered estimated I/O cost is 2.8735, so this is affecting performance

Method 3

select top 5 customer_id, customer_name 
from Customer 
order by rand(checksum(*))

This method's sort estimated I/O cost is 117.212 and index scan nonclustered estimated I/O cost is 213.149, this query is slower than all because estimated subtree cost is 213.228 so it's very slow.

UPDATE:

Method 4

select top 5 customer_id, customer_name, product_id
from Customer 
Join Product on product_id = product_id
where (customer_active = 'TRUE')
order by checksum(newid())

This approach is better and very fast. All the benchmark testing is fine.

QUESTION

How can I convert Method 4 to LINQ-to-SQL? Thanks

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
aadi1295
  • 982
  • 3
  • 19
  • 47
  • Are you asking about improve the random query performance or convert the query to LINQ? – Juan Carlos Oropeza May 08 '17 at 14:21
  • How random do you want the result to be? `TABLESAMPLE` is not really random (unless your rows are so large that only one fits on a page). – Gordon Linoff May 08 '17 at 14:22
  • @JuanCarlosOropeza Yes first I am looking to convert Method 1 to LINQ if not possible then I am looking for better approach. – aadi1295 May 08 '17 at 14:26
  • @GordonLinoff: Actually client just want to fill up the space so I just need 5 random rows to show without effecting the performance. – aadi1295 May 08 '17 at 14:27
  • if you want fill up space then why dont show up just TOP 5? – Juan Carlos Oropeza May 08 '17 at 14:28
  • @JuanCarlosOropeza Well he want to show random records even very old records or each page refresh not the latest. – aadi1295 May 08 '17 at 14:29
  • Well as gordon say, Method 1 isnt really random, so I would go for Method 2. And I woudlnt use LINQ for this. I rather create a function on db and then use EF to call that function to retrive the 5 records. – Juan Carlos Oropeza May 08 '17 at 14:34

2 Answers2

3

If you want to convert Method 2 into Linq To Entities just use the solution answered by jitender which look like this:

var randomCoustmers = context.Customers.OrderBy(x => Guid.NewGuid()).Take(5);

But for Method 1 which is very fast following your benchmarking, you need to do the following C# code because Linq To Entities doesn't have a LINQ equivalent for this SQL statement TABLESAMPLE(1000 rows).

var randomCoustmers = context.Customers.SqlQuery("Select TOP 5 customer_id, customer_name from Customer TABLESAMPLE(1000 rows) order by newid()").ToList();

You can move the SQL statements into a SQL View or Stored Procedure which will receive the number of customers to take.

UPDATE

For Method 4 which seems to be very fast (always by following your benchmark), you can do the following Linq To Entities:

var randomCoustmers = context.Customers.OrderBy(c => SqlFunctions.Checksum(Guid.NewGuid()).Take(5);

Entity Framework can translate into SQL all functions that are defined into SqlFunctions class. In those functions we have Checksum function which will do what you want.

If you want to join with other tables you can do it without difficulty with Linq To Entites so I just simplified my version by querying only the Customers DbSets.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
CodeNotFound
  • 22,153
  • 10
  • 68
  • 69
  • I am gonna test it, meanwhile I have updated the question, can you please check. Thanks – aadi1295 May 08 '17 at 15:10
  • Thanks so much. Method 4 with SqlFunctions working like charm. Very smooth and no load on the server. Thanks again :) – aadi1295 May 08 '17 at 16:34
0

As stated Here's the best way:

var randomCoustmers = Customers.OrderBy(x => Guid.NewGuid()).Take(5);
Community
  • 1
  • 1
jitender
  • 10,238
  • 1
  • 18
  • 44