ОК, я добавлю это, чтобы оно того стоило.
Мне нужно разобраться с несколькими вещами.
- Fast / Performant Query
- Любые приращения времени, 21:01, 12:14 и т. Д.
- Международный (?) - не уверен, что это проблема даже с часовыми поясами, по крайней мере, в моем случае, но кто-то более опытный здесь, не стесняйтесь звонить в
- Открыть - Закрыть на следующий день (открыть в полдень, закрыть в 2:00)
- Несколько раз в день
- Возможность переопределять определенные дни (праздники, что угодно)
- Возможность повторения переопределений
- Возможность запроса в любой момент времени и открытия бизнеса (сейчас, в будущем, в прошлом)
- Возможность легко исключать результаты закрытия предприятий в ближайшее время (фильтровать предприятия, закрывающиеся за 30 минут, вы не хотите, чтобы ваши пользователи были тем парнем, который появляется за 5 минут до закрытия в индустрии продуктов питания и напитков)
Мне нравится множество представленных подходов, и я заимствую у некоторых из них. На моем веб-сайте, проекте, что бы мне ни пришлось принять во внимание, у меня могут быть миллионы компаний, и некоторые из подходов, которые мне здесь представляются, не подходят мне лично.
Вот что я предлагаю для алгоритма и структуры.
Мы должны сделать некоторые конкретные предположения по всему миру, в любом месте, в любое время:
В неделе 7 дней.
В один день 1440 минут.
Существует конечное число перестановок минут открытия / закрытия, которые возможны.
Не конкретные, а достойные предположения:
Многие перестановки открытых / закрытых минут будут распределены между предприятиями, уменьшая общее количество перестановок, фактически сохраненных
В моей жизни было время, когда я мог легко рассчитать фактические возможные комбинации для этого подхода, но если кто-то сможет помочь / посчитает, что это будет полезно, это было бы здорово.
Предлагаю 3 таблицы:
Прежде чем вы перестанете читать, рассмотрим в реальном мире 2 из этих таблиц, достаточно ли кэш будет достаточно маленьким. Этот подход не будет для всех также из-за большой сложности кода, необходимого для интерпретации пользовательского интерфейса к модели данных и обратно, если это необходимо. Ваш пробег и потребности могут отличаться. Это попытка найти разумное решение на уровне предприятия, что бы это ни значило.
Таблица HoursOfOperations
ID | OPEN (минута дня) | ЗАКРЫТЬ (минута дня)
1 | 360 | 1020 (пример: 9:00 - 17:00)
2 | 365 | 1021 (пример: крайний случай 9:05 AM - 5:01 PM (weirdos))
и т.д.
HoursOfOperations не заботится о том, какие дни, просто открываются и закрываются и уникальны. Для каждой комбинации открытия / закрытия может быть только одна запись. Теперь, в зависимости от вашей среды, вся эта таблица может быть кэширована или кэширована для текущего часа дня и т. Д. В любом случае вам не нужно запрашивать эту таблицу для каждой операции. В зависимости от вашего решения для хранения, я предполагаю, что каждый столбец в этой таблице будет проиндексирован для повышения производительности. С течением времени эта таблица, вероятно, имеет экспоненциально обратную вероятность INSERT (s). Однако на самом деле работа с этой таблицей в основном должна быть оперативной операцией (ОЗУ).
Business2HoursMap
Примечание: в моем примере я храню «День» как поле / столбец битового флага. Во многом это связано с моими потребностями и развитием перечислений LINQ / Flags в C #. Ничто не мешает вам расширить это до 7 битных полей. Оба подхода должны быть относительно похожими как в логике хранения, так и в подходе к запросу.
Еще одно примечание: я не вхожу в аргумент семантики "каждой таблице нужен столбец идентификатора PK", пожалуйста, найдите другой форум для этого.
BusinessID | HoursID | День (или, если вы предпочитаете, разделить на: BIT понедельник, BIT вторник, ...)
1 | 1 | 1111111 (этот бизнес открыт 9-5 каждый день недели)
2 | 2 | 1111110 (этот бизнес открыт 9:05 - 5:01 М-СБ (понедельник = день 1)
Причина, по которой это легко запросить, состоит в том, что мы всегда можем довольно легко определить MOTD (Минута дня), к которому мы стремимся. Если я хочу узнать, что завтра открывается в 17:00, я беру все идентификаторы HoursOfOperations, ГДЕ Close> = 1020. Если я не ищу временной диапазон, Open становится незначительным. Если вы не хотите, чтобы предприятия закрывались в следующие полчаса, просто измените время прихода (ищите 17:30 (1050), а не 17:00 (1020).
Второй запрос, естественно, будет «дать мне все дело с HoursID IN (1, 2, 3, 4, 5) и т. Д. Это, вероятно, должно поднять красный флаг, поскольку существуют ограничения для этого подхода. Тем не менее, если кто-то может ответить на реальный вопрос о перестановках, приведенный выше, мы можем убрать красный флаг. Представьте, что нам нужны только возможные перестановки на любой стороне уравнения одновременно, открытая или закрытая.
Учитывая, что наша первая таблица кэширована, это быстрая операция. Вторая операция - запрос этой потенциально большой строки таблицы, но мы ищем очень маленькие (SMALLINT), мы надеемся, проиндексированные столбцы.
Теперь вы можете видеть сложность кода. Я нацеливаюсь в основном на бары в моем конкретном проекте, поэтому будет весьма безопасно предположить, что у меня будет значительное количество предприятий с часами, такими как «11:00 AM - 2:00 AM (следующий день)». В действительности это будет 2 записи как в таблицу HoursOfOperations, так и в таблицу Business2HoursMap. Например. бар, открытый с 11:00 до 2:00, будет иметь две ссылки на таблицу HoursOfOperations 660 - 1440 (11:00 - полночь) и 0 - 120 (полночь - 2:00). Эти ссылки будут отражены в фактических днях в таблице Business2HoursMap в виде 2 записей в нашем упрощенном случае: 1 запись = ссылка на все дни # 1, другая ссылка на все дни # 2. Надеюсь, это имеет смысл, это был долгий день.
Переопределение в особые дни / праздники / что угодно.
Переопределения по своей природе основаны на дате, а не на дне недели. Я думаю, что именно здесь некоторые подходы пытаются засунуть пресловутый круглый колышек в квадратное отверстие. Нам нужен еще один стол.
HoursID | BusinessID | День | Месяц | Год
1 | 2 | 1 | 1 | NULL
Это, безусловно, может стать более сложным, если вам нужно что-то вроде "каждый второй вторник, эта компания ловит рыбу в течение 4 часов". Однако то, что это позволит нам сделать довольно легко, это разрешить 1 - переопределения, 2 - разумные повторяющиеся переопределения. НАПРИМЕР. Если год равен NULL, то каждый год в новогодний день этот чудной бар открыт с 9:00 до 17:00, что соответствует приведенным выше примерам данных. То есть - Если год был установлен, это только на 2013 год. Если месяц равен нулю, это каждый первый день месяца. Опять же, это не будет обрабатывать каждый сценарий планирования только по столбцам NULL, но теоретически вы можете обрабатывать практически все, полагаясь на длинную последовательность абсолютных дат.
Опять же, я бы кэшировал эту таблицу на скользящей основе. Я просто не могу реально увидеть строки для этой таблицы в однодневном снимке очень большого размера, по крайней мере, для моих нужд. Я бы сначала проверил эту таблицу, так как она корректна, переопределил бы и сохранил бы запрос к намного большей таблице Business2HoursMap на стороне хранилища.
Интересная проблема. Я действительно удивлен, что это первый раз, когда мне действительно нужно обдумать это. Как всегда, я очень заинтересован в различном понимании, подходах или недостатках моего подхода.