Колоночные СУБД против строчных, как насчет компромисса?


    Колоночные СУБД активно развивались в нулевых годах, на данный момент они нашли свою нишу и практически не конкурируют с традиционными, строчными системами. Под катом автор разбирается, возможно ли универсальное решение и насколько оно целесообразно.
    «Во всём виден прогресс.… не надо бояться, что тебя вызовут в канцелярию и скажут: ”Мы тут посовещались, и завтра вы будете четвертованы или сожжены по вашему собственному выбору.“ Это был бы тяжелый выбор. Я думаю, многих из нас он бы поставил в тупик.»
    Ярослав Гашек. Похождения бравого солдата Швейка.

    Предыстория


    Сколько существуют базы данных, столько и длится это идеологическое противостояние. Автор из любопытства нашел в закромах книгу Дж.Мартина из IBM [1] 1975 года и тут же наткнулся в ней на слова (стр.183): “В работах […] используются бинарные отношения, т.е. отношения только двух доменов. Известно, что бинарные отношения придают наибольшую гибкость базе. Однако в коммерческих задачах удобными являются отношения различных степеней.” Под отношениями здесь понимаются именно реляционные отношения. А упомянутые работы датированы 1967...1970 гг.

    Пусть Sybase IQ была первой промышленно используемой колоночной СУБД, но по крайней мере на уровне идей, всё проговаривалось за 25 лет до неё.

    На данный момент являются по-колоночными или в той или иной мере поддерживают эту возможность следующие СУБД (взято в основном здесь):

    Коммерческие


    Free & open source


    Различия


    Реляционное отношение есть набор кортежей, в сущности двумерная таблица. Соответственно имеются две возможности хранения — построчная или по-колоночная. Разделение это немного искусственное, логическое. Разработчики баз данных давно уже не занимаются планированием записей по барабанам и дорожкам. Оптимально разложить данные СУБД по файловой системе(мам) — задача администраторов СУБД, а как как файловая система располагает данные на физических дисках известно в основном разработчикам файловых систем.

    Было бы логично предоставить СУБД самой решать в каком порядке хранить данные. Здесь мы говорим о некоторой гипотетической СУБД, которая поддерживает оба варианта организации хранения данных и имеет возможность назначить таблице любой из них. Мы не рассматриваем вполне популярный вариант поддерживать две БД — одну для работы, вторую для аналитики/отчетов. Также как и колоночные индексы a la Microsoft SQL Server. Не потому что это плохо, а для проверки гипотезы что существует какой-то более изящный способ.

    К сожалению, никакая самая гипотетическая СУБД не сможет выбрать как лучше хранить данные. Т.к. не обладает пониманием того, как мы эти данные собираемся использовать. А без этого выбор сделать невозможно, хотя он очень важен.

    Самым ценным качеством СУБД является способность быстро обрабатывать данные (и требования ACID, само собой). Скорость работы СУБД в основном определяется числом дисковых операций. Отсюда возникают два крайних случая:

    • Данные быстро изменяются/добавляются, надо успевать записывать. Очевидное решение — строка (кортеж) по возможности расположена на одной странице, быстрее не сделать.
    • Данные меняются крайне редко или вообще не меняются, мы многократно читаем данные, причем единовременно задействовано лишь небольшое число колонок. В этой ситуации логично использовать по-колоночный вариант хранения, тогда при чтении поднимется минимально возможное число страниц.

    Но это крайние случаи, в жизни всё не так очевидно.

    • Если требуется прочитать всю таблицу, то с точки зрения числа страниц не важно построчно или по-колоночно расположены данные. Т.е некоторая разница, конечно есть, в по-колоночном варианте мы имеем возможность лучше сжимать информацию, но в данный момент это не принципиально.
    • А вот с точки зрения производительности разница есть т.к. при построчной записи чтение с диска будет происходить более линейно. Меньшее число пробросов головок жесткого диска заметно ускоряет чтение. Более предсказуемое чтение файла при построчной записи позволяет операционной системе (ОС) эффективнее использовать дисковый кэш. Это имеет значение даже для SSD дисков, т.к загрузка по предположению (read ahead) чаще приводит к успеху.
    • Update далеко не всегда меняет запись целиком. Предположим, частый случай — изменение двух колонок. Тогда будет хорошо, если данные этих колонок окажутся на одной странице, ведь потребуется только одна блокировка страницы на запись вместо двух. С другой стороны, если данные разнесены по страницам, это даёт возможность разным транзакциям менять данные одной строки без конфликтов.

      Вот здесь повнимательнее. Гипотетический выбор — сделать таблицу строчной или колоночной, СУБД должна сделать в момент её создания. Но чтобы сделать этот выбор неплохо бы знать, например, каким образом мы собираемся эту таблицу менять. Может стоит подбросить монетку?
    • Предположим, мы используем для хранения древовидную структуру (ex:clustered index). В этом случае добавление данных или даже их изменение могут привести к пере-балансировке дерева или его части. При строчном хранении возникает (минимум одна) блокировка на запись, которая может затронуть значительную часть таблицы. В по-колоночном варианте такие истории происходят гораздо чаще, но наносят гораздо меньше ущерба т.к. касаются только конкретной колонки.
    • Рассмотрим выборку с фильтрацией по индексу. Предположим, выборка достаточна разреженная. Тогда построчная запись имеет предпочтение, ведь в этом случае лучше соотношение полезной информации к прочитанной за компанию.
    • Если же фильтрация даёт более плотный поток и требуется лишь небольшая часть колонок, дешевле становится по-колоночный вариант. Где водораздел между этими случаями, как его определить?

    Иными словами, ни при каких обстоятельствах наша гипотетическая СУБД не возьмет на себя ответственность выбора между строчным и по-колоночным вариантами хранения, это должен сделать проектировщик БД.

    Впрочем, учитывая вышесказанное, и проектировщик БД окажется в ситуации очень тяжелого выбора. Многих из нас он бы поставил в тупик.

    А что если


    В сущности и по-колоночный и строчный варианты — крайние случаи одной идеи — нарезать таблицу на “ленточки“ и внутри каждой ленты хранить данные построчно. Просто в одном случае лента одна, в другом ленты вырождаются до одной колонки.

    Так почему бы не допустить и промежуточные варианты — если данные некоторых колонок приходят/читаются вместе, пусть и окажутся на одной ленте. А если в ленте не оказалось данных (NULL-ы), то и хранить ничего не надо. Заодно снимается проблема максимального размера строки — можно расщепить таблицу, когда есть риск, что строка не поместится на одной странице.

    Идея эта не так чтобы особо оригинальная, автору доводилось и видеть подобное и самому применять. Элемент новизны в том, чтобы дать возможность проектировщику БД возможность самому определять как именно его таблица будет разбита на части и в каком виде данные попадут на диск.

    Мы для себя это сделали следующим образом:

    • при создании таблицы информация о наших предпочтениях передаётся SQL-процессору с помощью прагм
    • изначально при создании таблицы предполагается, что строка целиком будет расположена на одной странице В-дерева
    • однако можно использовать — — #pragma page_break
      для того, чтобы сообщить SQL-процессору, что следующие колонки будут расположены на другой странице (в другом дереве)
    • использование — — #pragma column_based
      позволяет лаконично сказать, что идущие далее колонки расположены каждая на своём дереве
    • — — #pragma row_based
      отменяет действие column_based
    • таким образом, таблица состоит из одного или более B-дерева, первым элементом ключа которого является скрытое IDENTITY поле. Есть мнение, что порядок, в котором создаются записи (вполне может коррелировать с порядком, в котором записи будут читать) тоже имеет значение и не стоит им пренебрегать. Первичный ключ является отдельным деревом, впрочем, это уже не относится к теме.

    Как это может выглядеть на практике?

    Например, так:

    CREATE TABLE twomass_psc (
        ra double precision,
        decl double precision,
        …
        -- #pragma page_break
        j_m real,
        j_cmsig real,
        j_msigcom real,
        j_snr real,
        h_m real,
        h_cmsig real,
        h_msigcom real,
        h_snr real,
        k_m real,
        k_cmsig real,
        k_msigcom real,
        k_snr real,
        -- #pragma page_break
        …
        coadd_key integer,
        coadd smallint
    );

    Для примера взята основная таблица атласа 2MASS, легенда здесь и здесь.
    J, H, K — инфракрасные под-диапазоны, данные по ним есть смысл хранить вместе, поскольку в исследованиях они обрабатываются вместе. Вот, например:


    Первая попавшаяся картинка.

    Или вот, даже красивее:

    Самое время подтвердить, что это имеет какой-то практический смысл.

    Результаты


    Ниже представлена:

    • фазовая диаграмма (X-номер записываемой страницы, Y-номер последней записанной ранее) порядка записи страниц (логических номеров) на диск при создании таблицы в двух вариантах
    • по-колоночном, он обозначен как by_1
    • и для таблицы, порезанной по 16 колонок, он обозначен как by_16
    • всего колонок 181


    Рассмотрим повнимательнее как она устроена:



    • Вариант by_16 заметно компактнее, что логично, предельный — строчный вариант дал бы просто прямую линию (с выбросами).
    • Треугольные выбросы — запись промежуточных страниц В-деревьев.
    • Показана запись данных, очевидно, чтение будет выглядеть примерно так же.
    • Выше говорилось, что все варианты записывают одно и тоже количество информации и поток, который надо вычитать, примерно одинаков (± эффективность сжатия).
      Но здесь очень наглядно показано, что в по-колоночном варианте деревья растут с разной скоростью за счет специфики данных (в одной колонке они часто повторяются и сжимаются очень хорошо, в другой колонке — шум с точки зрения компрессора). В результате одни деревья забегают вперед, другие запаздывают, при чтении мы объективно получаем очень неприятный для файловой системы “рваный” режим чтения.
    • Так вот, вариант by_16 намного предпочтительнее для чтения чем по-колоночный, он практически равен в комфорте по-строчному варианту.
    • Но при этом вариант by_16 обладает основными плюсами по-колоночного варианта в случае, когда требуется небольшое к-во колонок. Особенно если расщеплять таблицу не механически по 16 штук, а осмысленно, после анализа вероятностей их совместного использования.

    Источники


    [1] Дж.Мартин. Организация баз данных в вычислительных системах. “Мир”, 1978
    [2] Колоночные индексы, особенности использования
    [3] Daniel J. Abadi, Samuel Madden, Nabil Hachem. ColumnStores vs. RowStores: How Different Are They Really?, Proceedings of the ACM SIGMOD International Conference on Management of Data, Vancouver, BC, Canada, June 2008
    [4] Michael Stonebraker, Uğur Çetintemel. «One Size Fits All»: An Idea Whose Time Has Come and Gone, 2005
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 43

      +1
      Вы бы вычитку сделали, исправили оЧепятки
        +1
        Об очепятках обычно сообщают в личку с примерами оных.
        +1

        Что только люди не придумают, лишь бы не изучать работу с графами :-) Смотрите, как это делается с графовой субд:
        Есть документы — это узлы графа (строчки в терминах рсубд, но иерархические и с перекрёстными ссылками).
        Есть классы документов — к ним привязываются схемы, триггеры и пр (таблицы в терминал рсубд).
        Есть кластеры — это группы любых узлов, хранящиеся вместе (ленты в ваших терминах).
        Есть ноды — физические машинки.


        Теперь следите за руками:


        CREATE CLASS twomass_psc;
        
        CREATE PROPERTY twomass_psc.ra DOUBLE;
        CREATE PROPERTY twomass_psc.decl DOUBLE;
        CREATE PROPERTY twomass_psc.xyz LINK twomass_xyz;
        CREATE PROPERTY twomass_psc.coadd_key INTEGER;
        CREATE PROPERTY twomass_psc.coadd SHORT;
        
        CREATE CLASS twomass_xyz;
        
        CREATE PROPERTY twomass_xyz.j_m FLOAT;
        CREATE PROPERTY twomass_xyz.j_cmsig FLOAT;
        CREATE PROPERTY twomass_xyz.j_msigcom FLOAT;
        CREATE PROPERTY twomass_xyz.j_snr FLOAT;
        CREATE PROPERTY twomass_xyz.h_m FLOAT;
        CREATE PROPERTY twomass_xyz.h_cmsig FLOAT;
        CREATE PROPERTY twomass_xyz.h_msigcom FLOAT;
        CREATE PROPERTY twomass_xyz.h_snr FLOAT;
        CREATE PROPERTY twomass_xyz.k_m FLOAT;
        CREATE PROPERTY twomass_xyz.k_cmsig FLOAT;
        CREATE PROPERTY twomass_xyz.k_msigcom FLOAT;
        CREATE PROPERTY twomass_xyz.k_snr FLOAT;

        Тут мы создали два класса, где документы из первого класса ссылаются на документы из второго. По умолчанию каждый класс будет лежать в своём кластере, но можно и вручную указать какой куда положить:


        CREATE CLUSTER project_cucumber;
        
        INSERT INTO twomass_psc CLUSTER project_cucumber SET
            ...
            xyz = ( INSERT INTO twomass_xyz CLUSTER project_cucumber SET ... );

        И при репликации и шардировании кластеры будут раскидываться по машинам целиком, что гарантирует, что запросы внутри кластера не потребуют дорогостоящей коммуникации к другим машинам или даже дата-центрам.

          0
          пространственный индекс к кому цеплять будем?
            0
            К какому-то из этих классов. Я не имею ни малейшего понятия что это за данные.
              0
              Описание небесных объектов.
              XYZ-светимости в разных диапазонах
              Ra|Dec — координаты
              Где пространственный индекс будет?
                0
                Подвох здесь незатейливый.
                Конечно, логично прицепить пространственный индекс к кому классу, который содержит координаты (twomass_psc). Но тогда при фильтрации по пространственному критерию придется сделать лишнее чтение, чтобы получить ссылку на класс со светимостями (twomass_xyz).

                Делать (дублировать) пространственный индекс к twomass_xyz нелогично.
                Хранить в пространственном индексе ссылки на все экземпляры классов — некрасиво.
                Да и позволит ли это СУБД.
                Иметь один индекс на всех — а кто будет синхронизировать идентификаторы в разных классах?

                Никто ведь не запрещает и в реляционной парадигме иметь разные таблицы (twomass_psc,twomass_xy...) и join-ить их при необходимости. Но возникнут те же самые вопросы.

                Вообще, противостояние табличных и сетевых СУБД длится столько же, сколько существуют сами СУБД. Это как противостояние брони и снаряда.
                  0
                  Ну да, будет дополнительное чтение. Мы же для этого всё это и затевали, чтобы часть данных хранилась отдельно. Или что вы пытаетесь добиться?

                  В неуникальный индекс можно по одному ключу засовывать несколько разных документов. Зачем синхронизировать идентификаторы, если они не меняются?
                    0
                    Почему пытаюсь, в статье описано как сделать это без дополнительного чтения.
                    И зачем городить огород с разными классами, когда можно всё сделать в рамках старого доброго SQL?
                      0
                      В сущности и по-колоночный и строчный варианты — крайние случаи одной идеи — нарезать таблицу на “ленточки“ и внутри каждой ленты хранить данные построчно. Просто в одном случае лента одна, в другом ленты вырождаются до одной колонки.

                      Так почему бы не допустить и промежуточные варианты — если данные некоторых колонок приходят/читаются вместе, пусть и окажутся на одной ленте. А если в ленте не оказалось данных (NULL-ы), то и хранить ничего не надо. Заодно снимается проблема максимального размера строки — можно расщепить таблицу, когда есть риск, что строка не поместится на одной странице.

                      Каждая дополнительная "ленточка" — это дополнительное чтение.


                      Прагмы — это не "старый добрый SQL". Я привёл примеры на диалекте SQL — OSQL.

                        0
                        Конкретный запрос — построение статистики совместного распределения JKH
                        при фильтрации по пространственному критерию не требует дополнительного чтения.

                        В том и суть, если я знаю как собираюсь искать, то имею возможность настроить данные так, чтобы избежать чтения ненужного.
                          –1
                          Вы специально вбрасываете кучу специфических терминов, чтобы было ничего не понятно?

                          Если данные лежат в разных местах и нужны, то читать несколько раз в этих разных местах по любому придётся. Если же вы чисто про индексы, то любой индекс — это дерево, а дерево — частный случай графа.
                            0
                            Любой индекс в описанной в статье схеме относится ко всем колонкам.
                            Так же как и в строчных СУБД (и в колоночных, кстати).

                            Поэтому при фильтрации по индексу нет необходимости делать дополнительное чтение, чтобы узнать ссылку на экземпляр нужного класса.

                            Уж не знаю как и разжевывать.
                              0
                              Как я уже говорил, нет проблемы в том, чтобы засунуть в индекс по одному ключу несколько документов. В том числе засовывать в индекс не сами исходные документы, а агрегирующие документы со ссылками на исходные. Рулить в таком случае индексами придётся через триггеры, да. Но и возможностей гораздо больше.
                                0
                                Зачем пихать в индекс идентификаторы нескольких документов,
                                если это один документ? Вместе с идентификатором документа придётся хранить и идентификатор таблицы/класса. Конечно можно, но зачем, если можно обойтись без этого?

                                … is like sleeping with your sister. Sure she's a great piece of tail with a blouse full of goodies, but it's just illegal.

                                Topper Harley
                                  0

                                  Если нам нужно по разному хранить части документа, то по факту это разные документы. Идентификатор документа состоит из двух частей: номер кластера и номер документа в нём. @12:345

                                    0
                                    Если вы готовы из неведомых мне соображений принести в жертву производительность, не стану мешать.
                                    Но сам так делать не стану и никому не посоветую.
                                      0
                                      Почему вы считаете, что это медленнее?
                                        0
                                        Индексы распухнут, нет?
                                          0

                                          Индексы — это деревья, деревья — это графы. В графовой субд нет деления на таблицы и костыли к таблицами, чтобы первые не тормозили. Вся ваша база — один большой индекс.

                                            0
                                            А зачем тогда в графовых бд предназначены специальные команды для явного создания индексов?

                                            Логика "у индексов под капотом графы, значит для графов отдельные индексы не нужны" это примерно как "у лопаты черенок из дерева, значит чтобы в лесу выкопать яму, лопата не нужна, там и так деревья есть".
                                              0
                                              Для простоты использования главным образом. Не надо самому триггеры писать, ключ формировать и тд.
                                                0
                                                Так нужны индексы или нет? Подвижность вашей позиции удивляет. Сначала для вас приемлемо лишнее чтение,
                                                потом вы собираетесь идентификаторы всех частей записи записывать в индексах. Теперь и индексы не нужны.

                                                Самое время продемонстрировать хоть какие-то преимущества графового подхода. Сейчас я вижу одни только издержки.
                                                  0

                                                  Тут неплохо объясняется, чем графовый подход лучше: https://www.slideshare.net/lvca/how-graph-databases-started-the-multi-model-revolution

                                                    0
                                                    А без «мурзилок», вот на конкретной задаче объясните,
                                                    что ваш подход может предложить такого, чего нельзя достичь обычными средствами.
                                                      +1
                                                        0
                                                        Не не, это совершенно разные задачи.
                                                        Здесь речь о таблице с большим число записей (и колонок), минимизируем стоимости и создания такой таблицы и поиска по ней с фильтрацией.
                                                          0
                                                          Я же написал про это в самом начале. Мы ушли в рекурсию.
                                                            0
                                                            Покажите пальцем плз.
              0
              Да, кстати. Предположим что у вас более 2, пусть 3 класса, описывающих то, что когда-то было одной таблицей. Какова будет топология взаимоотношений между ними?
              Вот вы нарисовали одну ссылку из psc в xyz. Пусть есть еще qwe.

              Циклы делать нехорошо по понятным причинам. Звезда?
              Ок, у нас ссылки psc->xyz и psc->qwe. Рассмотрим select, в котором задействованы только колонки из xyz и qwe. Опять не обойтись без центрального узла с его ссылками.
                0
                Циклы делать нехорошо по понятным причинам.

                Не понятным.

                  0
                  Это бы вызвало либо повторный update одного из документов
                  либо необходимость руками управлять идентификаторами.
                  И то и другое не слишком красиво.

                  Кроме того, цикл предполагает наличие упорядочения в обходе разных классов.
                  А поскольку в самой задаче такое упорядочение не заложено, оно будет привнесено искусственно, а значит обязательно вылезет потом в виде ограничений/издержек.
                    0

                    Обновить 2 документа — это гораздо быстрее, чем обновить один документ и индекс. Ну и если руками расставлять двусторонние ссылки влом, то можно использовать высокоуровневый API который делает это за вас.


                    -- руками обеспечили обратные ссылки --
                    UPDATE @12:34 ADD bar = ( INSERT INTO bar SET( foo = @12:34 ) );

                    -- автоматически создали двусторонние ссылки --
                    CREATE EDGE foo_bar FROM @12:34 TO ( CREATE VERTEX bar )

                    Насчёт "упорядоченности" я не понял. Как наличие или отсутствие ссылки может что-то там "упорядочить"?

                      0
                      Обновить 2 документа — это гораздо быстрее, чем обновить один документ и индекс.
                      — не очевидно, документ и сам может быть расположен в индексе.

                      Упорядоченность возникает в тот момент, когда вам надо обойти цикл.
                        0

                        Обновление индекса может привести к его ребалансировке и как следствие гораздо большему числу записей.


                        Разумеется обходить цикл вы будете в каком-то не случайном порядке. Какие вы видите в этом проблемы?

                          0
                          Потенциальная проблема в том, что этот порядок привнесён искусственно.
                            0
                            Да нет, вполне естественный порядок. А вот порядок добавления данных в базу — весьма искусственный и недеретменированный.
                              0
                              В исходной задаче при разбиении записей по страницам эти страницы между собой никак не упорядочены.
                              Если конечно не заниматься схоластикой.

                              В схеме «звезда» тоже порядок отсутствует, есть правда центральное звено, но это еще как-то можно интуитивно оправдать.
                                0
                                Не понимаю, чего вы пытаетесь этим доказать.
                                  0
                                  Ничего не пытаюсь доказать, просто некрасиво.
              +1

              Идея ваша вполне понятна, не плоха и хорошо известна, но подана очень плохо.


              1. Все результат действия прагм примерно аналогичен созданию нескольких таблиц связанных по IDENTITY/ROWID. В MySQL это можно воспроизвести буквально, в СУБД с ROWID (PostresSQL) будет несколько иначе и примерно медленнее.


              2. Производительность этой схемы прежде всего зависит от отношения селектов/апдейтов, в том числе для отдельных полей. Этот момент как-то совсем не рассмотрен. Более того, это imho примерно единственная точка, с которой можно без усложнений и полноценно рассмотреть все плюсы-минусы.


              3. Добавлены отсылки к колоночным БД с их массовым перечислением, но при этом внезапно никак не упомянуты главное принципиальное отличие: Колоночные базы ориентированны на другой набор операций, поэтому как-правило не поддерживают апдейты, либо делают их крайне дорогими и без ACID. Соответственно, за счет этого могут использовать совсем другие индексы (примерно не b-tree, а зональные, битовые маски и column imprints).

              В сухом остатке выходит, что в статье:


              • описание well-known модели нескольких b-tree с общим PK;
              • это описание завуалированно и подано как новый велосипед с расширением синтаксиса SQL:
              • модель нескольких b-tree с общим PK сопоставляется с колоночной, без рассмотрения самых главных отличий.

              Вишенкой выглядит отсылка к колоночным индексам MS SQL. В целом складывается впечатление, что автор "поймал идею", но не достаточно осведомлен чтобы сопоставить её с уже существующим в индустрии и критически оценить.

                0
                1) про «несколько таблиц связанных по IDENTITY/ROWID».
                Конечно, так можно сделать. Конечному разработчику проще иметь дело с одной таблицей, которая где-то внутри разбита на ленты и деталей знать не надо. Не нужно следить за тем, чтобы ключи не рассогласовались. Не нужно всё обставлять скобками транзакций, если возникает например 3 insert-а вместо одного. Если я хочу в триггере использовать значение колонки из дружественной таблицы, просто беру и использую. Индексы относятся ко всем колонкам, не надо организовывать join-ы.… Разве нет?

                Опять же в тексте есть ссылка на статью «ColumnStores vs. RowStores: How Different Are They Really?». В ней пытаются эмулировать колоночные таблицы в обычной СУБД. Один из основных выводов — эмуляция не даёт нам понять, есть преимущества или нет.

                2) «Производительность этой схемы прежде всего зависит от отношения селектов/апдейтов, в том числе для отдельных полей». Да, это тема для будущих статей. Работа в процессе и я не готов делиться результатами.

                3) Мне бы не хотелось соревноваться с колоночными СУБД на их поле. Один из вложенных в статью смыслов (не знаю, насколько удалось) в том, чтобы показать, что есть смежная зона, где можно получить преимущества обоих подходов.

                PS: в статье честно сказано, что фактически новизна лишь в способе подачи подсказок SQL-процессору.

                PPS: автор вероятно «не достаточно осведомлен», но для этого и существует площадка Хабра,
                чтобы делиться мнениями и идеями, где можно встретить людей со знаниями в самых разных областях.
                  0
                  Вы вот это
                  INSERT INTO foo (auto,text)
                      VALUES(NULL,'text');              # generate ID by inserting NULL
                  INSERT INTO foo2 (id,text)
                      VALUES(LAST_INSERT_ID(),'text');  # use ID in second table
                  имели ввиду, когда говорили, что «создание нескольких таблиц связанных по IDENTITY… в MySQL можно воспроизвести буквально»?

                  Но это же совсем не то. Вся эта конструкция держится на доверии. На том, что прикладной программист всё сделает правильно. Правильно вставит, нигде не ошибётся, никто не полезет в таблицу вставлять/удалять грязными руками.

                  Фильтрацию по индексу одной таблицы и использование значений из другой без join-а не организуешь. Сумеет ли оптимизатор всегда распознать, что первую таблицу поднимать не надо?

                  Constraints уровня объединённой таблицы нетривиальны и остаются на совести разработчика.

                  Всё это детали реализации, которыми разработчика загружать не надо,
                  для него это должна быть одна таблица с общими индексами и общими constraints.

                  Этот вариант с MySQL напоминает обслуживание паровых машин до изобретения автоматического предохранительного клапана.

                Only users with full accounts can post comments. Log in, please.