简体   繁体   English

在写入SQL Server 2014中的基础表后立即查询视图

[英]Querying a view immediately after writing to underlying tables in SQL Server 2014

I am having an issue where if I write to a table ( using Linq-to-SQL ) which is a dependency of a view, and then immediately turn around and query that view to check the impact of the write (using a new connection to the DB, and hence a new data context), the impact of the write doesn't show up immediately but takes up to a few seconds to appear. 我有一个问题,如果我写一个表( 使用Linq-to-SQL )这是一个视图的依赖项,然后立即转身查询该视图以检查写入的影响(使用新连接到数据库,因此新的数据上下文),写入的影响不会立即显示,但需要几秒钟才能显示。 This only happens occasionally (perhaps 10-20 times per 10,000 or so writes). 这种情况偶尔会发生( 10-2010,000次写入10-20次)。

This is the definition of the view: 这是视图的定义:

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
)

while this is the query generated by Linq-to-SQL to write to one of the underlying tables: 而这是由Linq-to-SQL生成的用于写入其中一个基础表的查询:

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)

and this is the query generated by Linq-to-SQL to check the effect of the write: 这是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]

Also, this is the Linq-to-SQL code that generates the write (using F# type providers): 此外,这是生成写入的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()

while this is the corresponding Linq-to-SQL that generates the read: 而这是生成读取的相应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

I would have thought System.Data.Linq.DataContext.SubmitChanges() would only return once the write transaction was complete, and that any subsequent query of the view must contain the effect of the write... what am I missing/doing wrong? 我原以为System.Data.Linq.DataContext.SubmitChanges()只会在写事务完成后返回,并且视图的任何后续查询都必须包含写入的效果...我错过了什么/做错了什么?

I finally got to the bottom of this: the DB writes are done in their own threads, with the main thread waiting for all the write threads to complete before checking the results. 我终于明白了这一点:数据库写入是在自己的线程中完成的,主线程在检查结果之前等待所有写线程完成。 However, there was a bug in the code which checked whether all the threads were complete, causing the main thread to do the check too early. 但是,代码中存在一个错误,它检查所有线程是否都已完成,导致主线程过早地进行检查。

Is it possible that your Link to SQL to check the effect of the write is looking at old cached data? 你的链接SQL是否有可能检查写入的效果是否正在查看旧的缓存数据? Try refreshing the cache beforehand with the refresh method of the context object. 尝试使用上下文对象的refresh方法预先刷新缓存。 Use RefreshMode.OverwriteCurrentValues on the object. 在对象上使用RefreshMode.OverwriteCurrentValues

Could you try with table hints ie 你可以试试表提示

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 check this blog entry, in my case use the nolock hint solve the issue. Alos检查这个博客条目,在我的情况下使用nolock提示解决问题。

You have create a view with schema binding 您已创建具有架构绑定的视图

CREATE VIEW [Position].[Transactions]
WITH SCHEMABINDING

and has 8 union operation with 9 query from 4 tables 并且有4个联合操作,4个表有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

to refresh the view after each insert into one of these tables that system might required few seconds and your select query run immediately after insertion. 在每次插入其中一个表之后刷新视图,系统可能需要几秒钟,并且您的选择查询在插入后立即运行。 it might be happened that insert perform within 0~1 ms into table but refresh view take more then 100 ms and select query miss due to view is served from the cache of the server 可能会发生插入在0~1 ms内执行到表中但刷新视图需要超过100 ms并且由于视图从服务器的缓存中提供选择查询未命中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM