stringtranslate.com

Combinación de ordenamiento y fusión

La unión de ordenación y fusión (también conocida como unión de fusión) es un algoritmo de unión y se utiliza en la implementación de un sistema de gestión de bases de datos relacionales .

El problema básico de un algoritmo de unión es encontrar, para cada valor distinto del atributo de unión, el conjunto de tuplas en cada relación que muestran ese valor. La idea clave del algoritmo de ordenación y fusión es ordenar primero las relaciones por el atributo de unión, de modo que los escaneos lineales intercalados encuentren estos conjuntos al mismo tiempo.

En la práctica, la parte más costosa de realizar una combinación de ordenación y fusión es organizar que ambas entradas del algoritmo se presenten en orden ordenado. Esto se puede lograr mediante una operación de ordenación explícita (a menudo una operación de ordenación externa ) o aprovechando un ordenamiento preexistente en una o ambas relaciones de combinación. [1] La última condición, llamada orden interesante, puede ocurrir porque una entrada a la combinación puede ser producida por un escaneo de índice de un índice basado en árbol, otra combinación de fusión o algún otro operador de plan que produzca una salida ordenada según una clave apropiada. Los órdenes interesantes no tienen por qué ser fortuitos: el optimizador puede buscar esta posibilidad y elegir un plan que no sea óptimo para una operación precedente específica si produce un orden interesante que uno o más nodos posteriores puedan explotar.

Complejidad

Sean y relaciones donde . cabe en la memoria de páginas y cabe en la memoria de páginas. En el peor de los casos, se ejecutará una combinación de ordenación y fusión en las operaciones de E/S. En el caso de que y no estén ordenados, el costo de tiempo en el peor de los casos contendrá términos adicionales de tiempo de ordenación: , que es igual a (ya que los términos lineales superan a los términos lineales, consulte la notación Big O – Órdenes de funciones comunes ).

Pseudocódigo

Para simplificar, el algoritmo se describe en el caso de una unión interna de dos relaciones izquierda y derecha . La generalización a otros tipos de unión es sencilla. La salida del algoritmo contendrá solo las filas contenidas en la relación izquierda y derecha y los duplicados forman un producto cartesiano .

función Ordenar - Combinar unir ( izquierda : Relación , derecha : Relación , comparador : Comparador ) { resultado = nueva Relación () // Asegurarse de que al menos un elemento esté presente if ( ! izquierda . hasNext () || ! derecha . hasNext ()) { devolver resultado } // Ordenar la relación izquierda y derecha con el comparador izquierda . sort ( comparador ) derecha . sort ( comparador ) // Iniciar el algoritmo de combinación de fusión leftRow = izquierda . next () rightRow = derecha . next () outerForeverLoop : while ( true ) { while ( comparador . compare ( izquierda , fila derecha ) != 0 ) { if ( comparador . compare ( izquierda , fila derecha ) < 0 ) { // La fila izquierda es menor que la fila derecha if ( izquierda . hasNext ()) { // Avanzar a la siguiente fila izquierda leftRow = izquierda . next () } else { break outerForeverLoop } } else { // La fila izquierda es mayor que la fila derecha if ( right . hasNext ()) { // Avanzar a la siguiente fila derecha rightRow = right . next () } else { break outerForeverLoop } } } // Marcar la posición de la fila izquierda y mantener una copia de la fila izquierda actual left . mark () markedLeftRow = leftRow while ( true ) { while (                                                                                                comparador . compare ( leftRow , rightRow ) == 0 ) { // La fila izquierda y la fila derecha son iguales // Agregar filas al resultado result = add ( leftRow , rightRow ) // Avanzar a la siguiente fila izquierda leftRow = left . next () // Verificar si existe la fila izquierda if ( ! leftRow ) { // Continuar con el bucle infinito interno break } } if ( right . hasNext ()) { // Avanzar a la siguiente fila derecha rightRow = right . next () } else { break outerForeverLoop } if ( comparator . compare ( markedLeftRow , rightRow ) == 0 ) { // Restaurar la izquierda a la marca almacenada left . restoreMark () leftRow = markedLeftRow } else { // Verificar si existe la fila izquierda if ( ! leftRow ) { break outerForeverLoop } else { // Continuar con el bucle infinito externo break } } } } return result }                                                                       

Dado que la lógica de comparación no es el aspecto central de este algoritmo, se oculta detrás de un comparador genérico y también puede constar de varios criterios de comparación (por ejemplo, varias columnas). La función de comparación debe devolver si una fila es menor (-1) , igual (0) o mayor (1) que otra fila:

función comparar ( leftRow : RelationRow , rightRow : RelationRow ) : número { // Devuelve -1 si leftRow es menor que rightRow // Devuelve 0 si leftRow es igual a rightRow // Devuelve 1 si leftRow es mayor que rightRow }      

Tenga en cuenta que una relación en términos de este pseudocódigo admite algunas operaciones básicas:

interfaz Relation { // Devuelve verdadero si la relación tiene una siguiente fila (de lo contrario, falso) hasNext () : boolean // Devuelve la siguiente fila de la relación (si hay alguna) next () : RelationRow // Ordena la relación con el comparador dado sort ( comparator : Comparator ) : void // Marca el índice de la fila actual mark () : void // Restaura el índice de la fila actual al índice de la fila marcada restoreMark () : void }                      

Implementación sencilla en C#

Tenga en cuenta que esta implementación supone que los atributos de unión son únicos, es decir, no hay necesidad de generar múltiples tuplas para un valor dado de la clave.

public class MergeJoin { // Supongamos que izquierda y derecha ya están ordenadas 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 posición = 0 ; public int Posición => posición ;          público int Clave => lista [ posición ];     público bool IsPastEnd => posición == ENDPOS ;       público bool Advance () { if ( posición == lista . Count - 1 || posición == ENDPOS ) { posición = ENDPOS ; devuelve falso ; } posición ++ ; devuelve verdadero ; }                         public void Add ( int clave ) { lista.Add ( clave ) ; }       public void Print ( ) { foreach ( int clave en lista ) Console.WriteLine ( clave ) ; }           Relación pública ( Lista < int > lista ) { this.list = lista ; }        Relación pública () { esta . lista = nueva Lista < int > (); } }       

Véase también

Referencias

  1. ^ "Uniones de ordenación y fusión". www.dcs.ed.ac.uk . Consultado el 2 de noviembre de 2022 .

Enlaces externos

Implementaciones en C# de varios algoritmos de unión