Лучший способ хранить следующие временные данные в БД - PullRequest
2 голосов
/ 17 мая 2011

Представьте, что у нас есть набор сущностей, каждое из которых имеет свое состояние: свободен, занят или разорван. Состояние указывается для дня, например, сегодня, 2011-05-17, объект E1 свободен, а завтра, 2011-05-18, занят.

Необходимо хранить ~ 10 ^ 5 сущностей в течение 1000 дней. Какой лучший способ сделать это?

Я думаю о 2 вариантах:

  • представляют каждый день в виде символов «0», «1» или «2» и сохраняют для каждой сущности строку из 1000 символов
  • хранить каждый день с состоянием объекта подряд, т.е. 1000 строк для объекта

Наиболее важный запрос для таких данных: данные начальной и конечной даты определяют, какие объекты являются свободными.

Производительность имеет более высокий приоритет, чем хранение.

Все предложения и комментарии приветствуются.

Ответы [ 6 ]

3 голосов
/ 17 мая 2011

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

10 ^ 8 строк - не такая уж большая проблема для вашей средней базы данных на обычном сервере.Поместите индекс на дату, и я бы поспорил, что диапазонные запросы («с заданной датой начала и датой окончания ...») будут работать нормально.

Причины, по которым я утверждаю, что это и проще, и гибчеидея сохранения строки из 1000 символов:

  • Вам придется обрабатывать это в коде, и этот код будет не так просто понять, как код, который запрашивает записи БД, содержащие датуи статус.
  • В зависимости от ядра базы данных, 1000 символьных строк могут быть BLOB-объектами, которые хранятся вне записи.Это делает их менее эффективными.
  • Что произойдет, если вам вдруг понадобится 2000 дней вместо 1000?Начать обновлять все строки и код, который их обрабатывает?Это гораздо больше работы, чем просто изменение вашего запроса.
  • Что происходит, когда вас в следующий раз просят сохранить некоторую дополнительную информацию для каждой ежедневной записи, или вам нужно изменить гранулярность (например, перейти от дней к часам)?
2 голосов
/ 18 мая 2011

Создайте одну таблицу для хранения ваших данных.Создайте таблицу с идентификатором, датой, именем объекта и восемью логическими полями.SQL Server 2008 дал мне приведенный ниже код для таблицы:

CREATE TABLE [dbo].[EntityAvailability](
[EA_Id] [int] IDENTITY(1,1) NOT NULL,
[EA_Date] [date] NOT NULL,
[EA_Entity] [nchar](10) NOT NULL,
[EA_IsAvailable] [bit] NOT NULL,
[EA_IsUnAvailable] [bit] NOT NULL,
[EA_IsBroken] [bit] NOT NULL,
[EA_IsLost] [bit] NOT NULL,
[EA_IsSpare1] [bit] NOT NULL,
[EA_IsSpare2] [bit] NOT NULL,
[EA_IsSpare3] [bit] NOT NULL,
[EA_IsActive] [bit] NOT NULL,
 CONSTRAINT [IX_EntityAvailability_Id] UNIQUE NONCLUSTERED 
(
    [EA_Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[EntityAvailability]') AND name = N'IXC_EntityAvailability_Date')
CREATE CLUSTERED INDEX [IXC_EntityAvailability_Date] ON [dbo].[EntityAvailability] 
(
    [EA_Date] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Кластерный индекс по дате будет работать лучше всего для поиска в диапазоне.Никогда не разрешайте поиск без диапазона дат, и не будет необходимости в каком-либо индексе, кроме кластерного индекса.Логические поля допускают восемь ситуаций, используя только один байт.Размер строки для этой таблицы составляет 35 байт.230 строк поместятся на странице.Вы заявили, что вам нужно хранить 10 ^ 5 сущностей в течение 1000 дней, что составляет 100 миллионов.Сто миллионов строк займут 434 782 8K страниц или около 3 гигабайт.

Установите таблицу на SSD и все готово.

1 голос
/ 17 мая 2011

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

Предполагая, что вы сохраняете даты, когда объект не является свободным, тогда поиск начинается с даты начала <= date и end_date> = date, и любое совпадение строки означает, что объект не является свободным для этого периода

0 голосов
/ 17 мая 2011

enter image description here

Чтобы получить бесплатные объекты на свидание, вы можете попробовать:

select
      e.EntityName
    , s.StateName
    , x.ValidFrom
from EntityState as x
join Entity      as e on e.EntityId = x.EntityId
join State       as s on s.StateID  = x.StateID
where StateName = 'free'
  and x.ValidFrom = ( select max(z.ValidFrom)
                      from EntityState as z
                      where z.EntityID   = x.EntityID
                        and z.ValidFrom <= your_date_here )
;

Примечание. Убедитесь, что в таблице EntityState хранятся только изменения состояния.

0 голосов
/ 17 мая 2011

Я бы широко использовал схему типа Kimball Star (структура типа http://en.wikipedia.org/wiki/Star_schema) с тремя таблицами (изначально)

  • FactEntity (FK kStatus, kDate)
  • DimStatus (PK kStatus))
  • DimDate (PK kDate)

Это может быть загружено довольно просто (сначала Dims затем следуют Fact (s)), а также очень просто запрашивается. Производительность может быть оптимизирована с помощью подходящегоиндексирование.

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

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

DimDate обычно обогащается добавлением DayNo, MonthNo, YearNo, DayOfWeek, WeekendFlag,WeekdayFlag, PublicHolidayFlag. Они позволяют выполнять некоторые очень интересные анализы.

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

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

0 голосов
/ 17 мая 2011

Похоже, вы на правильном пути, и я бы посоветовал из-за огромного количества записей и акцента на производительность, что вы сохраняете схему максимально денормализованной.Чем меньше соединений вам нужно сделать, чтобы определить свободные или занятые объекты, тем лучше.

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