我觉得自己有点像个白痴,因为我不知道这里该用什么术语。所以让我试着画出我能画的最好的画面。如果我把两个表和一个连接在一起
select t1.prop, t2.prop from t1 join t2 on t1.prop = t2.prop
t1.prop并不是唯一的,假设其中有两个,t2.prop是唯一的,有没有可能中间查询计算t2.prop被填充在其中一个,而不是另一个呢?在我的头脑中,我无法想象,我假设它会找到t2.prop的所有结果,然后将它应用到结果中。
所以如果答案是否定的,那么也许有人可以指出我在这里遗漏的一个可能的东西,我正在试图修复一个队列表,幸运的是我看到了某种种族状况。我把范围缩小到上面的语句(我不相信这一点),或者查询是基于锁定提示跳过项,或者是脏读(已提交隔离级别),或者我很困惑。
这是基本的工作流程。
我的假设是,这将返回队列中按时间戳排序的最古老的已提交项(其中有一次,我在这里重新读过了,但我担心这可能会使我出现问题,我还随机地尝试了tablock,并将表锁定在insert上,但这并没有什么区别)。
因此,我的问题是,我一直让单个t.Prop的项目被按顺序处理。
我增加了触发器,显示项目时间戳在其他项目时间戳之前,但是它们被按错误的顺序读取掉队列。有什么提示或帮助吗?
更新
我证明了我能够得到一个局部的结果集,在这里我可以期望所有或什么都没有。
private static void OutOfOrder()
{
    var cnt = 100;
    var go = true;
    using (var db = new DBManager())
    {
        using (var cmd = db.GetCommand())
        {
            cmd.CommandText = "Delete from Foo";
            cmd.ExecuteNonQuery();
            cmd.CommandText = "Delete from Bar";
            cmd.ExecuteNonQuery();
            cmd.CommandText = "Insert Into Foo (B) Values ('joint')";
            for (var i = 0; i < cnt; i++)
            {
                cmd.ExecuteNonQuery();
            }
        }
    }
    var task1 = Task.Run(() =>
    {
        var inserted = false;
        while (go)
        {
            using (var db = new DBManager())
            {
                using (var cmd = db.GetCommand())
                {
                    var text = inserted ? "Delete from Bar" : "Insert Into Bar (B, C) Values ('joint', 'blah')";
                    cmd.CommandText = text;
                    Console.WriteLine(DateTime.Now.ToLongTimeString() + "  -  " + text);
                    cmd.ExecuteNonQuery();
                    inserted = !inserted;
                }
            }
            Thread.Sleep(20);
        }
    });
    var task2 = Task.Run(() =>
    {
        var text = "Select * from Foo join Bar on Foo.B = Bar.B";
        while (go)
        {
            using (var db = new DBManager())
            {
                using (var cmd = db.GetCommand())
                {
                    cmd.CommandText = text;
                    Console.WriteLine(DateTime.Now.ToLongTimeString() + "  -  " + text);
                    var ret = cmd.ExecuteDataTable();
                    var retCount = ret.Rows.Count;
                    var valid = retCount == 0 || retCount == 100;
                    if (!valid)
                    {
                        Console.WriteLine("Error, got {0} rows back!!!", ret.Rows.Count);
                        go = false;
                    }
                }
            }
            Thread.Sleep(17);
        }
    });
}我可以使用inner hash join将其变为全部或全部为零,但在另一个注意事项上,我可能尝试使用快照隔离级别。
发布于 2014-12-01 10:30:53
要么在读取器中使用脏读(read uncommitted),要么批量复制不使用事务。检查两者都很容易:
SELECT Q.* from Queue Q with(rowlock, updlock, nowait, readcommitted) 
  left join table t on Q.Prop = t.Prop
order by Q.Timestamp;(尽管就我个人而言,我不会依赖nowait提示并添加了一个显式的where)。
可以很容易地跟踪后者。您不必在跟踪中包含所有块-只需添加与事务相关的事件即可。
尽管实现队列的最佳方法是使用队列。例如,Service队列。
https://stackoverflow.com/questions/27222206
复制相似问题