Sortare-îmbinare îmbinare - Sort-merge join

Sortare-îmbinare se alăture (cunoscut și sub numele de îmbinare join) este un alătura algoritm și este utilizat în punerea în aplicare a unui relaționale sistem de management de baze de date .

Problema de bază a unui algoritm de asociere este de a găsi, pentru fiecare valoare distinctă a atributului de asociere, setul de tupluri din fiecare relație care afișează acea valoare. Ideea cheie a algoritmului de sortare-îmbinare este de a sorta mai întâi relațiile după atributul join, astfel încât scanările liniare intercalate să întâlnească aceste seturi în același timp.

În practică, cea mai scumpă parte a realizării unei îmbinări de sortare-îmbinare este aranjarea ambelor intrări în algoritm pentru a fi prezentate în ordine sortată. Acest lucru poate fi realizat printr-o operațiune de sortare explicită (de multe ori o sortare externă ) sau prin utilizarea unui ordin preexistent într-una sau ambele relații de asociere. Cea din urmă condiție, numită ordine interesantă, poate apărea deoarece o intrare la îmbinare ar putea fi produsă printr-o scanare a indexului unui index bazat pe arbore, o altă îmbinare de îmbinare sau un alt operator de plan care se întâmplă să producă ieșire sortată pe o cheie adecvată. Comenzile interesante nu trebuie să fie serioase: optimizatorul poate căuta această posibilitate și alege un plan care nu este optim pentru o anumită operație anterioară, dacă dă un ordin interesant pe care unul sau mai multe noduri din aval îl pot exploata.

Să spunem că avem două relații și și . se potrivește în memoria paginilor și se potrivește în memoria paginilor. Deci, în cel mai rău caz , unirea sort-merge va rula în I / Os. În cazul în care și nu sunt ordonate, cel mai rău cost al timpului va conține termeni suplimentari ai timpului de sortare:, care este egal (deoarece termenii liniaritmici depășesc termenii liniari, a se vedea notația O mare - Ordinele funcțiilor comune ).

Pseudo cod

Pentru simplitate, algoritmul este descris în cazul unei îmbinări interioare a două relații pe un singur atribut. Generalizarea către alte tipuri de uniri, mai multe relații și mai multe chei este simplă.

function sortMerge(relation left, relation right, attribute a)
    var relation output
    var list left_sorted := sort(left, a) // Relation left sorted on attribute a
    var list right_sorted := sort(right, a)
    var attribute left_key, right_key
    var set left_subset, right_subset // These sets discarded except where join predicate is satisfied
    advance(left_subset, left_sorted, left_key, a)
    advance(right_subset, right_sorted, right_key, a)
    while not empty(left_subset) and not empty(right_subset)
        if left_key = right_key // Join predicate satisfied
            add cartesian product of left_subset and right_subset to output
            advance(left_subset, left_sorted, left_key, a)
            advance(right_subset, right_sorted, right_key, a)
        else if left_key < right_key
            advance(left_subset, left_sorted, left_key, a)
        else // left_key > right_key
            advance(right_subset, right_sorted, right_key, a)
    return output
// Remove tuples from sorted to subset until the sorted[1].a value changes
function advance(subset out, sorted inout, key out, a in)
    key := sorted[1].a
    subset := emptySet
    while not empty(sorted) and sorted[1].a = key
        insert sorted[1] into subset
        remove sorted[1]

Implementare simplă C #

Rețineți că această implementare presupune că atributele de unire sunt unice, adică nu este necesar să se producă mai multe tupluri pentru o anumită valoare a cheii.

public class MergeJoin
{
    // Assume that left and right are already sorted
    public static Relation Merge(Relation left, Relation right)
    {
        Relation output = new Relation();
        while (!left.IsPastEnd() && !right.IsPastEnd())
        {
            if (left.Key == right.Key)
            {
                output.Add(left.Key);
                left.Advance();
                right.Advance();
            }
            else if (left.Key < right.Key)
                left.Advance();
            else // if (left.Key > right.Key)
                right.Advance();
        }
        return output;
    }
}
 
public class Relation
{
    private List<int> list;
    public const int ENDPOS = -1;

    public int position = 0;
    public int Position
    {
        get { return position; }
    }

    public int Key
    {
        get { return list[position]; }
    }

    public bool Advance()
    {
        if (position == list.Count - 1 || position == ENDPOS)
        {
            position = ENDPOS;
            return false;
        }
        position++;
        return true;
    }

    public void Add(int key)
    {
        list.Add(key);
    }

    public bool IsPastEnd()
    {
        return position == ENDPOS;
    }

    public void Print()
    {
        foreach (int key in list)
            Console.WriteLine(key);
    }

    public Relation(List<int> list)
    {
        this.list = list;
    }

    public Relation()
    {
        this.list = new List<int>();
    }
}

Vezi si

linkuri externe

Implementări C # ale diferitelor algoritmi de unire