Общие объекты арендатора - PullRequest
0 голосов
/ 15 марта 2019

У меня мультитенантное приложение с одной базой данных. У меня есть таблица «сущностей», где хранятся все объекты. Таблица «sahred_entity» используется для хранения объектов, которые используются Арендатором X для Арендатора Y. Например, «Арендатор 2» может совместно использовать «Сущность с ID 4» для «Арендатор 1».

В приведенном ниже примере «Объект с ID 4» используется совместно с «Арендатором 1» и «Арендатором 3»

+--------+--------------------------------------------------
| Table  | Create Table
+--------+--------------------------------------------------
| entity | CREATE TABLE `entity` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `tenant_id` int(10) unsigned NOT NULL,
  `added_at` timestamp NOT NULL,
  `color` varchar(20) NOT NULL,
  `size` varchar(5) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 |
+--------+--------------------------------------------------

+---------------+---------------------------------------
| Table         | Create Table
+---------------+---------------------------------------
| shared_entity | CREATE TABLE `shared_entity` (
  `tenant_to` int(10) unsigned NOT NULL,
  `tenant_from` int(10) unsigned NOT NULL,
  `entity_id` int(10) unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+---------------+---------------------------------------

Пример данных

select * from entity;

+----+-----------+---------------------+--------+------+
| id | tenant_id | added_at            | color  | size |
+----+-----------+---------------------+--------+------+
|  1 |         1 | 2019-03-07 00:00:00 | red    | m    |
|  2 |         1 | 2019-03-07 00:00:00 | green  | xl   |
|  3 |         2 | 2019-03-07 00:00:00 | green  | xl   |
|  4 |         2 | 2019-03-07 00:00:00 | red    | m    |
|  5 |         3 | 2019-03-07 00:00:00 | yellow | l    |
+----+-----------+---------------------+--------+------+

select * from shared_entity;

+-----------+-------------+-----------+
| tenant_to | tenant_from | entity_id |
+-----------+-------------+-----------+
|         1 |           2 |         4 |
|         3 |           2 |         4 |
+-----------+-------------+-----------+ 

Теперь мне нужно создать простой поисковый запрос. На данный момент я нашел два способа, как это сделать. Во-первых, через само присоединение

SELECT e.* FROM `entity` as e
LEFT JOIN entity as e1 ON (e.id = e1.id AND e1.tenant_id = 1)
LEFT JOIN entity as e2 ON (e.id = e2.id AND e2.id IN (4))
WHERE (e1.id IS NOT NULL OR e2.id IS NOT NULL) AND e.`color` = 'red';

Второй - через подзапрос и объединение

SELECT * FROM 
(
    SELECT * FROM entity as e1 WHERE e1.tenant_id = 1
        UNION
    SELECT * FROM entity as e2 WHERE e2.id IN(4)
) as entity
WHERE color = 'red';

Оба запроса возвращают ожидаемый результат

+----+-----------+---------------------+-------+------+
| id | tenant_id | added_at            | color | size |
+----+-----------+---------------------+-------+------+
|  1 |         1 | 2019-03-07 00:00:00 | red   | m    |
|  4 |         2 | 2019-03-07 00:00:00 | red   | m    |
+----+-----------+---------------------+-------+------+

Но какой подход лучше для больших таблиц? Как создать правильный индекс? Или, может быть, есть лучшее решение?

Ответы [ 2 ]

0 голосов
/ 16 марта 2019

Каждая таблица должна иметь PRIMARY KEY.shared_entity нужно PRIMARY KEY(tenant_from, tenant_to, entity_id);вероятно, подойдет любой заказ.

Что касается производительности, то предложение Хогана вместе с INDEX(color) подходит для небольшого стола:

SELECT *
    FROM entity
    WHERE (tenant_id = 1 OR id = 4)
      AND color = 'red'

Но OR предотвращает большинство форм оптимизации,Если color достаточно избирательно, то это не проблема;он просто просканирует все «красные» элементы, проверяя каждый на tenent_id и на id.

Если есть тысячи красных элементов, это будет выполняться быстрее:

( SELECT *
    FROM entity
    WHERE tenant_id = 1
      AND color = 'red' )
UNION DISTINCT
( SELECT *
    FROM entity
    WHERE id = 4
      AND color = 'red' )

вместе с

INDEX(color, tenant_id)  -- in either order
-- PRIMARY KEY(id)  -- already exists and is unique

UNION DISTINCT можно ускорить до UNION ALL, если вы знаете, что tenant-1 и id-4 не ссылаются на одну и ту же строку.

0 голосов
/ 15 марта 2019

Вы также можете использовать следующий запрос, чтобы получить те же результаты

SELECT *
FROM entity
WHERE (tenant_id = 1 or id = 4) AND color = 'red'

Мне не понятно, зачем вам все объединения

...