簡體   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