Solution 1
首先,來看這個看起來最簡潔的方式。
var Result = DB.Country_IPs.AsEnumerable().OrderBy(p => Guid.NewGuid()).Take(1);
這個效果等同於
select top 1 * from [dbo].[Country_IP] order by NewID()
我沒仔細研究內部是怎麼運作的,不過看起來是將資料都讀進程式後才作亂數排序,所以實際跑起來的速度甚至比select all的速度還慢上一點,在我的電腦上對約有11萬筆資料的table進行操作,約要800~900ms的時間,所以建議要使用這方法最好是對資料量小的資料表進行操作,不然會拖慢不少速度。
Solution 2
另一個方法則是要對Data Model做點手腳,在你的DataContext中,加上下面這段
[System.Data.Linq.Mapping.Function(Name = "NEWID", IsComposable = true)]
public System.Guid Random()
{
throw new System.NotImplementedException();
}
如果不知道去那加的話,可以在Solution Explorer裡,把你的dbml點開,然後去裡面的cs加。

加完之後長的這個樣子

然後接下來的實用就很簡單了,只要orderby我們剛剛建的function就好。
var Result = (from p in DB.Country_IPs orderby DB.Random() select p).Take(1);
第二個方法的速度比第一個快很多,與使用SqlDataAdapter去跑的速度相比,只慢了大約100ms,個人覺得是相當不錯的選擇,可以參考看看。

the other test
by the way,我後來試了一下保哥的作法,原本想說從DB做應該會更快點,沒想到速度比第一種方式還慢,蠻出乎我意料的。

保哥看到別生氣啊XDDDDD
test code
最後附上落落長的測試code,歡迎大家提出指正與改進之處:)
LINQDemoDataContext DB = new LINQDemoDataContext();
string queryString = "select top 1 * from [dbo].[Country_IP] order by NewID()";
int start, end;
DataSet dt = new DataSet();
DB.Log = Console.Out;
Console.WriteLine("LINQ to SQL");
start = System.Environment.TickCount;
//var Result = DB.Country_IPs.AsEnumerable().OrderBy(p => Guid.NewGuid()).Take(1);
//var Result = (from p in DB.Country_IPs orderby DB.Random() select p).Take(1);
var Result = (from p in DB.Country_IPs orderby DB.GetNewId() select p).Take(1);
end = System.Environment.TickCount;
foreach (var item in Result)
{
Console.WriteLine(item.IPStart + "\t" + item.IPEnd + "\t" + item.NumStart + "\t" + item.NumEnd + "\t" + item.Short + "\t" + item.Long);
}
Console.WriteLine("Run Time:" + (end - start));
Console.WriteLine();
Console.WriteLine("SqlDataAdapter");
Console.WriteLine(queryString);
start = System.Environment.TickCount;
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(queryString, connection);
adapter.Fill(dt);
}
end = System.Environment.TickCount;
for (int i = 0; i < dt.Tables.Count; i++)
{
Console.WriteLine("Table " + i.ToString() + " [" + dt.Tables[i].TableName + "]");
for (int j = 0; j < dt.Tables[i].Columns.Count; j++)
{
Console.Write(dt.Tables[i].Columns[j].ColumnName + "\t");
}
Console.WriteLine();
for (int j = 0; j < dt.Tables[i].Rows.Count; j++)
{
for (int k = 0; k < dt.Tables[i].Columns.Count; k++)
{
Console.Write(dt.Tables[i].Rows[j][k].ToString() + "\t");
}
Console.WriteLine();
}
}
Console.WriteLine("Run Time:" + (end - start));
Console.ReadLine();
No comments:
Post a Comment