【发布时间】:2021-05-19 15:50:29
【问题描述】:
我有一个带有 items 表的 MySQL 数据库,每个项目都限定为一个帐户。
这些项目每个都可以有几种颜色中的一种,如下所示:
项目
id | account_id | color
------------------------
1 | 1 | white
2 | 1 | white
3 | 1 | blue
4 | 1 | red
5 | 2 | white
6 | 2 | white
7 | 2 | white
在项目的显示页面上,我们希望显示项目的颜色,但仅当帐户曾经使用过多种颜色时。一旦他们开始在该帐户中使用另一种颜色,我们希望为所有项目显示颜色。
例如:
- 当显示 ID 为
1的项目时,我们会显示它是white,因为该帐户有混合白色、蓝色的项目 和红色。 - 当显示 ID 为
7的项目时,我们不会显示颜色, 因为帐户中的所有颜色都相同(白色),所以有 无需使用颜色来区分它们。
为了进行这项检查,我目前正在选择帐户中的任何项目(第一个,但可能是任何项目),并运行查询以查看帐户中是否有任何颜色不同的项目,像这样:
// Get any color in the account:
SELECT color FROM items WHERE account_id = 1 LIMIT 1;
// See if any other color is used ("red" was returned from the previous query):
SELECT 1 AS one FROM `items` WHERE account_id = 1 AND color != 'red' LIMIT 1;
这很有效,并且对于循环使用一堆颜色的帐户相当有效,但有些帐户可能有数千或数百万个项目,并且可能只使用一种颜色,因此它可能必须扫描一个帐户,看看有没有不同的。
我已经尝试在 account_id 和 color 上添加复合索引,但即使是该索引也必须扫描数千或数百万条记录才能确定,因为只有少数几种颜色可以分组。
这可以接受吗?是否有一种特殊的索引可以在这里有效,或者我需要添加触发器/过程来更新每次插入时缓存的列或表?
我对触发器的意思是这样的:
DELIMITER $$
CREATE TRIGGER items_after_insert_update_account_colors
AFTER INSERT
ON items FOR EACH ROW
BEGIN
// Insert row, but ignore if the exact row already exists.
INSERT IGNORE INTO account_colors
SET color = NEW.color, account_id = NEW.account_id;
END$$
DELIMITER;
然后通过如下查询检查该表以确定是否显示颜色:
// True if other color is found for account.
SELECT 1 AS one FROM account_colors WHERE account_id = 1 AND color != 'red' LIMIT 1;
有没有一种索引技术我可以用来有效地做到这一点,或者正在使用像上面这样的触发器来缓存表的当前状态,并在每次插入时更新它,这是我能做的最好的吗?
总而言之,我想我想问是否有办法使索引像上面那样工作,即使对于数百万条记录,索引也很小,只需要保存这样的最少信息:
account_id | uses_color
-----------------------
1 | white
1 | blue
1 | red
2 | white
或
account_id | used_colors
-------------------------------------
1 | ['blue', 'white', 'red']
2 | ['white']
【问题讨论】:
-
触发器与此有什么关系?您想从查询中得到什么结果?
-
幸运的是,到目前为止提供的所有帐户都是如此
-
@GordonLinoff 该触发器只是一个示例,说明如果没有一个可以快速处理数百万行的良好索引策略,我可以如何实现这一点。我想要一个查询来快速告诉我整个帐户中是否只使用了一种颜色。
-
请提供各种用例的示例数据,并显示所需的输出。
-
@RickJames 我在示例中添加了更多列以显示具有所有匹配颜色的帐户,并解释了我想要的结果。感谢您让我知道我不清楚的地方。
标签: mysql sql indexing triggers database-performance