Как сохранить статусы записи (такие как ожидающий, завершенный, черновой, отмененный ...)

18

Довольно много приложений требуют, чтобы записи в их таблицах имели статус, такой как «завершено», «черновик», «отменено». Каков наилучший способ хранения этих статусов? Чтобы проиллюстрировать то, к чему я клоню, приведу очень короткий пример.

У меня есть простое приложение для блога, и у каждого сообщения есть статус: опубликовано, черновик или ожидает рассмотрения.

На мой взгляд, есть два способа смоделировать это в базе данных.

  1. Таблица «Post» имеет текстовое поле, которое включает текст статуса.
  2. Таблица Post имеет поле состояния, которое содержит идентификатор записи в таблице PostStatus.

Пример блога здесь очень простой. Где может быть достаточно enum (если поддерживается). Однако я бы хотел, чтобы в ответах на этот вопрос учитывалось, что список статусов может измениться в любое время, чтобы можно было добавлять или удалять больше.

Кто-нибудь может объяснить преимущества / недостатки каждого?

Ура!

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

veganista
источник
1
Также см dba.stackexchange.com/q/11631/630
ГБН
Что вы подразумеваете под «в любое время»? Означает ли это как часть пользовательской активности или как часть цикла выпуска программного обеспечения?
Кевин Клайн
Оба, в каких случаях лучше использовать любой из упомянутых здесь подходов. Так что, если пользователи могут добавлять новые статусы, или если новые добавляются на более позднем этапе проекта
veganista
Хранение текста в базе данных может быть хорошей денормализацией. Я думаю, что это может зависеть от точных деталей, например. Как часто ваша организация меняет свои процессы (что приводит к возможным изменениям статуса)?
Джейди
Если пользователи могут добавлять новые статусы, то это совсем другое дело. Вы, вероятно, захотите записать создаваемого пользователя и т. Д. Со статусом, и вам определенно понадобится другая таблица.
Кевин Клайн

Ответы:

14

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

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

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

Кевин Клайн
источник
1
+1, Запрещая определенную потребность держать список статусов в БД, это , как правило , самый простой, наименее сложный способ сделать это.
GrandmasterB
2
Это нормально, если только вы не начнете менять архитектуру статуса или сохранять даты мутаций
LastTribunal
10

Хранение текста статуса - это не очень хорошая идея, так как кто-то может решить, что вместо этого «завершить» следует называть «завершенным», а затем вам придется обновить базу данных, просмотреть программу, если кто-то жестко закодировал текст и т. Д.

Во многих программах я видел либо числовой код (1 = новый, 2 = черновик, 3 = при проверке, 4 = полный, 99 = отмененный) или короткий буквенно-цифровой код («NEW», «DRA», «INV»). "," COM "," CAN "). Последнее делает код (в программе или в базе данных) более читабельным, что, как правило, хорошо. С другой стороны, числовые коды облегчают, например, сравнение "больше чем" или "меньше чем"

select * from myrecords where status < Status.Complete;
user281377
источник
Какой-то идиот тоже может хардкорно идентифицировать.
дебилы
Еще одним преимуществом идентификаторов является необходимость обеспечения локализации. Вы можете использовать свой идентификатор для поиска строки ресурса и отображения. С жестко закодированными строками это невозможно
armitage
3
Я не думаю, что создание состояний с использованием сравнений «больше чем» или «меньше чем», как вы показали, является хорошей идеей. Он может работать для более простых приложений, таких как этот пример, но не подходит для более сложных приложений (хотя я уверен, что вы знаете об этом)
veganista
1
@armitage: вполне возможно сделать поиск, используя строки. Имена ресурсов представляют собой строки:status.draft=Draught
Кевин Клайн
Веганиста: Конечно, могут быть трудности с большим или меньшим сравнением, но я видел большие, сложные системы, которые делают это и живут.
user281377
4

Три правила реляционных баз данных:

  1. Нормализовать
  2. Нормализовать
  3. Нормализовать

Так что ваш вопрос отвечает сам. Сохраняйте статус внутри своей таблицы и используйте GUID / UUID в качестве идентификатора . Индексированные GUID очень быстрые и устраняют проблемы, свойственные увеличивающимся числам. С помощью идентификатора вы можете делать классные вещи, например, запрашивать в БД все завершенные записи с использованием идентификатора, а поскольку вы работаете в рамках реляционной парадигмы БД, это очень быстро. Если у вас есть только поле, БД должна циклически проходить по каждой строке и сравнивать текст, возможно, с помощью манипулирования, и это очень медленно.

Названия статусов постов могут меняться, больше информации о статусе постов можно найти в таблице, все просто работает, если вы нормализуете .

Например, вы можете добавить уровни статуса в качестве дополнительной информации, что позволит для сравнения упоминает ammoQ. Но они не зависят от ключа для позиционирования, позволяя переупорядочивать уровень статуса без ущерба для целостности БД. Вы также можете вставить дополнительные уровни, что довольно сложно, если у вас есть уровень, связанный с автоинкрементным ключом.

Спенсер Рэтбун
источник
Причины, которые вы указали здесь, - это как раз те причины, по которым я использовал другую таблицу для хранения моих статусов. Основная причина, по которой я задал этот вопрос, состоит в том, чтобы увидеть, хорошо ли иногда использовать более простое текстовое поле.
Веганиста
@Liam Только если он нормализуется до текстового поля. То есть, если ваше текстовое поле зависит только от первичного ключа, и вы ищете вещи на основе первичного ключа , с появлением текстового поля. Реляционная БД - это отношения, у вас они есть, поэтому их нужно определить. Одно из немногих исключений - если вы обрабатываете грязные данные из внешнего источника, и у вас нет времени полностью их моделировать. Избегайте этого, если это возможно.
Спенсер Рэтбун
прячет глаза, оплакивая GUID, которые никогда не вернутся
sq33G
Вы должны были написать «три теории реляционных баз данных». Теория не всегда практична. Часто более эффективно хранить код состояния непосредственно в записи, с которой он связан. Если вам не нужно искать его, чтобы использовать его, удаление соединения с другой таблицей экономит много времени на обработку.
Suncat2000
Проголосовал из-за неверной информации о типах столбцов и полной таблицы сканирования.
igorrs
3

Да, вы должны пойти с вариантом 2, имея таблицу PostStatus.

Помимо всех преимуществ, упомянутых в других ответах.

Помня о том, что статусы нужно добавлять или удалять, вы можете иметь столбец «включено» в таблице PostStatus, поэтому, если статус будет удален, пометьте столбец «включен» как «N», таким образом вы сможете добавить или удалить статусы, а также существующие записи останутся без проблем.

Мистер Спарк
источник
1

Я хотел бы добавить к иначе проницательным ответам, что для полной нормализации изменение статуса сущности фактически моделируется в отдельной сущности, например с именем statusChange.

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

Dibbeke
источник
0

Использование текста для статуса в таблице записей, вероятно, не будет хорошей идеей, поскольку это может измениться, и будет трудно выполнить какие-либо проверки целостности данных при вставке / обновлении. Если вы используете СУБД с типом данных enum, вы можете использовать это вместо этого (производительность, вероятно, не пострадает ... в зависимости).

Если вашему статусу нужны какие-либо метаданные (описание, созданное, понятное имя, ...), вам нужно будет хранить статусы в отдельной таблице и иметь ключ статуса в своей таблице записей (убедитесь, что вы используете внешний ключ). Идентификатор не обязательно должен быть числом, просто PK таблицы состояния. Кроме того, если статусы находятся в их собственной таблице, вы можете поделиться ими между типами записей (таблицами), если это применимо. Я не буду беспокоиться о проблемах производительности при присоединении к таблице состояния.

Что бы вы ни делали, убедитесь, что вы избегаете магических статусов (1 для активного, 2 для удаленного, ...). Это опирается на документацию и традиции, которые всегда имеют тенденцию затеряться на достаточно большом сроке. Если вы вообще используете числовые идентификаторы, убедитесь, что в вашей базе данных есть текстовая ассоциация.

smp7d
источник
Если вы не беспокоитесь о производительности, вы, вероятно, жертвуете масштабируемостью. Компьютеры не могут избежать магических состояний: 0 и 1 по сути магические.
Suncat2000
0

Зависит от цели проектирования базы данных.

Если вы проектируете базу данных просто для поддержки приложения (то есть объекты (код) являются главными для всех), то использование перечисления (или перечисления psuedo для классов, которые их не поддерживают) и сохранение имени перечисления является хорошая идея, потому что вы по-прежнему управляете значениями, разрешенными через перечисление, и вы также немного облегчаете чтение таблицы, когда вынуждены просматривать необработанные данные (что не так часто, если код фактически управляет всеми). Но если перечисление помечено. Затем я обычно сохраняю значение enum (целое число).

ElGringoGrande
источник
-1

Статус очень важен, каждый раз, когда вы получаете информацию о сообщении, вам нужно получить его статус, или вы захотите фильтровать сообщения по статусу. Если у вас есть статус в другой таблице, вам нужно будет объединиться, чтобы получить эту информацию, и поэтому производительность снижается. Определенно вы должны иметь статус в той же таблице. И поместите индекс на это! Вы все еще можете использовать целые числа в качестве статуса или, может быть, поле enum.

dxvargas
источник
-2

Правильное решение - использовать хранилище событий / источник с CQRS или блокчейн. Проблема с захватом событий в RDB заключается в том, что RDB хранит моментальный снимок одного события во времени, а такие вещи, как «Состояния / Состояния», представляют собой последовательность мутаций, которые развиваются с течением времени.

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