簡體   English   中英

SQL Server:在uniqueidentifier上加入

[英]SQL Server : join on uniqueidentifier

我有兩個表BackupRequests

以下是兩個表的腳本

后備

CREATE TABLE UserBackup(
           FileName varchar(70) NOT NULL,
        )

文件名由GUID表示。 有時還有一些與文件有關的其他信息。 因此,我們在表中輸入了類似guid_ADD的條目。

要求

CREATE TABLE Requests(
           RequestId UNIQUEIDENTIFIER NOT NULL,
           Status int Not null
        )

以下是一些示例行:

UserBackup表:

FileName
15b993cc-e8be-405d-bb9f-0c58b66dcdfe 
4cffe724-3f68-4710-b785-30afde5d52f8 
4cffe724-3f68-4710-b785-30afde5d52f8_Add
7ad22838-ddee-4043-8d1f-6656d2953545

請求表:

RequestId                              Status
15b993cc-e8be-405d-bb9f-0c58b66dcdfe    1
4cffe724-3f68-4710-b785-30afde5d52f8    1
7ad22838-ddee-4043-8d1f-6656d2953545    2

我需要從userbackup表中返回所有行,該表的名稱(GUID)與Requests表中的RequestId匹配,並且狀態為1。所以這是我編寫的查詢

Select * 
from UserBackup
inner join Requests on UserBackup.FileName = Requests.RequestId
where Requests.Status = 1

這很好。 它給我以下結果

FileName                                      RequestId                              Status
15b993cc-e8be-405d-bb9f-0c58b66dcdfe          15b993cc-e8be-405d-bb9f-0c58b66dcdfe     1
4cffe724-3f68-4710-b785-30afde5d52f8          4cffe724-3f68-4710-b785-30afde5d52f8     1
4cffe724-3f68-4710-b785-30afde5d52f8_Add      4cffe724-3f68-4710-b785-30afde5d52f8     1

這正是我想要的。 但是我不明白它是如何工作的。 如果您注意到結果也返回4cffe724-3f68-4710-b785-30afde5d52f8_Add行。 內部uniqueidentifier位於varcharuniqueidentifier ,該uniqueidentifier而不是像“等於”比較那樣工作,而像“包含”比較那樣工作。 我想知道它是如何工作的,以便可以確保在沒有任何意外情況的情況下使用此代碼。

比較兩側的值必須是相同的數據類型。 例如,沒有比對uniqueidentifiervarchar比較。

uniqueidentifier優先級高於varchar因此在進行比較之前, varchar將被轉換為uniqueidentifier

不幸的是,如果該字符串包含的字符數超過所需數量,則不會出現任何錯誤或警告:

select CONVERT(uniqueidentifier,'4cffe724-3f68-4710-b785-30afde5d52f8_Add')

結果:

4CFFE724-3F68-4710-B785-30AFDE5D52F8

如果要強制在字符串之間進行比較,則必須執行顯式轉換:

Select * 
from UserBackup
inner join Requests
on UserBackup.FileName = CONVERT(varchar(70),Requests.RequestId)
where Requests.Status = 1

當您比較不同數據類型的兩列時,SQL Server將嘗試以較低的優先級進行隱式轉換。

以下是來自uniqueidentifier MSDN文檔

下面的示例演示了當值對於要轉換為的數據類型而言太長時,數據將被截斷。 因為uniqueidentifier類型限制為36個字符,所以超過該長度的字符將被截斷。

DECLARE @ID nvarchar(max) = N'0E984725-C51C-4BF4-9960-E1C80E27ABA0wrong'; 
SELECT @ID, CONVERT(uniqueidentifier, @ID) AS TruncatedValue;

http://msdn.microsoft.com/en-us/library/ms187942.aspx

文檔清楚數據被截斷

每當您不確定聯接操作時,都可以驗證“ Actual Execution Plan

這是可以在SSMS或SQL Sentry Plan Explorer中運行的測試示例

DECLARE @userbackup TABLE ( _FILENAME VARCHAR(70) )

INSERT INTO @userbackup
    VALUES  ( '15b993cc-e8be-405d-bb9f-0c58b66dcdfe' ),
            ( '4cffe724-3f68-4710-b785-30afde5d52f8' ),
            ( '4cffe724-3f68-4710-b785-30afde5d52f8_Add' )
,           ( '7ad22838-ddee-4043-8d1f-6656d2953545' )


DECLARE @Requests TABLE
    (
     requestID UNIQUEIDENTIFIER
    ,_Status INT
    )
INSERT INTO @Requests
    VALUES  ( '15b993cc-e8be-405d-bb9f-0c58b66dcdfe', 1 )
,           ( '4cffe724-3f68-4710-b785-30afde5d52f8', 1 )
,           ( '7ad22838-ddee-4043-8d1f-6656d2953545', 2 )

SELECT *
    FROM @userbackup u
    JOIN @Requests r
        ON u.[_FILENAME] = r.requestID
    WHERE r.[_Status] = 1

而不是常規join運行SQL Server正在做HASH MATCHEXPR 1006 SSMS中是很難看到什么做什么,但如果你打開XML文件,你會發現這個

<ColumnReference Column="Expr1006" />
<ScalarOperator ScalarString="CONVERT_IMPLICIT(uniqueidentifier,@userbackup.[_FILENAME] as [u].[_FILENAME],0)">

如有疑問,請檢查執行計划,並在比較時始終確保匹配數據類型。

這是很棒的博客,WHERE子句上的數據不匹配可能會導致 Microsoft工程師針對確切問題產生嚴重的性能問題。

這里發生的是FileName正在從varchar轉換為UniqueIdentifier,並且在此過程中,它將忽略前36個字符之后的任何內容。

您可以在這里看到它的運行情況

Select convert(uniqueidentifier, UserBackup.FileName), FileName
  from UserBackup

它可以工作,但是為了減少下一個人的困惑,您可能希望將與UserBackup關聯的RequestId作為GUID存儲在UserBackup表中並加入。

至少在;)中發表評論;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM