Хорошо, я добавлю это, потому что оно того стоит.
Мне нужно уладить довольно много дел.
- Быстрый / производительный запрос
- Любые приращения времени, 21:01, 12:14 и т. д.
- Международный (?) - не уверен, что это проблема даже с часовыми поясами, по крайней мере, в моем случае, но кто-то более сведущий здесь, не стесняйтесь вмешиваться
- Открыто — Закрытие до следующего дня (открытие в полдень, закрытие в 2:00)
- Несколько промежутков времени / день
- Возможность переопределить определенные дни (праздники, что угодно)
- Возможность повторяющихся переопределений
- Возможность запрашивать любой момент времени и открывать бизнес (сейчас, будущее время, прошлое время)
- Возможность легко исключить результаты закрытия предприятий в ближайшее время (отфильтруйте предприятия, закрывающиеся через 30 минут, вы не хотите, чтобы ваши пользователи были «тем парнем, который появляется за 5 минут до закрытия в индустрии продуктов питания / напитков»).
Мне нравятся многие из представленных подходов, и я заимствую некоторые из них. На моем веб-сайте, в проекте, во всем, что мне нужно принять во внимание, у меня могут быть миллионы предприятий, и некоторые из подходов здесь, похоже, не очень хорошо масштабируются лично для меня.
Вот что я предлагаю для алгоритма и структуры.
Мы должны сделать некоторые конкретные предположения по всему миру, в любом месте и в любое время: в неделе 7 дней. В сутках 1440 минут. Существует конечное число возможных комбинаций минут открытия/закрытия.
Не конкретные, но достойные предположения: многие перестановки открытых/закрытых минут будут распределяться между предприятиями, уменьшая общее количество фактически хранимых перестановок. Было время в моей жизни, когда я мог легко рассчитать фактические возможные комбинации этого подхода, но если кто-то может помочь / думает, что это будет полезно, это было бы здорово.
Я предлагаю 3 таблицы: Прежде чем вы перестанете читать, учтите, что в реальном мире 2 из этих таблиц будут достаточно аккуратно кэшированы. Этот подход подойдет не всем из-за огромной сложности кода, необходимого для интерпретации пользовательского интерфейса в модели данных и обратно, если это необходимо. Ваш пробег и потребности могут отличаться. Это попытка разумного решения на уровне предприятия, что бы это ни значило.
Таблица часов работы
ID | ОТКРЫТО (минуты дня) | ЗАКРЫТЬ (минуты дня)
1 | 360 | 1020 (пример: с 9:00 до 17:00)
2 | 365 | 1021 (пример: пограничный регистр 9:05 - 17:01 (чудаки))
и т.п.
HoursOfOperations не волнует, какие дни, просто открытые и закрытые и уникальность. На комбинацию открытия/закрытия может быть только один вход. Теперь, в зависимости от вашей среды, либо вся эта таблица может быть кэширована, либо она может кэшироваться для текущего часа дня и т. д. В любом случае вам не нужно запрашивать эту таблицу для каждой операции. В зависимости от вашего решения для хранения я предполагаю, что каждый столбец в этой таблице проиндексирован для повышения производительности. С течением времени эта таблица, вероятно, имеет экспоненциально обратную вероятность INSERT(ов). Однако на самом деле работа с этой таблицей должна быть в основном внутрипроцессной операцией (ОЗУ).
Business2HoursКарта
Примечание. В моем примере я сохраняю «День» в виде поля/столбца с битовым флагом. Во многом это связано с моими потребностями и продвижением перечислений LINQ/Flags в C#. Ничто не мешает вам расширить это до 7-битных полей. Оба подхода должны быть относительно похожи как в логике хранения, так и в подходе к запросам.
Еще одно примечание: я не вступаю в семантический аргумент о том, что «каждой таблице нужен столбец идентификатора PK», пожалуйста, найдите для этого другой форум.
Идентификатор бизнеса | Идентификатор часов | День (или, если хотите, разделить на: BIT Monday, BIT вторник, ...)
1 | 1 | 1111111 (этот бизнес работает с 9 до 5 каждый день недели)
2 | 2 | 1111110 (эта компания открыта с 9:05 до 5:01 Пн-Сб (понедельник = день 1)
Причина, по которой это легко запросить, заключается в том, что мы всегда можем довольно легко определить MOTD (минуту дня), которая нам нужна. Если я хочу знать, что открыто завтра в 17:00, я беру все идентификаторы HoursOfOperations WHERE Close >= 1020. Если я не ищу временной диапазон, Open становится незначительным. Если вы не хотите показывать, что предприятия закрываются в ближайшие полчаса, просто соответствующим образом измените время прибытия (ищите 17:30 (10:50), а не 17:00 (10:20). Второй запрос, естественно, будет ' дайте мне все дела с HoursID IN (1, 2, 3, 4, 5) и т. д. Это, вероятно, должно поднять красный флаг, поскольку у этого подхода есть ограничения.Однако, если кто-то может ответить на фактический вопрос о перестановках выше, мы можем быть в состоянии опустить красный флаг.Учтите, что нам нужны только возможные перестановки на любой стороне уравнения одновременно, либо открытые, либо закрытые.
Учитывая, что у нас есть наша первая таблица в кэше, это быстрая операция. Вторая операция запрашивает эту потенциально большую таблицу строк, но мы ищем очень маленькие (SMALLINT) столбцы, которые, как мы надеемся, проиндексированы.
Теперь вы можете видеть сложность кода. В моем конкретном проекте я ориентируюсь в основном на бары, поэтому можно с уверенностью предположить, что у меня будет значительное количество предприятий с такими часами, как «11:00 - 2:00 (следующего дня)». Это действительно будет 2 записи как в таблице HoursOfOperations, так и в таблице Business2HoursMap. Например. бар, который открыт с 11:00 до 2:00, будет иметь 2 ссылки на таблицу HoursOfOperations 660–1440 (11:00–полночь) и 0–120 (полночь–2:00). Эти ссылки будут отражены в фактических днях в таблице Business2HoursMap как 2 записи в нашем упрощенном случае, 1 запись = ссылка на все дни № 1, еще одна ссылка на все дни № 2. Надеюсь, это имеет смысл, это был долгий день.
Переопределение в особые дни/праздники/что угодно. Переопределения по своей природе основаны на дате, а не на дне недели. Я думаю, что именно здесь некоторые из подходов пытаются засунуть пресловутый круглый колышек в квадратное отверстие. Нам нужен еще один стол.
Идентификатор часов | Идентификатор бизнеса | день | Месяц | Год
1 | 2 | 1 | 1 | НУЛЕВОЙ
Это, безусловно, может стать более сложным, если вам нужно что-то вроде «каждый второй вторник эта компания ходит на рыбалку на 4 часа». Однако то, что это позволит нам сделать довольно легко, это разрешить 1 - переопределения, 2 - разумные повторяющиеся переопределения. НАПРИМЕР. если год равен NULL, то каждый год в день Нового года этот странный бар открыт с 9:00 до 17:00, что соответствует приведенным выше примерам данных. т.е. - Если указан год, то это только для 2013 года. Если месяц равен нулю, это каждый первый день месяца. Опять же, это не будет обрабатывать каждый сценарий планирования только по столбцам NULL, но теоретически вы можете справиться практически с чем угодно, полагаясь при необходимости на длинную последовательность абсолютных дат.
Опять же, я бы кэшировал эту таблицу по скользящему дню. Я просто не могу реально представить, что строки для этой таблицы в моментальном снимке за один день будут очень большими, по крайней мере, для моих нужд. Я бы сначала проверил эту таблицу, так как она переопределена, и сохранил бы запрос к гораздо большей таблице Business2HoursMap на стороне хранилища.
Интересная проблема. Я действительно удивлен, что это первый раз, когда мне действительно нужно все обдумать. Как всегда, очень заинтересован в различных взглядах, подходах или недостатках в моем подходе.
person
Dave Jellison
schedule
19.11.2013