【问题标题】:SQL query optimization - multiple rows from another tableSQL 查询优化 - 来自另一个表的多行
【发布时间】:2020-05-10 18:51:10
【问题描述】:

我的桌子是这样的(目前)

CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `user_opts` (
  `user_id` bigint(20) NOT NULL,
  `opt1` varchar(64) DEFAULT NULL,
  `opt2` TINYINT(4) DEFAULT NULL,
  `opt3` varchar(64) DEFAULT NULL,
  KEY `user_id_idx` (`user_id`)
);

我希望能够进行这样的查询:

SELECT DISTINCT name
FROM users
WHERE 
    id = 1 AND (
        EXISTS ( SELECT 1 FROM user_opts WHERE user_opts.user_id = users.id AND user_opts.opt1 = 'a' AND user_opts.opt3 = 'c') OR
        EXISTS ( SELECT 1 FROM user_opts WHERE user_opts.user_id = users.id AND user_opts.opt1 = 'b' AND user_opts.opt2 = 1)
    );

还有这个:

SELECT DISTINCT name
FROM users
WHERE 
    id = 1 AND (
        EXISTS ( SELECT 1 FROM user_opts WHERE user_opts.user_id = users.id AND user_opts.opt1 = 'a' AND user_opts.opt3 = 'e') AND
        EXISTS ( SELECT 1 FROM user_opts WHERE user_opts.user_id = users.id AND user_opts.opt1 = 'b' AND user_opts.opt2 = 1)
    );

我开始遇到的一个明显问题是,用户越多,查询就越慢。我知道我可以通过 JOIN 表重构第一种类型的查询(使用 OR),但是 JOIN 本身会很慢,因为我无法在 user_opts 表上进行 PK。

如何重组我的数据(和查询),以便进行高效/快速的搜索?最好,如果可能的话,我希望对 ANDOR 类型保持相同的查询,只是在两者之间切换条件。

DB Fiddle url

谢谢!

【问题讨论】:

  • 这是 1:n 关系还是 1:1?
  • 1:n,这就是为什么我不能在user_opts 表上进行 PK(至少使用当前结构)

标签: mysql sql mariadb entity-attribute-value sql-optimization


【解决方案1】:

你可以使用聚合:

select user_id
from user_opts uo
where opt3 = 'c' or opt2 = 1
group by user_id
having sum(opt3 = 'c') >= 1 and
       sum(opt2 = 1) >= 1;

这会处理两个选项设置在user_opts 中同一行的情况。

【讨论】:

  • 遗憾的是,这似乎并没有让它变得更快。我在生产数据库上试过这种方式,结果是一样的,+-3%
  • 澄清(现在无法编辑)您的查询本身很快,但是当我将其用作子查询以从用户中选择名称并添加users.id = user_opts.user_id 条件时,它会变慢。
  • @Andrew 。 . .随着您的数据变大,这会变慢,但可能比您的版本慢。
  • OR 在规模上是出了名的低效。并且查询似乎缺少user_id=1
【解决方案2】:

添加这两个索引会加快EXISTS:

INDEX(user_id, opt1, opt3)
INDEX(user_id, opt1, opt2)

您的架构是 EAV 的变体,众所周知,它效率低下且笨拙。 users 中没有 opt2 和 opt3 有充分的理由吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 2011-08-05
    相关资源
    最近更新 更多