我怎样才能改善大多数“退化”的内部联盟?

时间:2014-09-18 02:34:11

标签: 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和DATA。 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的查询?

1 个答案:

答案 0 :(得分:2)

我会直观地使用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(对于第一种情况,恕我直言,这是一个相当不错的选择)。