select POWER(2.,64.)
返回18446744073709552000
而不是18446744073709551616
. 它似乎只有 16 位精度(四舍五入第 17 位)。
即使使精度明确,select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0)))
它仍然返回四舍五入的结果。
这似乎是一个非常基本的操作,因为它可以像这样以 16 位精度任意剥离。它可以正确计算的最高值仅为POWER(2.,56.)
,失败为POWER(2.,57.)
。这里发生了什么?
真正可怕的是select 2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.;
实际上返回了正确的值。简洁到此为止。
我有一个包含 4 部分复合聚集主键(A、B、C、D)的表,按 A、B、C、D 排序。
我必须通过获取 N 条记录来批量遍历整个表,然后从检查的最后一个键(K1、K2、K3、K4)之后的任何值开始获取接下来的 N 条记录。键值不连续。
我正在尝试构造谓词来寻找下一批记录,给定带有复合键(K1,K2,K3,K4)的最后读取记录。
如果 ID 不是复合的,我只需运行一个 select 语句,例如“从表中选择前 N 个,其中 ID > K1”。然而,因为它是一个由 4 部分组成的复合键,所以我必须构造一个特殊的谓词来处理 D 可以小于 K4 的事实,只要 A、B 和 C 中的任何一个或全部大于 K1、K2和K3。
在某些数据库引擎中,我知道可以使用如下设置语法进行此类复合键比较:
where (A,B,C,D) > (K1,K2,K3,K4)
问题1: SQL Server支持上述集合比较语法吗?
如果没有,那么我怀疑我必须像这样构造谓词:
一把钥匙 | 两把钥匙 | 三把钥匙 | 四把钥匙 |
---|---|---|---|
其中 (A > K1) 按 A 排序 |
其中 (A = K1 且 B > K2) OR (A > K1) 按 A、B 排序 |
其中 (A = K1 且 B = K2 且 C > … |
有人说最好制作您的查询以避免重复的键异常,但我不相信仅设置IGNORE_DUP_KEY = ON
索引的性能更高。
我的目标是在尝试更新这些行之前,确保为一个或多个用户存在一行或一组行。我这样做,所以当我尝试使用如下所示的更新语句更新行时,没有行受到影响,这是因为[Count]
谓词的部分不满足,而不是根本不存在的行(即[ID]
不满足谓词的部分):
UPDATE [Inventory]
SET [Count] = [Count] + 1
WHERE [ID] = 3
AND ([Count] + 1) <= @MaxInventory
Run Code Online (Sandbox Code Playgroud)
我可以运行EXISTS(SELECT 1 From [Inventory] WHERE [ID] = 3
检查该单行,如果该行不存在,则仅插入该行。这只是避免了不必要的插入。如有必要,插入仍需处理并发事务,因此仍可能发生重复键异常。
我很好奇IGNORE_DUP_KEY
在这种情况下是否只打开性能更好,而不是允许抛出和捕获错误。具体来说,我很好奇它是否与运行存在检查一样快或什至可能更快,只是尝试插入记录并让它忽略重复的键。
当我一次检查和初始化多个记录时,这变得更加重要。例如,如果我需要确保单个更新语句中存在数千个用户的记录,如果我只是预先运行该插入语句,让它忽略重复的键,那么逻辑会简单得多。避免重复会更复杂,因为我必须首先查询不存在记录的表,然后尝试仅添加这些记录(再次忽略重复键)。即使所有记录都存在,只是插入可能会更快。
我可以在中途遇到它并检查是否有任何记录丢失,例如使用左连接或COUNT
比较,但是如果忽略重复键的插入速度更快,为什么还要麻烦呢?
使用IGNORE_DUP_KEY
并尝试插入而不是提前检查行是否存在是个好主意吗?如果不是,为什么?
存在一个“批量查询”表,它有两列(BatchID、RecordID),它们都是 TSQL 类型的“uniqueidentifier”。唯一的聚簇键在(BatchID,RecordID)上,并且没有二级索引。
我们使用 SqlBulkCopy 将数千或数百万个 id 快速插入到单个批处理 id 下的表中,以便各种查询可以加入它以使用与该批处理关联的记录 id 集执行过滤。这种方法比尝试多个查询快得多,所有查询都在查询字符串中发送 id 列表。查询完成后,该批记录 ID 将被删除。当没有查询运行时,该表平均为空,但可能有数百个活动批次,因为我们每秒处理数千个可能使用该表的 API 请求。
我的问题是,DBA 需要什么样的维护步骤(如果有)来维护这些表。例如,它是否会从定期索引重建中受益,或者 SQL Server 是否会自行处理已删除行的清理(释放页块等)。此外,表或聚集索引是否有任何特殊配置会有所帮助,特别是考虑到标识符是随机 Guids(唯一标识符)。
一般我们使用最新版本的SQL Server,企业版。有些服务器在 Azure 中,有些在 AWS 中。
我也有兴趣听取替代方案。例如,我认为这种方法最适合永久表,但我也可以创建一个会话本地临时表作为事务的一部分,该表在完成时被删除,而不是从永久表中插入和删除行。我只是不知道相比之下会如何表现。
performance sql-server delete index-maintenance bulk-insert performance-tuning
我想为 M 个用户自动保留 N 个对象的库存。
我有两张库存跟踪表,一张用于全球库存,一张用于个人库存。
有两个表,因为我必须为每个对象以及每个用户强制执行最大允许保留。例如,一个对象可能被限制为总共保留 1000 个,每个用户最多保留 10 个该对象。
全局清单表以 [ObjectID] 为唯一键,个人清单表以 [UserID, ObjectID] 为唯一键。
为 3 个对象保留库存的示例请求如下所示。一些对象有限制,而另一些则没有。
[
{ObjectID: 'A', QuantityToReserve: 1},
{ObjectID: 'C', QuantityToReserve: 2, GlobalMax: 1000, PersonalMax: 10},
{ObjectID: 'B', QuantityToReserve: 5}
]
Run Code Online (Sandbox Code Playgroud)
原子预留是通过启动一个事务,然后首先更新全局清单表中的行来实现的,对于所有对象 ID,按升序排列。
没有限制的对象的更新语句如下所示:
UPDATE [GlobalInventory] WITH (ROWLOCK, XLOCK, HOLDLOCK)
SET [Count] = [Count] + @QuantityToReserve
WHERE [ObjectID] = @ObjectID
Run Code Online (Sandbox Code Playgroud)
具有限制的对象的更新语句如下所示:
UPDATE [GlobalInventory] WITH (ROWLOCK, XLOCK, HOLDLOCK)
SET …
Run Code Online (Sandbox Code Playgroud) sql-server ×5
bulk-insert ×1
concurrency ×1
deadlock ×1
delete ×1
duplication ×1
locking ×1
performance ×1