sql - 如何改进 moSTLy "degenerate"内部联接?

标签 sql oracle join oracle11g

这是 Oracle 11g。

我有两个表,其相关列如下所示(我必须采用给定的表 - 我无法更改列数据类型):

CREATE TABLE USERS 
(
   UUID VARCHAR2(36),
   DATA VARCHAR2(128),
   ENABLED NUMBER(1)
);

CREATE TABLE FEATURES
(
   USER_UUID VARCHAR2(36),
   FEATURE_TYPE NUMBER(4)
);

这些表表达了可以为用户分配多个功能的概念。 (USER_UUID, FEATURE_TYPE) 组合是唯一的。

我有两个非常相似的查询,我对此很感兴趣。第一个查询用英语表示,是“返回分配了功能 X 的启用用户的 UUID”。第二个是“返回分配了功能 X 的启用用户的 UUID 和数据”。 USERS 表大约有 5,000 条记录,FEATURES 表大约有 40,000 条记录。

我最初将第一个查询天真地写为:

SELECT u.UUID FROM USERS u
JOIN FEATURES f ON f.USER_UUID=u.UUID
WHERE f.FEATURE_TYPE=X and u.ENABLED=1

而且性能很差。作为一个实验,我试图看看如果我不关心用户是否启用会发生什么,这激发了我的尝试:

SELECT USER_UUID FROM FEATURES WHERE TYPE=X

而且运行得非常快。这反过来又激励我尝试

(SELECT USER_UUID FROM FEATURES WHERE TYPE=X)
INTERSECT
(SELECT UUID FROM USERS WHERE ENABLED=1)

它的运行速度不如第二个查询,但比第一个查询运行得快得多。

经过更多思考,我意识到,在当前的情况下,每个用户或几乎每个用户都被分配了至少一个功能,这意味着连接条件始终或几乎始终为真,这意味着内部连接完全或大部分退化进入交叉连接。因为 5,000 x 40,000 = 200,000,000 这不是一件好事。显然,INTERSECT 版本将处理更少的行,这可能就是它明显更快的原因。

问题:在这种情况下,INTERSECT 真的是正确的选择吗?还是我应该考虑其他类型的连接?

我编写了与第一个查询类似的查询,该查询也需要返回DATA:

SELECT u.UUID, u.DATA FROM USERS u
JOIN FEATURES f ON f.USER_UUID=u.UUID
WHERE f.FEATURE_TYPE=X and u.ENABLED=1

但我似乎无法在这里执行 INTERSECT 技巧,因为 FEATURES 中没有与 DATA 列匹配的列。

问题:如何重写它以避免退化连接问题并像不返回 DATA 的查询一样执行?

最佳答案

我会直观地使用EXISTS子句:

SELECT u.UUID
FROM USERS u
WHERE u.ENABLED=1
  AND EXISTS (SELECT 1 FROM FEATURES f where f.FEATURE_TYPE=X and f.USER_UUID=u.UUID)

或类似:

SELECT u.UUID, u.DATA
FROM USERS u
WHERE u.ENABLED=1
  AND EXISTS (SELECT 1 FROM FEATURES f where f.FEATURE_TYPE=X and f.USER_UUID=u.UUID)

这样您就可以从USERS中选择每个字段,因为不再需要INTERSECT(对于第一种情况,这是一个相当不错的选择,恕我直言)。

关于sql - 如何改进 moSTLy "degenerate"内部联接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25903294/

相关文章:

php - MYSQL 多重计数和求和

mysql - 如何在MySQL中进行多连接查询?

PostgreSQL 连接以使用 generate_series 对表进行非规范化

MySQL 多重内部连接、联合和 where 子句

mysql - 查找有 0 个帖子、1-5 个帖子和 >5 个帖子的用户的平均年龄

sql - 如何使用 Postgres 添加指向 2 个表之一的外键?

java - java中的非唯一表别名错误

sql - 只允许将 3 行添加到表中以获取特定值

xml - 从 BPEL 中的 SOAP 主体请求字符串中提取 XPath

sql - 多个表上的多个 LEFT OUTER JOIN