Разбивать или не разбивать?

8

Уже прочитав несколько вопросов о SO, внешних постах в блоге и руководстве

Я все еще задаюсь вопросом, должен ли я пойти с разделением, рассматривая мой случай или нет.

Корпус - упрощенный

Хранение данных клиентов. Все названия таблиц, упомянутых ниже, составлены для ясности.

  1. Наличие объектов, которые могут быть идентифицированы клиентом и являются нефизическими существами, а также их физические объекты, в которых они фактически хранятся в случае необходимости отправить некоторые объекты обратно клиенту по требованию или обработать его другими способами. Они отображаются в отношениях «многие ко многим». objects_nonphysical, objects_physical, objects_mapping_table.

  2. Второе отношение «многие ко многим» заключается между этими нефизическими объектами и их метриками. Есть объекты, которые связаны с некоторыми метриками. metrics,metrics_objects_nonphysical

  3. Как нефизические, так и физические объекты имеют свои иерархические таблицы, которые являются дочерними и родительскими отношениями. objects_nonphysical_hierarchy,objects_physical_hierarchy

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

  • Поддерживайте внутреннюю систему для постов INSERTи SELECTвыписок, потому что именно здесь будет происходить отображение.

  • Поддерживать систему для внешнего клиента, чтобы просматривать и управлять своими нефизическими объектами - быстрый поиск данных. Сильная потребность в эффективности SELECTвыписок - эти данные доступны для поиска большинству клиентов в любое время.

Мое рассмотрение

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

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

Объем данных

Мои данные будут постоянно расти, особенно при импорте объектов и метрик новых клиентов. Темпы поступления новых данных в систему в настоящий момент непредсказуемы в долгосрочной перспективе. Нет никакого способа измерить это, не зная, кто будет следующим клиентом. В настоящее время есть только 2 клиента с более или менее строками для каждого клиента в каждой таблице. Но в будущем я ожидаю, что новые клиенты также будут иметь объем порядка 10 миллионов строк.

Вопросов

Все эти вопросы связаны друг с другом.

  1. Должно ли разделение действительно рассматриваться здесь, или это перебор? Я считаю, что это полезно, так как я всегда сканирую ровно один раздел.
  2. Если разделение - это путь, как мне FKнаиболее эффективно применять ограничения с учетом моих потребностей? Должен ли я пойти constraint triggersили просто оставить его на уровне приложений для внутренней системы, или, может быть, какой-то другой метод?
  3. Если разделение не путь, во что я должен погрузиться?

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

Камил Госциминский
источник
3
В общем, рекомендуется начинать производство без каких-либо издержек на индексы, разделы и т. Д., Затем, если необходимо, добавить индексы и разделы и т. Д.
alonk
1
С разделением вы получите ускорение только для определенных типов запросов, а также для других типов запросов. Вы также получите удар по записи. Разделение не должно быть первым, что вы достигнете, и я думаю, что вы будете в порядке, используя простые индексы в обозримом будущем, и пересечь эти мосты, когда вы доберетесь до них. 5M строк не так уж и велики. Это может быть полезный блог со сравнениями скорости: if-not-true-then-false.com/2009/…
dizzystar
2
Я согласен с dizzystar, я бы не стал беспокоиться прямо сейчас. Пересеките этот мост, если доберетесь до него. В настоящее время разбиение в Postgres также затрудняет (если не делает невозможным) использование надлежащих внешних ключей (это может измениться в 9.7, но пока ничего не решено). Даже таблица с 50M строками не обязательно является кандидатом на разбиение. Если вы в основном имеют условия равенства в запросах , которые уменьшают количество строк , по существу, хорошая индексация вы можете получить длинный путь.
a_horse_with_no_name
1
Для меня не совсем понятно, что вы подразумеваете под «разделением для подрядчиков». Отличаются ли таблицы, используемые подрядчиками, от таблиц, принадлежащих заказчику? Случается ли когда-нибудь, что клиент А должен получить доступ к данным клиента Б? Если нет, то можно выделить отдельные данные о клиенте в схему для каждого клиента - но не обязательно для производительности, но для разделения проблем (повышение безопасности / конфиденциальности и т. Д.).
Дезсо

Ответы:

1

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

  • Вы ожидаете много клиентов,
  • каждый из них может иметь тонны данных («тонны» означает гораздо больше, чем размер кеш-памяти),
  • большинство их наборов данных будут взаимоисключающими (каждый клиент видит разные подмножества данных).

ПРАВИЛА или триггеры снижают производительность и их можно избежать.

Рассмотрим что-то вроде этого:

BEGIN;

CREATE USER tenant1;
CREATE USER tenant2;

CREATE SCHEMA app;
CREATE SCHEMA tenant1;
CREATE SCHEMA tenant2;

CREATE TABLE app.objects_nonphysical(id int);
CREATE TABLE app.objects_physical(id int);
CREATE TABLE app.objects_mapping(id int);    
CREATE TABLE tenant1.objects_nonphysical() INHERITS(app.objects_nonphysical);
CREATE TABLE tenant1.objects_physical() INHERITS(app.objects_physical);
CREATE TABLE tenant1.objects_mapping() INHERITS(app.objects_mapping);
CREATE TABLE tenant2.objects_nonphysical() INHERITS(app.objects_nonphysical);
CREATE TABLE tenant2.objects_physical() INHERITS(app.objects_physical);
CREATE TABLE tenant2.objects_mapping() INHERITS(app.objects_mapping);

GRANT USAGE ON SCHEMA tenant1 TO tenant1;
GRANT USAGE ON SCHEMA tenant2 TO tenant2;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA tenant1 TO tenant1;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA tenant2 TO tenant2;

/* TEST: simulate login as customer */
SET SESSION AUTHORIZATION tenant2;
/* No schema needed - default search_path works */
SELECT count(*) FROM objects_nonphysical; 

ROLLBACK;

Вам не нужны никакие триггеры / правила для его поддержания.

Здесь есть открытые концы - это всего лишь черновик ... Некоторые вопросы:

  • PK, FK и индексы не «наследуются».
  • даже если вы их создадите, PK не будет применен к главной таблице
  • Вы можете преодолеть это, используя одинаковую последовательность для всех арендаторов
  • очевидно, приложение должно быть скорректировано для этой модели
filiprem
источник
0

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

Я рекомендую использовать правила для перенаправления вставок и внешнюю таблицу для первичных ключей (например CREATE TABLE objects_physical_ids (id bigserial NOT NULL PRIMARY KEY), вместе с одним триггером функции, который вставляет строку в таблицу идентификаторов и копирует ее в NEW.id (например INSERT INTO objects_physical_ids DEFAULT VALUES RETURNING id INTO NEW.id;), и другие триггеры, которые имеют дело с удалением). и обновлений, и триггера, выполняющего эти триггеры функций для каждой унаследованной таблицы (не забывайте делать это при создании новой унаследованной таблицы!). Тогда все связанные таблицы могут иметь FOREIGN KEYсоответствующую таблицу идентификаторов (включая любые действия внешнего ключа, такие как ON UPDATEили ON DELETE).

Ziggy Crueltyfree Zeitgeister
источник
2
У правил и триггеров определенно есть издержки, и их легко измерить. Кроме того, они добавляют сложность и усложняют отладку (намного). Кроме того, пройдя этот путь несколько раз, я бы предложил (без общеизвестного знания всех деталей) оставить пустую родительскую таблицу и один или несколько дочерних разделов. При изменении схемы разбиения это может оказаться очень полезным.
Дезсо