作为 ETL 过程的一部分,我们将暂存中的行与报告数据库进行比较,以确定自上次加载数据以来是否有任何列实际发生了更改。
比较基于表的唯一键和所有其他列的某种散列。我们目前使用HASHBYTES
该SHA2_256
算法,并发现如果许多并发工作线程都在调用HASHBYTES
.
在 96 核服务器上进行测试时,以每秒哈希数衡量的吞吐量不会增加超过 16 个并发线程。我通过将并发MAXDOP 8
查询的数量从 1更改为12 来进行测试。测试MAXDOP 1
显示了相同的可扩展性瓶颈。
作为一种解决方法,我想尝试 SQL CLR 解决方案。这是我试图说明要求的尝试:
NVARCHAR
或VARBINARY
字符串的输入(所有相关列都连接在一起)CHECKSUM
对我们不起作用,因为冲突太多。对于 Application Reasons™,假设我无法保存报告表的哈希值。这是一个不支持触发器或计算列的 CCI(还有其他我不想讨论的问题)。
HASHBYTES
使用 SQL CLR 函数进行模拟的可扩展方式是什么?我的目标可以表示为在大型服务器上每秒获得尽可能多的哈希值,因此性能也很重要。我对 CLR 很糟糕,所以我不知道如何做到这一点。如果它激励任何人回答,我计划尽快为这个问题添加赏金。下面是一个示例查询,它非常粗略地说明了用例:
DROP TABLE IF EXISTS #CHANGED_IDS;
SELECT stg.ID INTO #CHANGED_IDS
FROM (
SELECT ID,
CAST( HASHBYTES ('SHA2_256',
CAST(FK1 AS NVARCHAR(19)) +
CAST(FK2 AS NVARCHAR(19)) …
Run Code Online (Sandbox Code Playgroud) 我们需要创建 nvarchar 数据的哈希值以进行比较。T-SQL 中有多种哈希算法可用,但在这种情况下,最好选择哪一种?
我们希望确保两个不同的 nvarchar 值具有重复哈希值的风险最小。根据我对互联网的研究,MD5 似乎是最好的。那正确吗?MSDN 告诉我们(下面的链接)有关可用算法的信息,但没有说明哪一种适用于什么条件?
我们需要在两个 nvarchar(max) 列上连接两个表。可以想象,执行查询需要很长时间。我们认为最好保留每个 nvarchar(max) 数据的散列值并对散列值进行连接,而不是 nvarchar(max) 值是 blob。问题是哪种哈希算法提供了唯一性,这样我们就不会遇到一个哈希值对应多个 nvarchar(max) 的风险。
我想在redis中创建这种类型的结构:(它基本上是json数据)
{
"id": "0001",
"name":"widget ABC",
"model": "model123",
"service":"standard",
"admin_password": 82616416,
"r1":
{
"extid":"50000",
"password":"test123",
},
"r2":
{
"ext":"30000",
"password":"test123",
},
}
Run Code Online (Sandbox Code Playgroud)
到目前为止我尝试过的:
我试图创建一个没有“子”哈希的哈希,只是为了确保我掌握了基本知识。所以这是我从 redis-cli 开始的:
HMSET widget:1 id 0001 name 'widget ABC' model 'model123' service standard admin_password 82616416
HMSET widget:2 id 0002 name 'widget ABC' model 'model123' service standard admin_password 12341234
Run Code Online (Sandbox Code Playgroud)
这似乎有效。我可以看到我在小部件集合中有 2 条小部件数据“记录”。
但是我尝试使用 r1 数据创建记录失败。
这是我尝试过的:
HMSET widget:3 id 0002 name 'widget ABC' model 'model123' service standard admin_password 12341234 r1{extid 50000}
Run Code Online (Sandbox Code Playgroud)
这将创建一个散列值“50000}”的散列键“r1{extid”
任何建议,将不胜感激。我认为我的问题是我的行话。我只是不太了解 redis 语法,无法知道在我的谷歌搜索中使用哪些词。
也许我只需要像这样“展平”数据:
HMSET …
Run Code Online (Sandbox Code Playgroud) 对于每个支持哈希索引的 Postgres 版本,都有一个警告或说明哈希索引与btree索引“相似或更慢”或“不更好” ,至少到版本 8.3。从文档:
注意:由于哈希索引的实用性有限,B 树索引通常比哈希索引更受欢迎。我们没有足够的证据表明即使对于 = 比较,哈希索引实际上也比 B 树更快。此外,哈希索引需要更粗的锁;见第 9.7 节。
注意:测试表明 PostgreSQL 的哈希索引与B 树索引相似或更慢,并且哈希索引的索引大小和构建时间要差得多。哈希索引在高并发下也表现不佳。由于这些原因,不鼓励使用哈希索引。
注意:测试表明 PostgreSQL 的哈希索引的性能并不比 B 树索引好,哈希索引的索引大小和构建时间要差得多。此外,哈希索引操作目前没有 WAL 日志记录,因此在数据库崩溃后可能需要使用 REINDEX 重建哈希索引。由于这些原因,目前不鼓励使用哈希索引。
在这个 8.0 版本的线程中,他们声称从未发现哈希索引实际上比 btree 更快的情况。
根据这篇博文(2016 年 3 月 14 日):André Barbosa撰写的
Postgres 上的哈希索引,即使在 9.2 版本中,除了编写实际索引之外,任何其他方面的性能提升几乎都没有。
我的问题是这怎么可能?
根据定义,哈希索引是一种O(1)
操作,而 …
在 SQL Server 中,Except运算符如何在幕后工作的内部算法是什么?它是否在内部获取每一行的哈希值并进行比较?
David Lozinksi 进行了一项研究,SQL:在不存在新记录的地方插入新记录的最快方法他表明,对于大量行,Except 语句是最快的;与我们下面的结果密切相关。
假设:我认为 Left join 会最快,因为它只比较 1 列,Except 花费的时间最长,因为它必须比较所有列。
有了这些结果,现在我们的想法是,Except 自动并在内部获取每一行的哈希值?我查看了除非执行计划,它确实使用了一些哈希。
背景:我们的团队正在比较两个堆表。表 A 不在表 B 中的行被插入到表 B 中。
堆表(来自旧文本文件系统)没有主键/guids/标识符。有些表有重复的行,所以我们找到每一行的Hash,并去除重复,并创建主键标识符。
1)首先我们运行一个except语句,排除(哈希列)
select * from TableA
Except
Select * from TableB,
Run Code Online (Sandbox Code Playgroud)
2)然后我们在HashRowId上的两个表之间运行左连接比较
select *
FROM dbo.TableA A
left join dbo.TableB B
on A.RowHash = B.RowHash
where B.Hash is null
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,Except Statement Insert 是最快的。
结果实际上与 David Lozinksi 的测试结果接近
performance sql-server hashing sql-server-2016 except performance-tuning
在聊天讨论中出现的一个问题:
我知道散列连接救助在内部切换到某种嵌套循环。
SQL Server 为散列聚合救助做了什么(如果它可以发生的话)?
sql-server aggregate execution-plan database-internals hashing
PostgreSQL 9.2
我试图了解Hash Semi Join
和 just之间的区别Hash Join
。
这里有两个查询:
一世
EXPLAIN ANALYZE SELECT * FROM orders WHERE customerid IN (SELECT
customerid FROM customers WHERE state='MD');
Hash Semi Join (cost=740.34..994.61 rows=249 width=30) (actual time=2.684..4.520 rows=120 loops=1)
Hash Cond: (orders.customerid = customers.customerid)
-> Seq Scan on orders (cost=0.00..220.00 rows=12000 width=30) (actual time=0.004..0.743 rows=12000 loops=1)
-> Hash (cost=738.00..738.00 rows=187 width=4) (actual time=2.664..2.664 rows=187 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 7kB
-> Seq Scan on customers (cost=0.00..738.00 rows=187 width=4) (actual …
Run Code Online (Sandbox Code Playgroud) 存储结果的最佳数据类型是HASHBYTES('MD5', ...)
什么?
它输出 16 字节的二进制如下:例如
0x5CFCD77F9FF836189D2F647EBCEA183E
Run Code Online (Sandbox Code Playgroud)
我可以将它存储在以下数据类型中:
char(34)
binary(16)
(我认为 - 我在这里读到(/sf/ask/1030561381/#16680423)使用相同的算法应该返回无论输入字符串如何,每次都具有相同数量的字节)每行都有一个值(没有空值),并且该列将用于与另一个表中的类似列进行比较。
哪种数据类型用于存储HASHBYTES
上述使用的输出的最佳数据类型?
我在想,因为固定长度的数据类型有时在连接等方面可能更有效。binary(16)
vs varbinary(8000)
(的默认输出HASHBYTES
)似乎最好,而binary(16)
vs avarchar(34)
更好,因为它会使用更少的存储空间。
我有一个运行速度很慢的查询(见下文)。同时寻找改善它的方式,我们发现,约十倍,如果我们更换了更快的查询运行LEFT OUTER JOIN与LEFT JOIN HASH
结果似乎是一样的。是吗?在什么情况下它不会返回相同的结果?有什么区别?在运行 LEFT HASH JOIN 而不是 LEFT OUTER JOIN 时,有什么我应该注意的吗?
查询中的[ABC].[ExternalTable]表是我添加为外部表的另一台服务器上的视图
SELECT t.foo, t.bar, t.data
FROM [dbo].[Table] as t
LEFT OUTER JOIN [ABC].[ExternalTable] as s ON s.foo = t.foo and s.bar = t.bar and s.data = t.data
WHERE s.foo is null and s.bar IS NULL and s.data IS NULL
Run Code Online (Sandbox Code Playgroud) 我使用服务器端散列来传输密码,然后在数据库中运行 PBKDF2 来存储散列密码 + 盐组合。
散列nvarchar(max)
和@variable
持有相同值的HASHBYTES()
函数会产生不同的结果。
DECLARE @hash NVARCHAR(MAX) = 'password5baa61e4c9b93f3f0682250b6'
SELECT HASHBYTES('SHA1', 'password5baa61e4c9b93f3f0682250b6') AS NVARCHAR_INPUT,
HASHBYTES('SHA1', @hash) AS VARIABLE_INPUT
Run Code Online (Sandbox Code Playgroud)
产生以下结果:
NVARCHAR_INPUT | VARIABLE_INPUT
0xA03BEF0E3EC96CC7C413C6646D3FEC6174DA530F | 0x74B55C42E1E0AB5C5CDF10B28567590B240355C3
Run Code Online (Sandbox Code Playgroud)
这是 SQL Server 2012。这个特定的数据库正在运行 SQL Server Express,所以我也很好奇这个问题是否与版本无关。