共享租户对象

问题描述 投票:0回答:2

我有一个带有单个数据库的多租户应用程序。我有一个“实体”表,其中存储了所有对象。 “sahred_entity”表用于存储租户X与租户Y共享的对象。例如,“租户2”可以将“具有ID 4的实体”共享给“租户1”。

在下面的示例中,“租户1”和“租户3”共享“ID为4的实体”

+--------+--------------------------------------------------
| 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    |
+----+-----------+---------------------+-------+------+

但哪种方法对大型表更好?如何创建正确的索引?或者也许有更好的解决方案?

mysql sql indexing multi-tenant query-performance
2个回答
0
投票

您还可以使用以下查询来获得相同的结果

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

我不清楚为什么你需要所有的连接


0
投票

每张桌子应该有一个PRIMARY KEYshared_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_idid

如果有数千个红色项目,这将运行得更快:

( 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

如果你知道租户-1和id-4没有引用同一行,UNION DISTINCT可以加速到UNION ALL

© www.soinside.com 2019 - 2024. All rights reserved.