SQL 服务器 - 比较大量 MD5 哈希值
SQL Server - Compare large number of MD5-Hashed Values
假设我在 SQL 服务器中有一个 table 存储客户电子邮件(几百万条记录)- 为简单起见,看起来如下所示:
CREATE TABLE [Emails]
(
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[email] [nvarchar](1000) NOT NULL
)
我有一些客户向我发送他们客户电子邮件的列表,每个列表都有数百万条记录,但所有 MD5-Hash
都经过加密,因此列表看起来如下所示:
0x3B46E0E53842A74172BA678974E93BBB
0xACAC5843E184C85AA6FF641AAB0AA644
0xD3C7BA16E02BE75142761894E8E4A125
...
而且我必须想出一个快速的方法来查看我的 table 中存在他们列表中的哪些电子邮件。
根据我在网上/这里看到的一些答案,我想出了以下逻辑来做到这一点:
我创建了 Emails
table 的索引视图,其中 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
给定的列表,将其转换为临时 table,根据我的观点加入它,并 return 任何匹配的行如下:
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)
,但这只是因为没有其他任何方法真正起作用...这就是我遇到的问题。它似乎总是 return 一个空集,即使我已经在我的文件中放置了应该匹配的记录。
我的问题是:
- 我做错了什么/我该如何解决?
- 我的存储/索引/导入是否使用了正确的数据类型?
- 这只是一个整体上的坏主意吗?是否有更好的方法来完成我想要做的事情?
您的问题可能是这个值:
LOWER(email)
如果您不确定使用何种大小写或编码(Windows 1252、UTF8、UTF16、UTF16LE?)从来源处的电子邮件生成 MD5 哈希值,那么您正在寻找需要测试所有组合的匹配哈希值。考虑我们在哪里将 LOWER
更改为 UPPER
- 生成了一个完全不同的 MD5 哈希值:
您将需要控制如何在源中生成 MD5 哈希,或者将元数据(另一个字段)添加到导入中以描述输入的大小写和编码方式。
检查这个答案。您需要将 varchar 与 varchar 进行比较——我认为不是 varbinary。
Generate MD5 hash string with T-SQL
假设我在 SQL 服务器中有一个 table 存储客户电子邮件(几百万条记录)- 为简单起见,看起来如下所示:
CREATE TABLE [Emails]
(
[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[email] [nvarchar](1000) NOT NULL
)
我有一些客户向我发送他们客户电子邮件的列表,每个列表都有数百万条记录,但所有 MD5-Hash
都经过加密,因此列表看起来如下所示:
0x3B46E0E53842A74172BA678974E93BBB
0xACAC5843E184C85AA6FF641AAB0AA644
0xD3C7BA16E02BE75142761894E8E4A125
...
而且我必须想出一个快速的方法来查看我的 table 中存在他们列表中的哪些电子邮件。
根据我在网上/这里看到的一些答案,我想出了以下逻辑来做到这一点:
我创建了
Emails
table 的索引视图,其中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
给定的列表,将其转换为临时 table,根据我的观点加入它,并 return 任何匹配的行如下: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)
,但这只是因为没有其他任何方法真正起作用...这就是我遇到的问题。它似乎总是 return 一个空集,即使我已经在我的文件中放置了应该匹配的记录。
我的问题是:
- 我做错了什么/我该如何解决?
- 我的存储/索引/导入是否使用了正确的数据类型?
- 这只是一个整体上的坏主意吗?是否有更好的方法来完成我想要做的事情?
您的问题可能是这个值:
LOWER(email)
如果您不确定使用何种大小写或编码(Windows 1252、UTF8、UTF16、UTF16LE?)从来源处的电子邮件生成 MD5 哈希值,那么您正在寻找需要测试所有组合的匹配哈希值。考虑我们在哪里将 LOWER
更改为 UPPER
- 生成了一个完全不同的 MD5 哈希值:
您将需要控制如何在源中生成 MD5 哈希,或者将元数据(另一个字段)添加到导入中以描述输入的大小写和编码方式。
检查这个答案。您需要将 varchar 与 varchar 进行比较——我认为不是 varbinary。
Generate MD5 hash string with T-SQL