[英]Fastest way to filter records from a heavy collection of datarows (500k-1m records)
[英]LINQ fastest way to update lots of records (>2m)
我有這個循環:
using(var db = new MainContext())
{
var q = db.tblInternalURLs;
foreach (var rec in q)
{
db.ExecuteCommand("UPDATE tblInternalURLS SET hash = '" + LoginAPI.GetSha1(rec.URL) + "' WHERE ID = " + rec.ID);
}
}
將更新查詢轉換為db.ExecuteCommand
已大大提高了速度,但我想知道是否有更快的方法來執行這些查詢,因為它仍然需要很長時間超過2,000,000條記錄。 我相信很多開銷都在最初的LINQ查詢中。 這個對嗎?
好吧,看到SQL Server支持散列,您可以通過編寫SQL查詢來一次性完成整個表,從而避免將任何數據帶到客戶端:
update
tblInternalURLS
SET
hash = HASHBYTES('SHA1',CONVERT(nvarchar(4000), URL))
如果散列存儲為字符串,則sys.fn_varbintohexsubstring
可能很方便。
以下內容應該更快,因為它將select
限制為僅返回所需的列。
更改:
var q = db.tblInternalURLs;
至:
var q = db.tblInternalURLs.Select(x => new { URL = x.URL, ID = x.ID }).ToList();
更快的方法是使用本機ADO.NET Prepare命令然后綁定參數而不是concat查詢字符串並生成許多不同的查詢(從DB的角度來看)。 每個新查詢必須由服務器解析...
這是片段
var conn = ...//get native connection from your context
var cmd = conn.CreateCommand();
cmd.CommandText = "UPDATE tblInternalURLS SET hash = @hash WHERE ID = @id";
var hashParam = cmd.CreateParameter();
//set parameter type and name
var idParam = cmd.CreateParameter();
//set parameter type and name
cmd.Parameters.Add(hashParam);
cmd.Parameters.Add(idParam);
//prepare command
cmd.Prepare();
foreach (var rec in q)
{
idParam.Value = rec.ID;
hashParam.Value = LoginAPI.GetSha1(rec.URL);
cmd.ExecuteNonQuery();
}
更新
如果您使用的是SQL Server且哈希列必須始終與URL同步,則可以修改tblInternalURLS表並將哈希列轉換為計算列。 在這種情況下,哈希列將始終與URL同步。
ALTER TABLE dbo.tblInternalURLS DROP COLUMN hash
ALTER TABLE dbo.tblInternalURLS
ADD hash AS
CAST(HASHBYTES('SHA1', URL) AS VARBINARY(20)) PERSISTED
我建議將您的查詢分頁。 現在你一次全部撤下所有2,000,000條記錄。 這是數據庫,網絡連接,客戶端內存等方面的消耗。
通過將其分解為幾個較小的查詢,每個查詢,例如幾千個,您可能會看到一些明顯的改進。
以下是一些用於分頁給定查詢的幫助程序:
public static IEnumerable<T> Paginate<T>(this IQueryable<T> query, int pageSize)
{
return GetPages(query, pageSize).SelectMany(x => x);
}
public static IEnumerable<IEnumerable<T>> GetPages<T>(this IQueryable<T> query, int pageSize)
{
for (int currentPage = 0; true; currentPage++)
{
IEnumerable<T> nextPage = query.Skip(currentPage * pageSize)
.Take(pageSize)
.ToList();
if (nextPage.Any())
yield return nextPage;
else
yield break;
}
}
如果您向Paginate(1000)
添加對查詢的調用,您應該至少看到一些改進。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.