【发布时间】:2018-09-18 05:20:21
【问题描述】:
假设我在 SQL Server 中有一个存储客户电子邮件的表(几百万条记录) - 为简单起见,如下所示:
CREATE TABLE [Emails]
(
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[email] [nvarchar](1000) NOT NULL
)
我有客户向我发送列表,每百万条记录长,他们的客户的电子邮件,但所有 MD5-Hash 加密,所以列表看起来如下:
0x3B46E0E53842A74172BA678974E93BBB
0xACAC5843E184C85AA6FF641AAB0AA644
0xD3C7BA16E02BE75142761894E8E4A125
...
我必须想出一个快速的方法来查看他们列表中的哪些电子邮件存在于我的表格中。
根据我在网上/这里看到的一些答案,我想出了以下逻辑来做到这一点:
-
我创建了
Emails表的索引视图,其中MD5-Hash列作为索引:CREATE VIEW dbo.vw_Emails WITH SCHEMABINDING AS SELECT Id , email , CONVERT(VARBINARY(16), HASHBYTES('MD5', LOWER(email))) AS MD5 FROM dbo.Emails GO CREATE UNIQUE CLUSTERED INDEX Idx_vw_Emails ON vw_Emails (MD5) GO -
我创建了一个存储过程,它将
BulkImport给定的列表,将其转换为临时表,将其加入我的视图并返回任何匹配的行,如下所示:CREATE PROCEDURE Import_ReturnMatches ( @PathToCSVFile VARCHAR(8000) ) AS DECLARE @fieldsep CHAR(1) = ','; DECLARE @recordsep CHAR(1) = CHAR(10); DECLARE @Emails TABLE ( MD5 VARCHAR(MAX) NOT NULL ); DECLARE @sql VARCHAR(8000) = 'CREATE TABLE #tmp ( MD5 varchar(max) NOT NULL ); BULK INSERT #tmp FROM ''' + @PathToCSVFile + ''' WITH (FIRSTROW = 1, FIELDTERMINATOR = ''' + @fieldsep + ''', ROWTERMINATOR = ''' + @recordsep + '''); SELECT * FROM #tmp'; INSERT INTO @Emails EXEC (@sql); SELECT r.* FROM @Emails l JOIN vw_Email_Dim r ON l.MD5 = r.MD5
如您所见,我将导入的列类型设置为VARCHAR(MAX),但这只是因为没有其他方法真正起作用......这就是我卡住的地方。即使我在文件中放置了应该匹配的记录,它似乎总是返回一个空集。
我的问题是:
- 我做错了什么/我该如何解决这个问题?
- 我是否为我的存储/索引/导入使用了正确的数据类型?
- 这只是一个整体的坏主意吗?有没有更好的方法来完成我想做的事情?
【问题讨论】:
-
如果可能的话,我会在您的表中添加另一列来存储您电子邮件的 MD5 哈希值。它肯定会使加入更快。电子邮件中字母的大小写也可能引起悲伤。
-
谢谢,@thomas,我很可能最终会这样做,但这仍然是对我公司的考验,所以在我证明这可行之前,他们不会让我更改生产表。不过,这确实是有道理的。
-
比较 binary 和 varchar 不会做你想要的。
-
@MartinSmith,我看到了这一点,这就是我的问题的症结所在 - 我怎样才能做到这一点?
-
您需要使用带有样式参数的
CONVERT将包含十六进制字符串的varchar 转换为varbinary,反之亦然
标签: sql-server join hash filter md5