MySql настраиваемый первичный ключ с автоматическим приращением [дубликат]

Использование базовой функции R aggregate:

aggregate(value ~ name, dat1, I)

# name           value.1  value.2  value.3  value.4
#1 firstName      0.4145  -0.4747   0.0659   -0.5024
#2 secondName    -0.8259   0.1669  -0.8962    0.1681
1
задан Mario 2 October 2011 в 00:25
поделиться

4 ответа

Механизм MyISAM MySQL может это сделать. См. Их руководство в разделе Использование AUTO_INCREMENT :

Для таблиц MyISAM вы можете указать AUTO_INCREMENT на вторичном столбце в индексе с несколькими столбцами. В этом случае генерируемое значение для столбца AUTO_INCREMENT вычисляется как MAX (auto_increment_column) + 1 WHERE prefix = given-prefix. Это полезно, когда вы хотите поместить данные в упорядоченные группы.

Документы продолжаются после этого параграфа, демонстрируя пример.

Механизм InnoDB в MySQL не поддерживайте эту функцию, что является неудачным, потому что лучше использовать InnoDB практически во всех случаях.

Вы не можете эмулировать это поведение с помощью триггеров (или любых операторов SQL, ограниченных областью транзакций) без блокировки таблиц в INSERT. Рассмотрим эту последовательность действий:

  1. Mario начинает транзакцию и вставляет новую строку для пользователя 4.
  2. Билл начинает транзакцию и вставляет новую строку для пользователя 4.
  3. Сеанс Марио запускает триггер для вычисления MAX (id) +1 для пользователя 4. Вы получаете 3.
  4. В сеансе Билла срабатывает триггер для вычисления MAX (id). Я получаю 3.
  5. Заседание Билла заканчивает его INSERT и совершает.
  6. Сеанс Марио пытается завершить свой INSERT, но теперь строка с (userid = 4, id = 3) существует, поэтому Марио получает конфликт с первичным ключом.

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

Решения для это либо:

  • Получите эксклюзивную блокировку таблицы. Перед тем, как попробовать INSERT, заблокируйте таблицу. Это необходимо, чтобы предотвратить одновременные ВСТАВКИ от создания условия гонки , как в приведенном выше примере. Необходимо заблокировать всю таблицу, так как вы пытаетесь ограничить INSERT, нет конкретной строки для блокировки (если вы пытаетесь управлять доступом к данной строке с помощью UPDATE, вы можете заблокировать только определенную строку). Но блокировка таблицы приводит к тому, что доступ к таблице становится последовательным, что ограничивает вашу пропускную способность.
  • Сделайте это за пределами транзакции. Создайте идентификационный номер таким образом, чтобы он не скрывался от двух параллельных транзакций. Кстати, это то, что делает AUTO_INCREMENT. Два параллельных сеанса будут получать уникальное значение id независимо от порядка выполнения или порядка фиксации. Но отслеживание последнего сгенерированного идентификатора для каждого пользователя требует доступа к базе данных или дублированного хранилища данных. Например, ключ memcached для каждого пользователя, который может быть инкрементирован атомарно .

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

  • Что произойдет, если вы вСТАВИТЕСЬ в транзакции, а затем откат? Вы указали значение 3 в этой транзакции, а затем я выделил значение 4, поэтому, если вы откат и я зафиксирую, теперь есть пробел.
  • Что произойдет, если INSERT завершится с ошибкой из-за других ограничений на таблица (например, другой столбец NOT NULL)? Вы также можете получить пробелы.
  • Если вы когда-либо удаляете строку, вам нужно перенумеровать все следующие строки для одного и того же идентификатора пользователя? Что это делает для ваших записей memcached, если вы используете это решение?
3
ответ дан Bill Karwin 22 August 2018 в 23:03
поделиться

SQL Server должен позволить вам сделать это. Если вы не можете реализовать это с помощью вычисленного столбца (возможно, нет - существуют некоторые ограничения), вы можете реализовать его в триггере .

MySQL также позволит вам реализовать это через триггеры.

0
ответ дан Icarus 22 August 2018 в 23:03
поделиться

В комментарии вы задаете вопрос об эффективности. Если вы не имеете дело с экстремальными объемами, сохранение 8-байтного DATETIME не является значительным накладным расходами по сравнению с использованием, например, 4-байтового INT.

Он также значительно упрощает ваши вставки данных, а также (g10)

Если вам это нужно, будьте осторожны с именами полей. Если в таблице есть uid и id, я ожидаю, что id будет уникальным в этой таблице, а uid - другим. Вместо этого используйте имена полей property_id и amendment_id.

В терминах реализации есть, как правило, два варианта.

1) , Триггер

Реализации различаются, но логика остается неизменной. Поскольку вы не указываете RDBMS (кроме NOT MS / Oracle), общая логика проста ...

  • Запустить транзакцию (часто это неявно уже запущено внутри триггеров)
  • Найти MAX(amendment_id) для вставки свойства_id
  • Обновить вновь вставленное значение с помощью MAX(amendment_id) + 1
  • Зафиксировать транзакцию

Вещи, которые нужно знать, - это ... - вставляются одновременно несколько записей - вставляются записи с уже заполненным изменением_id - обновляются изменения существующих записей

2). Сохраненная процедура

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

  • Неявно, вы знаете, что имеете дело только с один запись.
  • Вы просто не предоставляете параметр для полей DEFAULT.
  • Вы знаете, какие обновления / удаления могут и не могут произойти.
  • Вы можете реализовать всю необходимую бизнес-логику без скрытых триггеров

Я лично рекомендую маршрут хранимой процедуры, но триггеры работают.

0
ответ дан MatBailie 22 August 2018 в 23:03
поделиться

Важно, чтобы ваши типы данных были правильными.

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

Если запись идентифицирована (entity_id,version_number), тогда обнимайте это описание и используйте его напрямую, вместо того, чтобы изменять значение ваших ключей. Вам придется писать запросы, которые ограничивают номер версии, но это нормально. Базы данных хороши в этом.

version_number может быть временной меткой, как предлагает a_horse_with_no_name. Это неплохая идея. Не существует значимого недостатка производительности для использования временных меток вместо простых целых чисел. Вы получаете значение , что более важно.

Вы могли бы поддерживать таблицу «последней версии», которая содержит для каждого entity_id только запись с самым большим количеством файлов, недавний version_number. Это будет больше для вас, так что сделайте это, только если вам действительно нужна производительность.

0
ответ дан spraff 22 August 2018 в 23:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: