我对一行的内容不感兴趣,我只是想知道一行是否存在。 Name
列是主键,因此将有0或1个匹配的行。目前,我正在使用:
if ((from u in dc.Users where u.Name == name select u).Count() > 0)
// row exists
else
// row doesn't exist
虽然上述方法有效,但通过选择行的所有内容(如果存在),它会做很多不必要的工作。以下是否会创建更快的查询:
if (dc.Users.Where(u => u.Name == name).Any())
...还是有更快的查询?
答案 0 :(得分:85)
Count()
方法可能会做额外的工作,因为(在TSQL中)EXISTS
或TOP 1
通常要快得多; db可以优化“至少有一行”。就个人而言,我会使用any / predicate重载:
if (dc.Users.Any(u => u.Name == name)) {...}
当然,你可以通过观察TSQL来比较每个人做的事情:
dc.Log = Console.Out;
答案 1 :(得分:11)
当然
if (dc.Users.Where(u => u.Name == name).Any())
这是最好的,如果要检查多个条件,那么写为
非常简单假设您要检查公司的用户
if (dc.Users.Where(u => u.ID== Id && u.Company==company).Any())
答案 2 :(得分:4)
我想:
if (dc.Users.Any(u => u.Name == name)) {...}
是最好的方法。
答案 3 :(得分:1)
对于那些声称Any()是前进的人,我已经在LinqPad中对CommonPasswords的SQL数据库进行了一次简单的测试,有1400万人给予或接受。 代码:
var password = "qwertyuiop123";
var startTime = DateTime.Now;
"From DB:".Dump();
startTime = DateTime.Now;
if (CommonPasswords.Any(c => System.Data.Linq.SqlClient.SqlMethods.Like(c.Word, password)))
{
$"FOUND: processing time: {(DateTime.Now - startTime).TotalMilliseconds}\r\n".Dump();
}
else
{
$"NOT FOUND: processing time: {(DateTime.Now - startTime).TotalMilliseconds}\r\n".Dump();
}
"From DB:".Dump();
startTime = DateTime.Now;
if (CommonPasswords.Where(c => System.Data.Linq.SqlClient.SqlMethods.Like(c.Word, password)).Count() > 0)
{
$"FOUND: processing time: {(DateTime.Now - startTime).TotalMilliseconds}\r\n".Dump();
}
else
{
$"NOT FOUND: processing time: {(DateTime.Now - startTime).TotalMilliseconds}\r\n".Dump();
}
"From DB:".Dump();
startTime = DateTime.Now;
if (CommonPasswords.Where(c => c.Word.ToLower() == password).Take(1).Any())
{
$"FOUND: processing time: {(DateTime.Now - startTime).TotalMilliseconds}\r\n".Dump();
}
else
{
$"NOT FOUND: processing time: {(DateTime.Now - startTime).TotalMilliseconds}\r\n".Dump();
}
这是翻译过的SQL:
-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'qwertyuiop123'
-- EndRegion
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [Security].[CommonPasswords] AS [t0]
WHERE [t0].[Word] LIKE @p0
) THEN 1
ELSE 0
END) AS [value]
GO
-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'qwertyuiop123'
-- EndRegion
SELECT COUNT(*) AS [value]
FROM [Security].[CommonPasswords] AS [t0]
WHERE [t0].[Word] LIKE @p0
GO
-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'qwertyuiop123'
-- EndRegion
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT TOP (1) NULL AS [EMPTY]
FROM [Security].[CommonPasswords] AS [t0]
WHERE LOWER([t0].[Word]) = @p0
) AS [t1]
) THEN 1
ELSE 0
END) AS [value]
你可以看到ANY将查询包装在另一层代码中,以执行CASE Where Exists Then 1,其中Count()只是在Count命令中添加。这两个问题都是你不能做Top(1)但我看不到使用Top(1)
的更好方法结果:
来自DB: 发现:处理时间:13.3962
来自DB: 发现:处理时间:12.0933
来自DB: 发现:处理时间:787.8801
再次:
来自DB: 完成:处理时间:13.3878
来自DB: 发现:处理时间:12.6881
来自DB: 发现:处理时间:780.2686
再次:
来自DB: 发现:处理时间:24.7081
来自DB: 完成:处理时间:23.6654
来自DB: 发现:处理时间:699.622
没有索引:
来自DB: 发现:处理时间:2395.1988
来自DB: 发现:处理时间:390.6334
来自DB: 发现:处理时间:664.8581
现在有些人可能认为它只有一两毫秒。然而,在我给它做一个索引之前,差异要大得多;几秒钟。
最后一次计算是因为我开始认为ToLower()比LIKE更快,我是对的,直到我尝试计数并在其上放置一个索引。我猜Lower()使索引无关紧要。
答案 4 :(得分:0)
我不同意选择top 1总是优于所有SQL实现的select count。你知道,这完全依赖于实现。奇怪的是,即使存储在特定数据库中的数据的性质也会影响整体结果。
如果我这样做,让我们检查它们的实现方式:对于这两种情况,投影(WHERE子句)评估是一个常见的步骤。
接下来选择top 1,你必须读取所有字段(除非你确实选择了top 1'x',例如:select top 1 1)。这将在功能上等同于IQueryable.Any(...)。,除非您将花费一些时间在第一个遇到的记录的每一列的值中闪烁(如果是EXISTS)。如果在语句中找到SELECT TOP,则如果没有后投影过程(例如ORDER BY子句),则投影将被截断。这个预处理会产生很小的成本,但如果没有记录就会产生额外的成本,在这种情况下,仍然会完成一个完整的项目。
对于选择计数,不执行预处理。完成投影,如果EXISTS为假,则结果是即时的。如果EXISTS为真,则计数仍然很快,因为它只是dW_Highest_Inclusive - dW_Lowest_Exclusive。快到500 - 26.如果存在是假的,结果会更加迅速。
因此剩下的情况是:投影的速度有多快以及通过全投影放松了什么?答案导致最关键的问题是:[NAME]字段是否已编入索引!如果你在[NAME]上有一个索引,那么任何一个查询的性能都会非常接近开发人员的偏好。
总的来说,我会简单地写两到四个linq查询并输出前后时间差异。
在[NAME];
上使用非聚集索引重复全部4