在 SQL Server 2014 中写入基础表后立即查询视图
Querying a view immediately after writing to underlying tables in SQL Server 2014
我遇到一个问题,如果我写入 table(using Linq-to-SQL),它是视图的依赖项,然后立即转身并查询该视图以检查写入的影响(使用与数据库的新连接,因此使用新的数据上下文),写入的影响不会立即显示出来,但会占用几秒钟出现。这只是偶尔发生(可能每 10,000
次左右写入 10-20
次)。
这是视图的定义:
CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING
AS
(
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(QuantityBase, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-QuantityBase * Rate, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(QuantityBase, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(1 AS tinyint), 1) AS TransactionType
FROM Trades.FxSpotManual
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-QuantityBase * Rate, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(1 AS tinyint), 1) AS TransactionType
FROM Trades.FxSpotManual
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(SpotQuantityBase, 0) AS Quantity,
SpotValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-SpotQuantityBase * SpotRate, 0) AS Quantity,
SpotValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(ForwardQuantityBase, 0) AS Quantity,
ForwardValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-ForwardQuantityBase * ForwardRate, 0) AS Quantity,
ForwardValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
c.Book,
TimeUtc AS DateTimeUtc,
Currency,
ISNULL(Amount, 0) AS Quantity,
SettleDate,
ISNULL(CAST(3 AS tinyint), 3) AS TransactionType
FROM Trades.Commission c
JOIN Trades.Payment p
ON c.UniquePaymentId = p.UniquePaymentId
AND c.Book = p.Book
)
虽然这是 Linq-to-SQL 生成的查询,用于写入底层 tables 之一:
INSERT INTO [Trades].[FxSpotMF] ([UniqueTradeId], [BaseCcy], [QuoteCcy], [ValueDate], [Rate], [QuantityBase], [Account], [Book], [CounterpartyId], [Counterparty], [ExTradeId], [TimeAPIClient], [TimeAPIServer], [TimeExchange], [TimeHandler], [UniqueOrderId], [IsCancelled], [ClientId], [SequenceId], [ExOrdId], [TradeDate], [OrderCycleId], [CycleIndex])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22)
这是 Linq-to-SQL 生成的用于检查写入效果的查询:
SELECT
SUM([t0].[Quantity]) AS [Item2],
[t0].[Currency] AS [Item1]
FROM [Position].[Transactions] AS [t0]
WHERE ([t0].[Book] = @p0)
AND ([t0].[DateTimeUtc] < @p1)
GROUP BY [t0].[Currency]
此外,这是生成写入的 Linq-to-SQL 代码(使用 F# 类型提供程序):
type Schema = Microsoft.FSharp.Data.TypeProviders.DbmlFile<"TradeDb.dbml", ContextTypeName="TradeDb">
use db = new Schema.TradeDb(connectionString)
let trade = new Schema.Trades_FxSpotMF()
(* omitted: set object properties corresponding to column values here... *)
db.Trades_FxSpotMF.InsertOnSubmit(trade)
db.SubmitChanges()
虽然这是生成读取的相应 Linq-to-SQL:
use db = new Schema.TradeDb(connectionString)
query { for t in db.Position_Transactions do
where ( t.Book = book &&
t.DateTimeUtc < df.MaxExecutionTimeExcl
)
groupBy t.Currency into group
let total = query { for x in group do sumBy x.Quantity }
select (group.Key, total)
}
|> Map.ofSeq
我原以为 System.Data.Linq.DataContext.SubmitChanges()
只会 return 一旦写入事务完成,并且视图的任何后续查询都必须包含写入的效果...我是什么 missing/doing错了?
您已经创建了具有模式绑定的视图
CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING
并且有 8 个联合操作和来自 4 tables
的 9 个查询
FROM Trades.FxSpotMF --2times
WHERE IsCancelled = 0
FROM Trades.FxSpotManual --2 times
WHERE IsCancelled = 0
FROM Trades.FxSwap -- 4 times
FROM Trades.Commission c
JOIN Trades.Payment p
ON c.UniquePaymentId = p.UniquePaymentId
AND c.Book = p.Book
在每次插入这些 table 之一后刷新视图,系统可能需要几秒钟,并且您的 select 查询 运行 在插入后立即。
可能发生插入在 0~1 毫秒内执行到 table 但刷新视图需要超过 100 毫秒并且 select 由于视图是从服务器缓存提供的查询未命中
您的 Link 到 SQL 是否有可能检查写入效果是在查看旧的缓存数据?尝试使用上下文对象的 refresh method 预先刷新缓存。在对象上使用 RefreshMode.OverwriteCurrentValues
。
你可以试试 table hints 即
CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING
AS
(
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(QuantityBase, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF WITH(NOLOCK)
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-QuantityBase * Rate, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF WITH(NOLOCK)
WHERE IsCancelled = 0
...
)
Alos 检查 this 博客条目,在我的情况下使用 nolock 提示解决问题。
我终于弄明白了:数据库写入是在它们自己的线程中完成的,主线程在检查结果之前等待所有写入线程完成。但是在检查所有线程是否完成的代码中有一个错误,导致主线程过早地进行检查。
我遇到一个问题,如果我写入 table(using Linq-to-SQL),它是视图的依赖项,然后立即转身并查询该视图以检查写入的影响(使用与数据库的新连接,因此使用新的数据上下文),写入的影响不会立即显示出来,但会占用几秒钟出现。这只是偶尔发生(可能每 10,000
次左右写入 10-20
次)。
这是视图的定义:
CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING
AS
(
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(QuantityBase, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-QuantityBase * Rate, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(QuantityBase, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(1 AS tinyint), 1) AS TransactionType
FROM Trades.FxSpotManual
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-QuantityBase * Rate, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(1 AS tinyint), 1) AS TransactionType
FROM Trades.FxSpotManual
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(SpotQuantityBase, 0) AS Quantity,
SpotValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-SpotQuantityBase * SpotRate, 0) AS Quantity,
SpotValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(ForwardQuantityBase, 0) AS Quantity,
ForwardValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
Book,
ExecutionTimeUtc AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-ForwardQuantityBase * ForwardRate, 0) AS Quantity,
ForwardValueDate AS SettleDate,
ISNULL(CAST(2 AS tinyint), 2) AS TransactionType
FROM Trades.FxSwap
UNION ALL
SELECT
Account,
c.Book,
TimeUtc AS DateTimeUtc,
Currency,
ISNULL(Amount, 0) AS Quantity,
SettleDate,
ISNULL(CAST(3 AS tinyint), 3) AS TransactionType
FROM Trades.Commission c
JOIN Trades.Payment p
ON c.UniquePaymentId = p.UniquePaymentId
AND c.Book = p.Book
)
虽然这是 Linq-to-SQL 生成的查询,用于写入底层 tables 之一:
INSERT INTO [Trades].[FxSpotMF] ([UniqueTradeId], [BaseCcy], [QuoteCcy], [ValueDate], [Rate], [QuantityBase], [Account], [Book], [CounterpartyId], [Counterparty], [ExTradeId], [TimeAPIClient], [TimeAPIServer], [TimeExchange], [TimeHandler], [UniqueOrderId], [IsCancelled], [ClientId], [SequenceId], [ExOrdId], [TradeDate], [OrderCycleId], [CycleIndex])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22)
这是 Linq-to-SQL 生成的用于检查写入效果的查询:
SELECT
SUM([t0].[Quantity]) AS [Item2],
[t0].[Currency] AS [Item1]
FROM [Position].[Transactions] AS [t0]
WHERE ([t0].[Book] = @p0)
AND ([t0].[DateTimeUtc] < @p1)
GROUP BY [t0].[Currency]
此外,这是生成写入的 Linq-to-SQL 代码(使用 F# 类型提供程序):
type Schema = Microsoft.FSharp.Data.TypeProviders.DbmlFile<"TradeDb.dbml", ContextTypeName="TradeDb">
use db = new Schema.TradeDb(connectionString)
let trade = new Schema.Trades_FxSpotMF()
(* omitted: set object properties corresponding to column values here... *)
db.Trades_FxSpotMF.InsertOnSubmit(trade)
db.SubmitChanges()
虽然这是生成读取的相应 Linq-to-SQL:
use db = new Schema.TradeDb(connectionString)
query { for t in db.Position_Transactions do
where ( t.Book = book &&
t.DateTimeUtc < df.MaxExecutionTimeExcl
)
groupBy t.Currency into group
let total = query { for x in group do sumBy x.Quantity }
select (group.Key, total)
}
|> Map.ofSeq
我原以为 System.Data.Linq.DataContext.SubmitChanges()
只会 return 一旦写入事务完成,并且视图的任何后续查询都必须包含写入的效果...我是什么 missing/doing错了?
您已经创建了具有模式绑定的视图
CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING
并且有 8 个联合操作和来自 4 tables
的 9 个查询FROM Trades.FxSpotMF --2times
WHERE IsCancelled = 0
FROM Trades.FxSpotManual --2 times
WHERE IsCancelled = 0
FROM Trades.FxSwap -- 4 times
FROM Trades.Commission c
JOIN Trades.Payment p
ON c.UniquePaymentId = p.UniquePaymentId
AND c.Book = p.Book
在每次插入这些 table 之一后刷新视图,系统可能需要几秒钟,并且您的 select 查询 运行 在插入后立即。 可能发生插入在 0~1 毫秒内执行到 table 但刷新视图需要超过 100 毫秒并且 select 由于视图是从服务器缓存提供的查询未命中
您的 Link 到 SQL 是否有可能检查写入效果是在查看旧的缓存数据?尝试使用上下文对象的 refresh method 预先刷新缓存。在对象上使用 RefreshMode.OverwriteCurrentValues
。
你可以试试 table hints 即
CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING
AS
(
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
BaseCcy AS Currency,
ISNULL(QuantityBase, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF WITH(NOLOCK)
WHERE IsCancelled = 0
UNION ALL
SELECT
Account,
Book,
TimeAPIClient AS DateTimeUtc,
QuoteCcy AS Currency,
ISNULL(-QuantityBase * Rate, 0) AS Quantity,
ValueDate AS SettleDate,
ISNULL(CAST(0 AS tinyint), 0) AS TransactionType
FROM Trades.FxSpotMF WITH(NOLOCK)
WHERE IsCancelled = 0
...
)
Alos 检查 this 博客条目,在我的情况下使用 nolock 提示解决问题。
我终于弄明白了:数据库写入是在它们自己的线程中完成的,主线程在检查结果之前等待所有写入线程完成。但是在检查所有线程是否完成的代码中有一个错误,导致主线程过早地进行检查。