我有这个循环:
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查询中。这是对的吗?
答案 0 :(得分:10)
好吧,看到SQL Server支持散列,您可以通过编写SQL查询来一次性完成整个表格,从而避免将任何数据带到客户端:
update
tblInternalURLS
SET
hash = HASHBYTES('SHA1',CONVERT(nvarchar(4000), URL))
如果哈希值存储为字符串,sys.fn_varbintohexsubstring
可能会很方便。
答案 1 :(得分:1)
以下内容应该更快,因为它限制select
仅返回所需的列。
变化:
var q = db.tblInternalURLs;
要:
var q = db.tblInternalURLs.Select(x => new { URL = x.URL, ID = x.ID }).ToList();
答案 2 :(得分:1)
更快的方法是使用本机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表并将哈希列转换为 computed 列。在这种情况下,哈希列将始终与URL同步。
ALTER TABLE dbo.tblInternalURLS DROP COLUMN hash
ALTER TABLE dbo.tblInternalURLS
ADD hash AS
CAST(HASHBYTES('SHA1', URL) AS VARBINARY(20)) PERSISTED
答案 3 :(得分:1)
我建议您对查询进行分页。现在你一次全部撤下所有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)
来电,则至少会看到一些改进。