我有一个带有单个数据库的多租户应用程序。我有一个“实体”表,其中存储了所有对象。 “ 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 |
+----+-----------+---------------------+-------+------+
但是哪种方法更适合大型表?如何创建正确的索引?还是有更好的解决方案?
答案 0 :(得分:0)
您还可以使用以下查询获得相同的结果
SELECT *
FROM entity
WHERE (tenant_id = 1 or id = 4) AND color = 'red'
我不清楚您为什么需要所有联接
答案 1 :(得分:0)
每个表都应有一个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
如果您知道承租人1和id-4不在同一行,则 UNION DISTINCT
最多可加速UNION ALL
。