繁体   English   中英

使用Linq to SQL确定行是否存在的最快方法是什么?

[英]What is the fastest way to determine if a row exists using Linq to SQL?

我对行的内容不感兴趣,我只想知道是否存在行。 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())

...或者是否有更快的查询?

Count()方法可能会做额外的工作,因为(在TSQL中) EXISTSTOP 1通常要快得多; db可以优化“至少有一行”。 就个人而言,我会使用any / predicate重载:

if (dc.Users.Any(u => u.Name == name)) {...}

当然,你可以通过观察TSQL来比较每个人做的事情:

dc.Log = Console.Out;

当然

if (dc.Users.Where(u => u.Name == name).Any())

这是最好的,如果要检查多个条件,那么写起来非常简单

假设您要检查公司的用户

if (dc.Users.Where(u => u.ID== Id && u.Company==company).Any())

我认为:

if (dc.Users.Any(u => u.Name == name)) {...}

是最好的方法。

对于那些声称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:FOUND:处理时间:13.3962

来自DB:FOUND:处理时间:12.0933

来自DB:FOUND:处理时间:787.8801

再次:

来自DB:FOUND:处理时间:13.3878

来自DB:FOUND:处理时间:12.6881

来自DB:FOUND:处理时间:780.2686

再次:

来自DB:FOUND:处理时间:24.7081

来自DB:FOUND:处理时间:23.6654

来自DB:FOUND:处理时间:699.622

没有索引:

来自DB:FOUND:处理时间:2395.1988

来自DB:FOUND:处理时间:390.6334

来自DB:FOUND:处理时间:664.8581

现在有些人可能认为它只有一两毫秒。 然而,在我给它做一个索引之前,差异要大得多; 几秒钟。

最后的计算是在那里,我开始认为ToLower()比LIKE更快,我是对的,直到我尝试计数并在其上放置一个索引。 我猜Lower()使索引无关紧要。

我不同意选择top 1总是优于所有SQL实现的select count。 你知道,这完全依赖于实现。 奇怪的是,即使存储在特定数据库中的数据的性质也会影响整体结果。

让我们按照我实现它们的方式检查它们:对于这两种情况,投影(WHERE子句)评估是一个常见的步骤。

对于选择前1的下一个,您将必须读取所有字段(除非您确实选择了前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查询并输出前后时间差。

  1. 选择计数
  2. 选择前1名
  3. 选择前1 1
  4. 选择任何

在[NAME]上使用非聚集索引重复全部4;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM