SQL 处理长整数类型时 SDK 和存储过程之间的不一致
Inconsistency between SQL SDK and Stored Procedure when handling long integer types
我们的团队使用 Cosmos DB 作为我们的后端图形存储。基本上我们使用 JAVA Gremlin SDK 对 vertices/edges 进行查询,并使用 SQL SDK 对 create/update 个顶点进行查询,由于 Gremlin [=89= 的大小和步长限制].
我在尝试更新包含 Long 类型属性的顶点时遇到了这个问题。
在我们的代码中,我们使用 CosmosDbElement
和另一个标志作为输入参数,调用 sqlClient.executeStoredProcedure(“sp_name”, pk, new Object[] { document, flag });
我使用的存储过程只是做了一些验证,然后调用 collection.replaceDocument()
来替换文档。
当我为此属性设置不同的值时,我得到了不同的行为:
[-2^53 + 1, 2 ^53 - 1]内的属性值(JavaScript中的MIN_SAFE_INTEGER至MAX_SAFE_INTEGER)
- 替换为SQLSDK然后通过ID获取:效果很好
- 替换为SP然后通过ID获取:效果很好
属性值超出范围但在Int64范围内
- 替换为SQLSDK然后通过ID获取:效果很好
- 替换为SP然后通过ID获取:最后3位四舍五入。例如。
9223372036854775107 -> 9223372036854775000;
9223372036854775807 -> 9223372036854776000.
我们可以使用 SQL SDK 获得相同的舍入值。
对于大多数情况,g.V([id])
获得相同的舍入值。
但是如果四舍五入后的值在Int64
范围之外,比如9223372036854775807 -> 9223372036854776000, g.V([id])
抛出异常:Cannot create ValueField on non-primitive type BigInteger
.
- 属性超出 Int64 范围
- 替换为SQLSDK然后通过ID获取:效果很好
- 替换为SP然后通过ID获取:效果很好
我使用 SP 的方式正确吗?
这是设计限制还是问题?
如何避免这种精度丢失并能够查询顶点?
如果您需要更多信息,请告诉我,谢谢。
The Stored Procedures are written in JavaScript.
As you know, JavaScript uses double-precision floating-point format numbers as specified in IEEE 754, and it can only safely hold numbers between -(2^53 - 1)
and 2^53-1
(i.e., 9007199254740991
).
So if you use a sproc to replace the value outside of the safe MIN_SAFE_INTEGER
to MAX_SAFE_INTEGER
in JavaScript, it will get rounded. This is a by-design limitation.
推荐的解决方法是:
- If you are ok with the precision-loss, then converting the
Int64
values into doubles is recommended so that your application handles the conversion/rounding.
- If you need to maintain the precision then use strings, with the downside being that arithmetic ops cannot be applied server-side.
我们的团队使用 Cosmos DB 作为我们的后端图形存储。基本上我们使用 JAVA Gremlin SDK 对 vertices/edges 进行查询,并使用 SQL SDK 对 create/update 个顶点进行查询,由于 Gremlin [=89= 的大小和步长限制].
我在尝试更新包含 Long 类型属性的顶点时遇到了这个问题。
在我们的代码中,我们使用 CosmosDbElement
和另一个标志作为输入参数,调用 sqlClient.executeStoredProcedure(“sp_name”, pk, new Object[] { document, flag });
我使用的存储过程只是做了一些验证,然后调用 collection.replaceDocument()
来替换文档。
当我为此属性设置不同的值时,我得到了不同的行为:
[-2^53 + 1, 2 ^53 - 1]内的属性值(JavaScript中的MIN_SAFE_INTEGER至MAX_SAFE_INTEGER)
- 替换为SQLSDK然后通过ID获取:效果很好
- 替换为SP然后通过ID获取:效果很好
属性值超出范围但在Int64范围内
- 替换为SQLSDK然后通过ID获取:效果很好
- 替换为SP然后通过ID获取:最后3位四舍五入。例如。
9223372036854775107 -> 9223372036854775000;
9223372036854775807 -> 9223372036854776000.
我们可以使用 SQL SDK 获得相同的舍入值。
对于大多数情况,g.V([id])
获得相同的舍入值。
但是如果四舍五入后的值在Int64
范围之外,比如9223372036854775807 -> 9223372036854776000, g.V([id])
抛出异常:Cannot create ValueField on non-primitive type BigInteger
.
- 属性超出 Int64 范围
- 替换为SQLSDK然后通过ID获取:效果很好
- 替换为SP然后通过ID获取:效果很好
我使用 SP 的方式正确吗?
这是设计限制还是问题?
如何避免这种精度丢失并能够查询顶点?
如果您需要更多信息,请告诉我,谢谢。
The Stored Procedures are written in JavaScript.
As you know, JavaScript uses double-precision floating-point format numbers as specified in IEEE 754, and it can only safely hold numbers between
-(2^53 - 1)
and2^53-1
(i.e.,9007199254740991
).So if you use a sproc to replace the value outside of the safe
MIN_SAFE_INTEGER
toMAX_SAFE_INTEGER
in JavaScript, it will get rounded. This is a by-design limitation.
推荐的解决方法是:
- If you are ok with the precision-loss, then converting the
Int64
values into doubles is recommended so that your application handles the conversion/rounding.- If you need to maintain the precision then use strings, with the downside being that arithmetic ops cannot be applied server-side.