I join di SQL sono coerenti in un set di risultati

c# queue sql sqlbulkcopy sql-server

Domanda

Mi sento un po 'un idiota, perché non sono sicuro di cosa debba usare la terminologia qui. Quindi fammi provare e dipingere la migliore immagine che posso. Se sto unendo due tavoli insieme a un join

select t1.prop, t2.prop from t1 join t2 on t1.prop = t2.prop

t1.prop non è univoco e assumiamo che ce ne siano 2, t2.prop è univoco, esiste una possibilità remota che il mid query computing t2.prop sia popolato in uno, ma non nell'altro? Nella mia testa non riesco a immaginarlo, immagino che troverà tutti i risultati per t2.prop quindi li applicherà ai risultati.

Quindi se la risposta è no, allora forse qualcuno può indicare una possibile cosa che mi manca qui, sto cercando di sistemare un tavolo in coda e, fortunatamente, sto vedendo una specie di condizione di gara. L'ho ristretto all'affermazione precedente, che non credo, o forse la query salta gli elementi in base ai suggerimenti di blocco, o magari alle letture sporche (il livello di isolamento viene letto in commit), o sono confuso.

Ecco il flusso di lavoro di base.

  1. In qualsiasi momento una porzione di elementi viene inserita nella coda utilizzando la copia bulk (SQLBulkCopy .net), ed è all'interno di una transazione e viene impegnata con un timestamp (solo un thread sta compilando anche questa coda, quindi davvero in qualsiasi momento, 1 thread potrebbe farlo).

  2. Solo un consumatore sta attivamente scandagliando la coda con una query che sembra essenzialmente così

    SELECT Q.* from Queue Q with(rowlock, updlock, nowait) 
    join table t on Q.Prop = t.Prop
    order by Q.Timestamp;
    

Sono sotto il presupposto che questo mi restituirebbe gli oggetti più vecchi impegnati nella coda ordinata per data / ora dove essi (a un certo punto, avevo letto qui, ma temevo che potesse restituirmi cose fuori ordine, anch'io casualmente provò il tablock e bloccò la tabella sull'inserto, ma ciò non fece differenza).

Quindi, il mio problema è che continuo a ricevere gli articoli elaborati per un singolo t.Prop .

Ho aggiunto trigger che mostrano elementi che Timestamp è precedente all'ora di altri elementi, ma vengono letti dalla coda nell'ordine sbagliato. Qualche suggerimento o aiuto?

Aggiornare

Ho dimostrato di essere in grado di ottenere un set di risultati parziale in cui mi sarei aspettato tutto o niente

    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);
            }
        });
    }

Sono stato in grado di ottenere tutto o niente usando l' inner hash join , ma su un'altra nota potrei provare a utilizzare il livello di isolamento dello snapshot.

Risposta popolare

O si utilizzano letture sporche ( read uncommitted ) nel lettore o la copia di massa non utilizza le transazioni. Per controllare entrambi è abbastanza facile:

SELECT Q.* from Queue Q with(rowlock, updlock, nowait, readcommitted) 
  left join table t on Q.Prop = t.Prop
order by Q.Timestamp;

(anche se personalmente non farei affidamento sul suggerimento nowait e aggiungo un esplicito where ).

Quest'ultimo può essere facilmente rintracciato da SQL Profiler. Non è necessario includere tutti i bulks nella traccia: è sufficiente aggiungere eventi relativi alle transazioni.

PS Anche se il modo migliore per implementare una coda è usarne uno. Coda Service Broker, ad esempio.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché