[英]SQL Server : join on uniqueidentifier
我有两个表Backup
和Requests
。
以下是两个表的脚本
后备
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
位于varchar
和uniqueidentifier
,该uniqueidentifier
而不是像“等于”比较那样工作,而像“包含”比较那样工作。 我想知道它是如何工作的,以便可以确保在没有任何意外情况的情况下使用此代码。
比较两侧的值必须是相同的数据类型。 例如,没有比对uniqueidentifier
和varchar
比较。
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 MATCH
与EXPR 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.