Сортировка-слияние - Sort-merge join
Эта статья не цитировать любой источники.Декабрь 2009 г.) (Узнайте, как и когда удалить этот шаблон сообщения) ( |
В сортировка-слияние (также известное как объединение слиянием) алгоритм присоединения и используется в реализации реляционный система управления базами данных.
Основная проблема алгоритма соединения состоит в том, чтобы найти для каждого отдельного значения атрибута соединения набор кортежи в каждом отношении, которое отображает это значение. Ключевая идея алгоритма сортировки-слияния состоит в том, чтобы сначала отсортировать отношения по атрибуту соединения, чтобы при чередующемся линейном сканировании эти наборы одновременно встречались.
На практике самая дорогостоящая часть выполнения соединения сортировка-слияние - это организация представления обоих входных данных в алгоритм в отсортированном порядке. Этого можно добиться с помощью явной операции сортировки (часто внешний вид ), или воспользовавшись ранее существовавшим порядком в одном или обоих отношениях соединения. Последнее условие, называемое интересным порядком, может возникнуть из-за того, что вход в соединение может быть произведен сканированием индекса древовидного индекса, другого объединения слиянием или какого-либо другого оператора плана, который производит вывод, отсортированный по соответствующему ключу. Интересные заказы не обязательно должны быть случайными: оптимизатор может найти эту возможность и выбрать план, который является неоптимальным для конкретной предыдущей операции, если он дает интересный порядок, который может использовать один или несколько нижестоящих узлов.
Допустим, у нас есть два отношения и и . вписывается в память страниц и вписывается в страницы памяти. Итак, в худшем случае сортировка-слияние будет работать в Ввод / вывод. В случае, если и не заказываются; в худшем случае временные затраты будут содержать дополнительные сроки сортировки: , что равно (в качестве линейный условия перевешивают линейные члены, см. Обозначение Big O - Порядки общих функций ).
Псевдокод
Для простоты алгоритм описан в случае внутреннее соединение двух отношений по одному атрибуту. Обобщение для других типов соединений, большего количества отношений и большего количества ключей просто.
функция sortMerge (связь оставили, связь верно, атрибут а) отношение var выход список переменных left_sorted: = sort (слева, a) // Отношение отсортировано слева по атрибуту a список переменных right_sorted: = sort (справа, a) атрибут var left_key, right_key набор переменных left_subset, right_subset // Эти наборы отбрасываются, кроме случаев, когда выполняется предикат соединения advance (left_subset, left_sorted, left_key, a) advance (right_subset, right_sorted, right_key, a) в то время как не пустой (left_subset) и нет пустой (right_subset) если left_key = right_key // Предикат соединения выполнен добавить декартово произведение left_subset и right_subset для вывода advance (left_subset, left_sorted, left_key, a) advance (right_subset, right_sorted, right_key, a) иначе если left_keyеще // left_key> right_key advance (right_subset, right_sorted, right_key, a) возвращаться выход
// Удаляем кортежи из sorted to subset, пока значение sorted [1] .a не изменитсяфункция продвижение (подмножество из, отсортировано inout, ключ из, а в) ключ: = отсортировано [1]. подмножество: = пустой набор в то время как не пустой (отсортированный) и sorted [1] .a = ключ вставить отсортировано [1] в подмножество удалить отсортировано [1]
Простая реализация на C #
Обратите внимание, что эта реализация предполагает, что атрибуты соединения уникальны, то есть нет необходимости выводить несколько кортежей для заданного значения ключа.
общественный учебный класс MergeJoin{ // Предположим, что левый и правый уже отсортированы общественный статический Связь Объединить(Связь оставили, Связь верно) { Связь выход = новый Связь(); пока (!оставили.IsPastEnd() && !верно.IsPastEnd()) { если (оставили.Ключ == верно.Ключ) { выход.Добавлять(оставили.Ключ); оставили.Продвигать(); верно.Продвигать(); } еще если (оставили.Ключ < верно.Ключ) оставили.Продвигать(); еще // если (left.Key> right.Key) верно.Продвигать(); } возвращаться выход; }} общественный учебный класс Связь{ частный Список<int> список; общественный const int ENDPOS = -1; общественный int позиция = 0; общественный int Позиция { получать { возвращаться позиция; } } общественный int Ключ { получать { возвращаться список[позиция]; } } общественный bool Продвигать() { если (позиция == список.Считать - 1 || позиция == ENDPOS) { позиция = ENDPOS; возвращаться ложный; } позиция++; возвращаться истинный; } общественный пустота Добавлять(int ключ) { список.Добавлять(ключ); } общественный bool IsPastEnd() { возвращаться позиция == ENDPOS; } общественный пустота Распечатать() { для каждого (int ключ в список) Консоль.WriteLine(ключ); } общественный Связь(Список<int> список) { это.список = список; } общественный Связь() { это.список = новый Список<int>(); }}