Возможно, вы заметили, что MySQL теперь поддерживает создание функций (и процедур хранения) в Javascript с использованием GraalVM.
Эта новая функциональность доступна только в MySQL Enterprise и MySQL HeatWave.
Как разработчик, вы также можете получить бесплатный доступ к MySQL Enterprise из Oracle Technology Network (OTN): Загрузка MySQL Enterprise.
Зачем использовать JS-функцию?
Как вы, возможно, знаете, UUID становятся все более популярными, и их использование в MySQL ограничено UUID V1.
Итак, мы знаем, что можно извлечь временную метку из UUIDv1. Есть компонент MySQL (C ++), который предоставляет 3 UDF (определяемые пользователем функции) для этой цели. Компонент доступен на GitHub: mysql-component-uuid_v1.
При использовании MySQL DBaaS невозможно установить такие компоненты, и то же самое происходит с MySQL HeatWave. Следовательно, возможность использования функций JavaScript становится особенно выгодной в этом сценарии.
Функции для обработки UUIDv1
Затем мы создадим функции для анализа UUID MySQL и отображения метки времени.
Давайте начнем с извлечения временной метки как времени Unix в миллисекундах:
USE test; DROP function IF EXISTS js_uuid_to_unixtime; CREATE FUNCTION js_uuid_to_unixtime (uuid_in CHAR(36)) RETURNS CHAR(23) LANGUAGE JAVASCRIPT AS $$ const UUID_T_LENGTH = 16; const UNIX_TS_LENGTH = 6; function uuidToUnixTs(uuid_str) { const MS_FROM_100NS_FACTOR = 10000; const OFFSET_FROM_15_10_1582_TO_EPOCH = 122192928000000000n; // Разделите UUID символом "-" в качестве разделителя let uuid_parts = uuid_str.split('-'); // Создайте временную метку UUID из ее частей let uuid_timestamp = uuid_parts[2].substring(1) + uuid_parts[1] + uuid_parts[0]; // Преобразовать строку шестнадцатеричной метки времени в целое число let timestamp = BigInt('0x' + uuid_timestamp); // Вычислить временную метку Unix в миллисекундах let unixTimestampMs = Number((timestamp - OFFSET_FROM_15_10_1582_TO_EPOCH) / BigInt(MS_FROM_100NS_FACTOR)); return unixTimestampMs; } function stringToUuid(str) { if (str.length !== 36) { return 1; } if (str[14] !== '1') { return 1; } return 0; } let result = stringToUuid(uuid_in); let timestamp_out; if (result === 0) { timestamp_out = uuidToUnixTs(uuid_in)/1000; } else { timestamp_out="Error parsing UUID"; } return (timestamp_out); $$ ;
Давайте протестируем это:
MySQL > select now(), from_unixtime(js_uuid_to_unixtime(uuid())); +---------------------+--------------------------------------------+ | now() | from_unixtime(js_uuid_to_unixtime(uuid())) | +---------------------+--------------------------------------------+ | 2024-03-20 22:24:13 | 2024-03-20 22:24:13.503000 | +---------------------+--------------------------------------------+ 1 row in set (0.0009 sec)
Мы создали другие функции Javascript, предлагающие другой результат:
- js_uuid_to_datetime()
- js_uuid_to_datetime_long()
Давайте посмотрим на них в действии:
MySQL > select js_uuid_to_datetime(uuid()); +-----------------------------+ | js_uuid_to_datetime(uuid()) | +-----------------------------+ | 2024-03-20 22:31:20.824 | +-----------------------------+ 1 row in set (0.0009 sec) MySQL > select js_uuid_to_datetime_long(uuid()); +----------------------------------------------+ | js_uuid_to_datetime_long(uuid()) | +----------------------------------------------+ | Wednesday, March 20, 2024 at 10:31:30 PM GMT | +----------------------------------------------+ 1 row in set (0.0012 sec)
UUIDv7
Все больше и больше людей используют UUIDv7. К сожалению, они недоступны в MySQL. UUIDv7 являются последовательными и не используют Mac-адрес.
Мы также можем создавать функции Javascript для генерации и обработки UUIDv7 в MySQL HeatWave.
Функции доступны здесь.
Давайте протестируем UUIDv7 в качестве первичного ключа для таблицы:
MySQL > CREATE TABLE `item` ( `id` varbinary(16) NOT NULL, `name` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; MySQL > insert into item values (uuid_to_bin(js_uuidv7()),'item01'), (uuid_to_bin(js_uuidv7()),'item02'), (uuid_to_bin(js_uuidv7()),'item03'); Query OK, 3 rows affected (0.0060 sec) MySQL > select * from item; +------------------------------------+--------+ | id | name | +------------------------------------+--------+ | 0x018E5E04BA3376AED34A5B5EB51720A5 | item01 | | 0x018E5E04BA34732799E01BED0C1A06F9 | item03 | | 0x018E5E04BA34780F6A683BA37F00CA27 | item02 | +------------------------------------+--------+ 3 rows in set (0.0007 sec) MySQL > select bin_to_uuid(id) uuid, name from item; +--------------------------------------+--------+ | uuid | name | +--------------------------------------+--------+ | 018e5e04-ba33-76ae-d34a-5b5eb51720a5 | item01 | | 018e5e04-ba34-7327-99e0-1bed0c1a06f9 | item03 | | 018e5e04-ba34-780f-6a68-3ba37f00ca27 | item02 | +--------------------------------------+--------+ 3 rows in set (0.0008 sec)
Мы также можем получить время создания каждой записи:
MySQL > insert into item values (uuid_to_bin(js_uuidv7()),'item04'); Query OK, 1 row affected (0.0035 sec) MySQL > select js_uuidv7_to_datetime(bin_to_uuid(id)) insert_date, name from item; +-------------------------+--------+ | insert_date | name | +-------------------------+--------+ | 2024-03-20 22:39:11.923 | item01 | | 2024-03-20 22:39:11.924 | item03 | | 2024-03-20 22:39:11.924 | item02 | | 2024-03-20 22:41:54.567 | item04 | +-------------------------+--------+ 4 rows in set (0.0041 sec)
Для повышения производительности лучше хранить UUID с использованием uuid_to_bin() как BINARY(16). Конечно, если мы планируем использовать и вторичные индексы.
Но, возможно, вы предпочитаете напрямую видеть представление (значение) UUID при запросе таблицы.
Затем мы можем изменить нашу таблицу следующим образом:
MySQL > alter table item add column uuid char(36) generated always as (bin_to_uuid(id)) virtual after id, alter column id set invisible; MySQL > insert into item (id, name) values (uuid_to_bin(js_uuidv7()),'item05'); MySQL > select * from item; +--------------------------------------+--------+ | uuid | name | +--------------------------------------+--------+ | 018e5e04-ba33-76ae-d34a-5b5eb51720a5 | item01 | | 018e5e04-ba34-7327-99e0-1bed0c1a06f9 | item03 | | 018e5e04-ba34-780f-6a68-3ba37f00ca27 | item02 | | 018e5e07-3587-73af-6535-f805bee0cc04 | item04 | | 018e5e15-12bf-7590-a010-7a5b5457a6c3 | item05 | +--------------------------------------+--------+ 5 rows in set (0.0006 sec) MySQL > select *, js_uuidv7_to_datetime(uuid) inserted_at from item; +--------------------------------------+--------+-------------------------+ | uuid | name | inserted_at | +--------------------------------------+--------+-------------------------+ | 018e5e04-ba33-76ae-d34a-5b5eb51720a5 | item01 | 2024-03-20 22:39:11.923 | | 018e5e04-ba34-7327-99e0-1bed0c1a06f9 | item03 | 2024-03-20 22:39:11.924 | | 018e5e04-ba34-780f-6a68-3ba37f00ca27 | item02 | 2024-03-20 22:39:11.924 | | 018e5e07-3587-73af-6535-f805bee0cc04 | item04 | 2024-03-20 22:41:54.567 | | 018e5e15-12bf-7590-a010-7a5b5457a6c3 | item05 | 2024-03-20 22:57:03.167 | +--------------------------------------+--------+-------------------------+ 5 rows in set (0.0014 sec)
Заключение
Возможность писать программы на Javascript непосредственно в MySQL является приятным дополнением, особенно при запуске MySQL HeatWave в облаке, где невозможно установить дополнительные компоненты или плагины.
Для тех, кто владеет такими пользовательскими функциями (UDF), теперь вы можете переписать их в Javascript и использовать там, где MySQL поддерживает GraalVM: MySQL Enterprise и MySQL Heatwave.
Наслаждайтесь написанием функций Javascript в MySQL!