С помощью триггеров SQL вы можете делать все, что вам нужно. Следующий SQL добавляет триггер на tablename.table_id
для автоматического создания UUID первичного ключа при вставке, а затем сохраняет вновь созданный идентификатор в переменную SQL для последующего извлечения:
CREATE TRIGGER `tablename_newid`
AFTER INSERT ON `tablename`
FOR EACH ROW
BEGIN
IF ASCII(NEW.table_id) = 0 THEN
SET NEW.table_id = UNHEX(REPLACE(UUID(),'-',''));
END IF;
SET @last_uuid = NEW.table_id;
END
В качестве бонуса он вставляет UUID в двоичном виде в двоичное поле (16), чтобы сэкономить место на диске и значительно увеличить скорость запроса.
edit: триггер должен проверить существующее значение столбца перед вставкой собственного UUID, чтобы имитировать возможность предоставления значений для первичных ключей таблицы в MySQL - без этого любые передаваемые значения всегда будут переопределены триггер. Пример был обновлен для использования ASCII() = 0
для проверки существования значения первичного ключа в INSERT, который будет обнаруживать пустые строковые значения для двоичного поля.
edit 2: после комментария здесь с тех пор мне было указано, что использование BEFORE INSERT
приводит к установке переменной @last_uuid
, даже если вставка строки завершается неудачно. Я обновил свой ответ, чтобы использовать AFTER INSERT
- хотя я чувствую, что это совершенно хороший подход в общих обстоятельствах, у него могут быть проблемы с репликацией строк в кластеризованных или реплицируемых базах данных. Если кто-нибудь знает, я бы тоже с удовольствием!
Чтобы прочитать ID вставки новой строки обратно, просто запустите SELECT @last_uuid
.
При запросе и чтении таких двоичных значений функции MySQL HEX()
и UNHEX()
будут очень полезны, так же как и запись значений вашего запроса в шестнадцатеричном формате (с предшествующим 0x
). Код стороны php для вашего исходного ответа, учитывая этот тип триггера, примененного к table1, будет:
// insert row
$sql = "INSERT INTO table1(text) VALUES ('some text')";
mysql_query($sql);
// get last inserted UUID
$sql = "SELECT HEX(@last_uuid)";
$result = mysql_query($sql);
$row = mysql_fetch_row($result);
$id = $row[0];
// perform a query using said ID
mysql_query("SELECT FROM table1 WHERE id = 0x" . $id);
В ответ на комментарий @ ina :
UUID не является строкой, даже если MySQL решит представить его как таковой. Это двоичные данные в необработанном виде, и эти черточки являются просто дружественным способом представления их MySQL.
Наиболее эффективное хранилище для UUID - создать его как UNHEX(REPLACE(UUID(),'-',''))
- это удалит это форматирование и преобразует его обратно в двоичные данные. Эти функции сделают оригинальную вставку медленнее, но все последующие сравнения, которые вы выполняете для этого ключа или столбца, будут намного быстрее для 16-байтового двоичного поля, чем для 36-символьной строки.
Во-первых, символьные данные требуют анализа и локализации. Любые строки, поступающие в механизм запросов, как правило, автоматически сопоставляются с набором символов базы данных, а некоторые API (вспоминается wordpress) даже запускают CONVERT()
для всех строковых данных перед запросом. Двоичные данные не имеют этих накладных расходов. С другой стороны, ваш char(36)
фактически выделяет 36 символов , что означает (если ваша база данных UTF-8), каждый символ может быть длиной до 3 или 4 байта в зависимости от версия MySQL, которую вы используете. Таким образом, char(36)
может варьироваться от 36 байтов (если он полностью состоит из символов низкого ASCII) до 144, если он полностью состоит из символов UTF8 высокого порядка. Это на намного больше, чем 16 байтов, которые мы выделили для нашего двоичного поля.
Любую логику, выполняемую с этими данными, можно выполнить с помощью UNHEX()
, но лучше это сделать, просто экранируя данные в запросах в шестнадцатеричном виде с префиксом 0x
. Это так же быстро, как чтение строки, на лету преобразуется в двоичный файл и напрямую назначается запросу или ячейке. Очень быстро.
Считывание данных происходит немного медленнее - вам нужно вызвать HEX()
для всех двоичных данных, считанных из запроса, чтобы получить их в полезном формате, если ваш клиентский API плохо справляется с двоичными данными (PHP, в частности, обычно определяет, что двоичные строки === null
и прервут их, если ими манипулировать без предварительного вызова bin2hex()
, base64_encode()
или подобного) - но эти издержки примерно такие же минимальные, как сопоставление символов, и, что более важно, вызываются только в фактические ячейки не все ячейки участвуют во внутренних вычислениях результата запроса.
Так что, конечно, все эти небольшие увеличения скорости очень минимальны, а другие области приводят к небольшому уменьшению - но когда вы добавляете их все, binary
все равно выходит на первое место, и когда вы рассматриваете варианты использования и общие чтения> пишет, что принцип действительно сияет.
... и поэтому binary(16)
лучше, чем char(36)
.