小编Tri*_*nko的帖子

为什么 TSQL 为 POWER(2.,64.) 返回错误的值?

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.;实际上返回了正确的值。简洁到此为止。

sql-server azure-sql-database

14
推荐指数
2
解决办法
1717
查看次数

如何构造谓词以触发具有组合键的特定记录搜索的聚集索引?

我有一个包含 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 > …

sql-server

10
推荐指数
2
解决办法
626
查看次数

什么时候应该在索引上使用 IGNORE_DUP_KEY 选项?

有人说最好制作您的查询以避免重复的键异常,但我不相信仅设置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并尝试插入而不是提前检查行是否存在是个好主意吗?如果不是,为什么?

sql-server duplication unique-constraint sql-server-2019

7
推荐指数
2
解决办法
1308
查看次数

配置和维护具有许多插入和删除的表的最佳方法,平均而言是空的?

存在一个“批量查询”表,它有两列(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

5
推荐指数
1
解决办法
117
查看次数

在以下库存系统中,是否可以强制行锁以避免死锁并确保其按预期工作?

我想为 M 个用户自动保留 N 个对象的库存。

我有两张库存跟踪表,一张用于全球库存,一张用于个人库存。

  • 全局清单表列:ObjectID uniqueidentifier、Count int
  • 个人库存表列:UserID nvarchar(64)、ObjectID uniqueidentifier、Count int

有两个表,因为我必须为每个对象以及每个用户强制执行最大允许保留。例如,一个对象可能被限制为总共保留 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 deadlock concurrency locking sql-server-2019

-4
推荐指数
2
解决办法
285
查看次数