我们有一个 SQL 2016 数据库,它有一个 19 亿行的表,其中有一个 varbinary(255) 列,我们用它来将 nvarchar(2000) 字段的 HashBytes 存储在同一个表中。
我们在 varbinary 字段上有一个非聚集索引,我们的索引维护脚本每 2-3 天对此执行一次 REORGANIZE。但这需要10多个小时才能完成。
有什么方法可以提高 varbinary 字段的索引维护速度?
我们有一个 SQL 2016 数据库,它有一个 19 亿行的表,其中有一个 varbinary(255) 列,我们用它来将 nvarchar(2000) 字段的 HashBytes 存储在同一个表中。
我们在 varbinary 字段上有一个非聚集索引,我们的索引维护脚本每 2-3 天对此执行一次 REORGANIZE。但这需要10多个小时才能完成。
有什么方法可以提高 varbinary 字段的索引维护速度?
如果您有一个包含 19 亿行的表,我猜它的百分比变化率相当低。检查您每天实际插入/更新的行数 - 可能少于 1%。
在这种情况下,每 2-3 天重新组织一次整个表是没有意义的(特别是考虑到它需要 10 多个小时。)我会首先每周只进行一次索引维护,如果不是每月一次的话尺寸。
首先退后一步问:“我试图通过索引重组来解决什么问题?” 如果答案是缓慢的选择语句,那么对 19 亿行表的索引维护将不是答案。
根据评论,我关于使用的问题是因为我希望存在这个索引来检查现有记录,即单例查找,没有扫描行为。考虑到这一点,我呼应@BrentOzar,经常重组不太可能产生任何切实的好处。关掉它,看看 ETL 性能是否会恶化,我怀疑不会。
如果有修改 ETL 过程的空间,那么我会考虑转储
VARBINARY
哈希并替换为BIGINT
. 我在数据仓库 ETL 过程中使用了类似的安排:在这个用例中,由于截断而导致的冲突不是问题。哈希用于通过由 8 字节键组成的索引而不是 255 字节的索引来检查行是否已经存在,或者用于扫描包含 4000 字节列的表。如果检查没有产生任何行,则插入。如果哈希匹配,则对原始文本进行比较以确定您是否有现有行或需要插入。
FILLFACTOR
NonClustered 索引上有什么?你用的是什么哈希算法?该指数是否已PAD_INDEX
设置为ON
?聚集索引(包括列数据类型)的定义是什么?所有这些都将使我们更清楚地了解该指数的物理构成。
还发生了哪些其他操作?意思是,你更新
NVARCHAR(2000)
专栏了吗?你删除很多行吗?唯一应该增加碎片的事情是:常规插入(因为哈希实际上是“随机”排序的),对NVARCHAR
字段的更新,因为这将改变哈希的值(但不是大小),以及大量的删除。这些问题的答案将使我们更清楚地了解碎片化如何/为什么会增加。
此外,除了碎片级别达到 Ola 脚本推荐碎片整理的默认限制之外,您是否发现不进行碎片整理时 ETL 性能有任何下降?
此外,我还会小心地将散列值转换为只有 8 个字节的
BIGINT
给定值,但所有散列算法——甚至MD5——都大于 8 个字节(MD5 = 16 字节,SHA1 = 20,SHA2_256 = 32 和SHA2_512 = 64)。并且将大于 8 字节的二进制值转换为静默截断值,因此您会失去准确性并增加误报的发生率。以下查询显示了这种行为:BIGINT
BIGINT
当然,根据@Marks 对用法的解释,这种截断可能只会增加对
NVARCHAR
字段进行全面比较的频率。尽管如此,人们还是应该意识到这种行为,因为它是一种无声(即非显而易见的)截断。