将查询JOIN重写为EXISTS

时间:2014-08-05 03:16:00

标签: database oracle left-join exists

我试图理解从EXISTS重写查询为JOIN和Viceversa。

所以我有这个:

SQL Fiddle

Oracle 11g R2架构设置

create table store
(
  storeKey number,
  storeName varchar2(500),
  storeLocationKey number,
  constraint StorePK primary key(storeKey)
);

create table storeLocation
(
  storeLocationKey number,
  storeLocationName varchar2(500),
  storeCountry varchar2(500),
  constraint StoreLocPK primary key(storeLocationKey)
);

insert into store values(1, 'Le Store', 1);
insert into store values(2, 'La tiendinha', 2);
insert into store values(3, 'The SuperHyperMegaStore', 3);
insert into store values(4, 'Le Other Store', 1);
insert into store values(5, 'La tienda', 4);
insert into store values(6, 'Chiquinha Tienda', 2);
insert into store values(7, 'Pecorela Tiendinha', 3);
insert into store values(8, 'Le Petit Store', 1);
insert into store values(9, 'Tienda Cipote', 4);
insert into store values(10, 'Tienda Desconocida', 0);


insert into storeLocation values(1, 'Camps Elisees', 'France');
insert into storeLocation values(2, 'Brasilia', 'Brasil');
insert into storeLocation values(3, 'Boston', 'USA');
insert into storeLocation values(4, 'San Salvador', 'El Salvador');

查询1

SELECT store.*
FROM store
LEFT OUTER JOIN storeLocation
    ON store.storeLocationKey = storeLocation.storeLocationKey
WHERE storeLocation.storeCountry <> 'France'
ORDER BY store.storeKey ASC

Results

| STOREKEY |               STORENAME | STORELOCATIONKEY |
|----------|-------------------------|------------------|
|        2 |            La tiendinha |                2 |
|        3 | The SuperHyperMegaStore |                3 |
|        5 |               La tienda |                4 |
|        6 |        Chiquinha Tienda |                2 |
|        7 |      Pecorela Tiendinha |                3 |
|        9 |           Tienda Cipote |                4 |

查询2

SELECT *
FROM store
WHERE EXISTS (
        SELECT 1
        FROM storeLocation
        WHERE storeLocationKey = store.storeLocationKey
            AND storeCountry <> 'France'
        )
ORDER BY storeKey ASC

Results

| STOREKEY |               STORENAME | STORELOCATIONKEY |
|----------|-------------------------|------------------|
|        2 |            La tiendinha |                2 |
|        3 | The SuperHyperMegaStore |                3 |
|        5 |               La tienda |                4 |
|        6 |        Chiquinha Tienda |                2 |
|        7 |      Pecorela Tiendinha |                3 |
|        9 |           Tienda Cipote |                4 |

查询3

-----------------------------

SELECT store.*
FROM store
LEFT OUTER JOIN storeLocation
    ON store.storeLocationKey = storeLocation.storeLocationKey
where storeLocation.storeLocationName is null
ORDER BY store.storeKey ASC

Results

| STOREKEY |          STORENAME | STORELOCATIONKEY |
|----------|--------------------|------------------|
|       10 | Tienda Desconocida |                0 |

查询4

SELECT store.*
FROM store
WHERE NOT EXISTS (
        SELECT NULL
        FROM storeLocation
        WHERE storeLocationKey = store.storeLocationKey
        )

Results

| STOREKEY |          STORENAME | STORELOCATIONKEY |
|----------|--------------------|------------------|
|       10 | Tienda Desconocida |                0 |

从这里开始,我有一些(愚蠢的)问题:

  • 为什么查询2和4必须相关(当我没有关联查询时,它什么都没有返回)?存在/不存在是否必须与工作相关?

  • 哪种方案最好与其中任何一种一起使用?

  • 使用大量数据(DW)会有所不同吗?

感谢。

1 个答案:

答案 0 :(得分:2)

问题1:

实际上,如果您没有关联子查询,那么您的查询2将返回不在法国(SQLFiddle)的每一行。这是因为相关查询:&#34;从商店返回行,其中storelocation中至少有一个 匹配 行不在法国&#34; 。您的不相关查询意味着&#34;从商店返回行,其中至少存在不在法国&#34;的storelocation中的行。由于子查询将始终返回至少一行,因此WHERE条件始终为真。

对于查询4,没有相关性,子查询仍将始终返回一行,WHERE条件将始终为false,并且您将不会获得任何行。

问题2:

如果是我,由于您未选择storelocation中的任何内容,我会使用EXISTS版本。我觉得更清楚的是,您唯一关心的是商店位置中是否存在匹配行而不是连接情况。

这是一个简单的查询,我怀疑优化器会提出相同的执行计划,但我肯定不知道。

此外,我发现EXISTS子句允许优化器在找到匹配后停止查找行而不必进行完全连接的情况。

在这种情况下你显然不会,但如果你的商店位置有多个具有相同id的位置,那么两种情况下的行数会有所不同。

问题3:

如果没有看到执行计划,真的没有办法回答这个问题。我会以一种让读者最清楚的方式编写您的查询,然后对其进行测试。如果运行时间可以接受,请停止。只有在速度太慢的情况下才能让它快速运行。