Основные возможности CUBRID 8.4.0

    Приветствую всех!

    Этот блог будет очень занимательным! Сегодня я расскажу об очень интересных особенностях последней версии CUBRID 8.4.0, о том, чего обычно не найдешь в мануале. Приведу очень важные рекоммендации по оптимизации запросов и индексов, приведу результаты тестов, а также примеры использования в реальных Веб сервисах.

    Ранее я уже поверхностно рассказывал об изменениях в новой версии, о вдвое ускоренном движке базы данных, о расширенной поддержке MySQL синтаксиса, и т.д. А сегодня расскажу о них и других вещах более подробно, акцентируя на том, как мы смогли увеличить производительность CUBRID в два раза.

    Основные направления, повлиявшие на производительность CUBRID, являются:
    • Уменьшение размера тома базы данных
    • Улучшенные параллельные вычисления в Windows версии
    • Оптимизации индексов
    • Оптимизации обработки условий в LIMIT
    • Оптимизации обработки условий в GROUP BY


    Уменьшение размера тома базы данных


    В CUBRID 8.4.0 размер тома базы данных уменьшился аж на целых 218%. Причиной этому является полностью измененнная структура для хранения индексов, что параллельно повлияло на производительность всей системы.

    В следующем рисунке можно увидеть сравнение размера томов базы данных в предыдущей версии 8.3.1 и новой 8.4.0. В этом случае обе базы данных хранили по 64,000,000 записей с первичным ключем. Данные указаны в гигабайтах.

    Сравнение использования тома базы данных.

    Улучшенные параллельные вычисления в Windows версии


    В CUBRID 8.4.0 улучшены параллельные вычисления в версии для Windows платформы с помощью усовершенствованных Мьютексов. В следующем графике указаны сравнительные результаты производительности предыдущей и новой версий.

    Улучшенные параллельные вычисления в Windows версии

    Оптимизации индексов


    Вот тут-то я расскажу Вам все очень подробно.

    CUBRID 8.4.0 отличается от предыдущей версии вдвое ускоренным движком базы данных. Мы реализовали несколько очень важных оптимизаций индексов, как:
    • Покрывающий индекс
    • Оптимизация обработки условий в LIMIT
      — Ограничение по ключям (Key Limit)
      — Многодиапазонное сканирование (Multi Range)
    • Оптимизация обработки условий в GROUP BY
    • Сканирование индекса по убыванию
    • Поддержка сканирования индекса в операторах LIKE

    Теперь давайте посмотрим как организована структура индексов в CUBRID 8.4.0. В CUBRID индекс реализован в виде B+ дерева [ссылка на статью в Википедии], в котором значения ключей индекса хранятся в листьях дерева.

    Для практического примера предлагаю посмотреть на следующую структуру таблицы (STRING = VARCHAR(1,073,741,823)):

    CREATE TABLE tbl (a INT, b STRING, c BIGINT);

    Введем данные:

    INSERT INTO tbl VALUES (1, ‘AAA, 123), (2, ‘AAA’, 12), …;

    И создадим многоколоночный индекс. Кстати, заметьте, что индекс я создаю после того, как ввел данные. Это — рекоммендуемый способ, если Вы хотите вводить данные на начальном этапе или при их востановлении. Таким образом, вы можем избежать затраты времени и ресурсов на индексирования при каждом вводе. Более подробно о рекоммендациях при вводе больших данных вы можете прочитать здесь.

    CREATE INDEX idx ON tbl (a, b);

    На рисунке ниже показана структура этого индекса, в листьях которого есть указатели (OID) на сами данные, находящиеся в куче-файле (heap file) на диске.

    Структура индекса в CUBRID
    1. Таким образом, значения ключей индекса (a и b) отсортированы по увеличению (по умолчанию).
    2. Каждый лист имеет указатель (указанный стрелкой) на соответсвующие данные (запись в таблице), находящиеся в куче на диске.
    3. Данные в куче расположены в случайном порядке, как указано на рисунке.

    Сканирование индекса

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

    SELECT * FROM tbl
    WHERE a > 1 AND a < 5
    AND b < ‘K’
    AND c > 10000
    ORDER BY b;

    1. Сначала CUBRID найдет все листья, в которых a >1 и a < 5.
    2. Затем среди этого результата, он отберет листья, в которых b < 'K'.
    3. Так как колонка c не индексирована, для получения ее значений необходимо обратиться в кучу, который находится на диске.
    4. Каждый лист в дереве индекса содержит значение OID (Идентификатор Объекта), который указывает, где именно на диске хранятся данные определенной записи таблицы.
    5. Исходя из этих OID, сервер обратится в кучу для получения значений колонки c.
    6. Затем CUBRID найдет все те записи, в которых c > 10000.
    7. В результате все эти записи будут отсортированы по колонке b, как требуется в запросе.
    8. Затем полученные результаты отправляется к клиенту.

    Сканирование Индекса в CUBRID

    Покрывающий индекс

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

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

    SELECT a, b FROM tbl
    WHERE a > 1 AND a < 5
    AND b < ‘K’
    ORDER BY b;

    • Как Вы можете заметить, все колонки, используемые в данном запросе, находятся в одном многоколоночном индексе, который мы создали в самом начале.
    • В условии оператора WHERE указаны только те колоки, которые находятся в одном многоколоночном индексе.
    • Также в условии оператора ORDER BY указана только та колонка, которая находятся в том же многоколоночном индексе.

    И так, если мы запустим этот запрос:
    1. Как часть обычного процесса сканирования индекса, CUBRID сначала найдет все листья в дереве индекса, в которых a >1 и a < 5.
    2. Затем среди этого результата, он отберет листья, в которых b < 'K'.
    3. Так как значения колонок a и b уже получены в процессе сканирования индекса, уже нет необходимости идти и смотреть в кучу на диске, чтобы получить эти значения. Таким образом, после второго шага сервер сразу приступает в сортированию результатов по колонке b.
    4. Затем возвращает значения.

    Покрывающий индекса в CUBRID

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

    Q1. Ниже приведен запрос, который использует колонки, указанные в одном составном индексе.

    SELECT a, b FROM tbl WHERE a BETWEEN ? AND ?

    Q2. А теперь запрос, где колонка a индексирована, а колонка c — нет.

    SELECT a, c FROM tbl WHERE a BETWEEN ? AND ?

    Следующая график показывает, насколько быстро могут быть обработаны запросы, если они используют покрывающий индекс.

    Производительность покрывающего индекса в CUBRID

    Оптимизации обработки условий в LIMIT


    Ограничение по ключям (Key Limit)

    У CUBRID 8.4.0 — очень «умный» анализатор операторов LIMIT. Данный анализатор был очень оптимизирован, что позволяет обрабатывать только то количество записей, которое требуется в условии оператора LIMIT, при достижении которого сервер сразу возвращает результаты. К примеру, посмотрим на следующий запрос.

    SELECT * FROM tbl
    WHERE a = 2
    AND b < ‘K’
    ORDER BY b
    LIMIT 3;

    1. CUBRID сначала находит первый лист в дереве индекса, в котором a = 2.
    2. Так как индекс включает значения колонки b, которые уже отсортированы, нет необходимости отдельно отсортировывать результаты.
    3. Сервер проходит только по первым 3-м ключам индекса и на этом останавливается, так как нет необходимости возвращать больше 3 результатов.
    4. Затем сервер уже обрщается в кучу, чтобы получить значения всех остальных колонок. Таким образом только 3 записи будет затронуты на диске.

    Ограничение по ключям в CUBRID

    Многодиапазонное сканирование (Multi Range)

    Оптимизация многодиапазонного сканирования является еще одним главным усовершенствованием в новом CUBRID 8.4.0. Когда пользователи заправшивают данные, которые лежат в определенном диапазоне, например, между a > 0 AND a < 5, задача является довольно легкой для большинства СУБД. Однако все становится намного сложнее, когда в условия включаются разбросанные диапазоны, например, a > 0 AND a < 5 AND a = 7 AND a > 10 AND a < 15. Здесь то CUBRID и отличается. Новая функция оптимизации in-place sorting (сортировка на лету) позволяет решить сразу две задачи:
    1. Ограничение по ключям (Key Limit)
    2. А также сортировка записей на лету

    К примеру, рассмотрим следующий запрос.

    SELECT * FROM tbl
    WHERE a IN (2, 4, 5)
    AND b < ‘K’
    ORDER BY b
    LIMIT 3;

    1. Так как все ключи в дереве индекса отсортированы, сервер начнет сканирование, начиная с первого листа, где a = 2 (см. рисунок ниже).
    2. Так как необходимо получить только 3 строки таблицы, отсортированные по колонке b, сервер будет отсортировывать результаты, удовлетворяющие условию a IN (2, 4, 5) AND b < 'K', на лету.
      1. В самом начале сервер найдет запись (2, AAA), что дает 1-й результат.
      2. Затем находит запись (2, ABC), что дает 2-й результат.
      3. Затем находит запись (2, CCC), что дает 3-й результат.
      4. Так как сервер нашел уже 3 записи, он прыгает на следующий диапазон, в целях поиска записей, где значения колонки b будут меньше уже найденных значений.
      1. Сначала сервер найдет запись (4, DAA), который больше, чем последнее значение колонки b уже найденных записей. Поэтому этот диапазон сразу отпадает, и сервер прыгает на следующий диапазон.
      2. Находит запись (5, AAA), который меньше, чем ABC и CCC. Поэтому убирает последнюю запись и вставляет эту запись в подходящее место.
      3. Следующая запись (5, BBB) уже больше, чем последняя запись предварительных результатов. Поэтому на этом сканирование этого диапазона завершается. Также завершается и весь поиск, так как больше нет других диапазонов необходимые для сканирования.

    3. Так как все результаты уже отсортированы, остается только заглянуть в кучу и получить значения остальных колонок.

    Благодаря этой возможности многодиапазонного сканирования с сортированием на лету, CUBRID может производить очень быстрый поиск среди большого количества данных.

    Многодиапазонное сканирование в CUBRID

    Результаты тестов

    В Корее есть очень популярный Веб сервис Me2Day, аналог Твиттера. Следующие результаты тестов были получены на основе реальных данных этого сервиса.

    Как и в Твиттере, в Me2Day есть таблица posts, где хранятся все «твиты». Статистика пользователей и их отношений показывает, что:
    • 50% пользователей следят за 1-50 пользователями.
    • 40% пользователей следят за 51-2000 пользователями.
    • 10% пользователей следят за 2001+ пользователями.

    Для этой таблицы создан следующий индекс.

    INDEX (author_id, registered DESC)

    Самый главный запрос, который чаще всего запрашивается и в сервисе Twitter, и в сервисе Me2Day — это "показать последние 20 случайных постов всех пользователей, за которыми я слежу". Ниже приведен этот самый запрос.

    SELECT * FROM posts
    WHERE author_id IN (?, ?, ..., ?) AND registered < :from ORDER BY reg_date DESC
    LIMIT 20;


    Тест был запущен на 10 минут, в период которых продолжительно обрабатывался этот запрос. Ниже приведет график результатов тестирования, в котором сравнивается оператор UNION в MySQL, который в среднем в 4 раза быстрее, чем IN оператор в MySQL, с оператором IN в CUBRID. За одно, сравнив с предыдущей версие, Вы можете посмотреть, насколько увеличилась производительность CUBRID 8.4.0 после реализации многодеапазонного сканирования.

    Результаты тестов оператора IN в CUBRID

    После таких положительных результатов мы заменили MySQL сервера Me2Day, отвечающие за ежедневную работу сервиса, на сервера CUBRID. В следующий раз расскажу об этом тесте более подробно. А пока Вы можете также прочитать о нем на английском на главном сайте.

    Оптимизации обработки условий в GROUP BY


    Новая версия CUBRID 8.4.0 значительно ускорила обработку запросов, содержащие ORDER BY и GROUP BY операторы. Когда в условиях ORDER BY и GROUP BY используются колонки, включенные в многоколоночный индекс, отпадает необходимость отсортировывать значения, так как они уже отсортированы в дереве индекса. Такая оптимизация позволяет значительно увеличить производительность обработки всего запроса. Можем посмотреть на работу следующего запроса.

    SELECT COUNT(*) FROM tbl
    WHERE a > 1 AND a < 5
    AND b < ‘K’ AND c > 10000
    GROUP BY a;

    1. Как часть обычного процесса сканирования индекса, CUBRID сначала найдет все листья в дереве индекса, в которых a >1 и a < 5.
    2. Используя значения OID, сервер обратится в кучу для получения значений колонки c.
    3. Затем CUBRID найдет все те записи, в которых c > 10000.
    4. Так как все необходимые значения уже отсортированы, операция GROUP BY будет производиться сразу же без предварительной сортировки.
    5. Затем сервер возвращает полученные результаты.

    GROUP BY в CUBRID

    Увеличение Продуктивности Разработчиков



    Помимо улучшения производительности всей системы, новая версия CUBRID 8.4.0 поддерживает более 90% SQL синтаксиса СУБД MySQL. Мы также реализовали расширенную поддержку неявного преобразования типов, чтобы разработчики концентрировались на улучшение функциональности своих приложений, в то время как CUBRID будет делать все внутренние преобразования. Ниже приведу несколько примеров нового синтаксиса.
    • Неявное преобразование типов
      CREATE TABLE x (a INT);
      INSERT INTO x VALUES (‘1’);

    • Запросы SHOW
      SHOW TABLES; SHOW COLUMNS; SHOW INDEX; …

    • ALTER TABLE… CHANGE/MODIFY COLUMN…
      CREATE TABLE t1 (a INTEGER);
      ALTER TABLE t1 CHANGE a b DOUBLE;
      ALTER TABLE t2 MODIFY col1 BIGINT DEFAULT 1;

    • UPDATE… ORDER BY
      UPDATE t
      SET i = i + 1
      WHERE 1 = 1
      ORDER BY i
      LIMIT 10;

    • DROP TABLE IF EXISTS…
      DROP TABLE IF EXISTS history;

    Всего в новой версии 23 новых DATE/TIME синтаксиса, 5 — связанных со строками, и 5 новых функций аггрегирования. Весь список нового синтаксиса можете найти в блоге на офф. сайте.

    Улучшение недёжности Высокой Доступности


    Улучшение блокировки следующего ключа

    Также в версии CUBRID 8.4.0 значительно улучшили механизм блокировки, чтобы минимизировать появления застоев. Например, в среде Высокой Доступности застои не будут образовываться между транзакциями, которые вводят данные в одну и ту же таблицу в одно и то же время.

    Заключение


    Как Вы, наверное, уже поняли, новая версия CUBRID 8.4.0 явно превосходит все предыдущие версии и в производительности, и в надёжности, и в удобстве разработки. CUBRID разрабатывается с целью использования в Веб приложениях и сервисах, посему все основные разработки, улучшения и оптимизации ведутся в сфере функций, часто используемых в Веб приложениях (например, как операторы IN, ограничения LIMIT, группировки и сортирование, а также Высокая Доступность), превосходство в производительности которых доказывается результатами сравнительных тестов.

    Если у Вас есть определенные вопросы, пишите в комментариях. Буду очень рад все разъяснить!
    CUBRID
    20,00
    Компания
    Поделиться публикацией

    Комментарии 4

      0
      а где можно глянуть сравнение производительности с mysql и postgresql?
        0
        С PostgreSQL не сравнивали, пока в планах нет. С MySQL есть одна статья тут на Хабре и на офф. сайте. Посмотрите, и если будут вопросы, пожалуйста, задавайте.
        0
        «размер тома базы данных уменьшился аж на целых 218%» — это как? :)
          0
          Т.е. теперь данные в базе, включая сами индексы, занимают на более чем в половину меньше места на диске.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое