Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle SQL-连接比较空值的性能_Sql_Performance_Oracle_Join - Fatal编程技术网

Oracle SQL-连接比较空值的性能

Oracle SQL-连接比较空值的性能,sql,performance,oracle,join,Sql,Performance,Oracle,Join,早上好 昨天我在两个大小合适的结果集之间编写了一个查询(第一种情况下为45分钟,而第二种情况下为,因为每个空值都不同,所以数据库不使用优化(对于a中的每一行,检查表b中的每一行) 在第二种情况下,数据库首先将所有空值更改为“N/A”,然后使用优化只比较A.class和b.class 在Oracle中比较空值非常耗时。空值是未定义的值-一个空值不同于另一个空值。 比较两个几乎相同的查询的结果: select 1 from dual where null is null select 1 from

早上好


昨天我在两个大小合适的结果集之间编写了一个查询(第一种情况下为45分钟,而第二种情况下为,因为每个空值都不同,所以数据库不使用优化(对于
a
中的每一行,检查表
b
中的每一行)

在第二种情况下,数据库首先将所有空值更改为“N/A”,然后使用优化只比较
A.class
b.class

在Oracle中比较空值非常耗时。空值是未定义的值-一个空值不同于另一个空值。 比较两个几乎相同的查询的结果:

select 1 from dual where null is null

select 1 from dual where null = null
只有带有特殊
的第一个查询是null
子句才能返回正确答案。因此,空值不能被索引。

请尝试以下方法:

SELECT a from Table1 a JOIN JTable1 b ON a.class = b.class
where a.class is null
union all
SELECT a from Table1 a JOIN JTable1 b ON a.class = b.class
where b.class is null

应该快一点

为什么不简单一点呢。 像

挑选* 从a到b 哪里 a、 类(+)=b.class(+)


我认为它更具可读性。

您返回的是带有空类记录的叉积。这对您的结果合适吗

我在11gR2中创建了两个示例查询:

WITH a as 
(select NULL as class, 5 as columna from dual
 UNION
 select NULL as class, 7 as columna from dual
 UNION
 select NULL as class, 9 as columna from dual
 UNION
 select 'X' as class, 3 as columna from dual
 UNION
 select 'Y' as class, 2 as columna from dual),
 b as 
 (select NULL as class, 2 as columnb from dual
 UNION
 select NULL as class, 15 as columnb from dual
 UNION
 select NULL as class, 5 as columnb from dual
 UNION
 select 'X' as class, 7 as columnb from dual
 UNION
 select 'Y' as class, 9 as columnb from dual)
    SELECT * from a JOIN b ON (a.class = b.class 
                              OR (a.class is null AND b.class is null))
当我在这个查询上运行EXPLAIN PLAN时,它指示表(在我的例子中是内联视图)通过嵌套循环联接。嵌套循环联接的操作方式是扫描一个表的第一行,然后扫描另一个表的每一行以查找匹配项,然后扫描第一个表的第二行,在第二个表上查找匹配项,等等。因为您没有直接比较联接中的表或部分,所以优化器必须se嵌套循环

在幕后,它可能看起来像:

  • 获取表A的第1行。如果类为null,则在结果集中包含表A中的此行
  • 当仍在表A第1行时,在表B中搜索class为null的所有行
  • 对表a第1行和表B中的所有行执行叉积
  • 将这些行包括在结果集中
  • 获取表A第2行。如果类为null,则将表A中的此行包含在结果集中
  • ……等等
当我将SELECT语句更改为
SELECT*时,从NVL上的联接b(a.class,'N/a')=NVL(b.class,'N/a'))
,EXPLAIN表示使用了散列联接。散列联接基本上生成较小表的每个联接键的散列,然后扫描较大表,在较小表中查找匹配的每一行的散列。在这种情况下,由于它是一个简单的等联接,优化器可以对驱动表的每一行进行散列,而不会出现问题

在幕后,它可能看起来像:

  • 浏览表A,将空类值转换为“N/A”
  • 边走边散列表A的每一行
  • 哈希表A现在位于临时空间或内存中
  • 扫描表B,将空类值转换为“N/A”,然后计算值的哈希值。哈希表中的查找哈希值(如果存在)包括结果集中表A和B中的联接行
  • 继续扫描B
如果对查询运行解释计划,您可能会发现类似的结果

即使最终结果是相同的,但由于在第一次查询中没有使用“或”连接表,优化器也无法使用更好的连接方法。如果驱动表很大,或者对较大的辅助表强制进行完整表扫描,则嵌套循环可能会非常慢

您可以使用ANSI
COALESCE
函数在其他数据库系统中模拟NVL oracle函数。这里的真正问题是,您正试图加入一个空值,在这个空值上,您确实应该有一个“无类”或其他方法来识别一个空=无而不是空=未知意义上的“空”类

在评论中回答您的问题的附录:

对于空查询,SQL引擎将执行以下操作:

  • 从表A中读取第1行,类为空,转换为“N/A”
  • 表B有3行,其中类为null,请将每个null转换为“N/A”
  • 由于第一行与所有3行匹配,因此将向结果集中添加3行,其中一行用于A1B1、A1B2、A1B3
  • 从表A中读取第2行,类为空,转换为“N/A”/
  • 表B有3行,其中类为null,请将每个null转换为“N/A”
  • 由于第二行与所有3行匹配,因此将向结果集中添加3行,其中一行用于A2B1、A2B2、A2B3
  • 从表A中读取第3行,类为空,转换为“N/A”/
  • 表B有3行,其中类为null,请将每个null转换为“N/A”
  • 由于第三行与所有3行都匹配,因此将向结果集中添加3行,其中一行用于A3B1、A3B2、A3B3。 10..第4行和第5行不是空的,因此它们不会在联接的这一部分中被处理
  • 对于“N/A”查询,SQL引擎将执行以下操作:

  • 从表A中读取第1行,类为空,转换为“N/A”,散列此值
  • 从表A中读取第2行,类为空,转换为“N/A”,散列此值
  • 从表A中读取第3行,类为空,转换为“N/A”,散列此值
  • 从表A中读取第4行,类不为null,散列此值
  • 从表A中读取第5行,类不为null,散列此值
  • 哈希表C现在在内存中
  • 从表B中读取第1行,类为空,转换为“N/A”,散列值
  • 将哈希值与内存中的哈希表进行比较,对于每个匹配项,向结果集中添加一行。找到3行,A1、A2和A3。结果添加A1B1、A2B1、A3B1
  • 从表B中读取第2行,类为空,转换为“N/A”,散列值
  • 将哈希值与内存中的哈希表进行比较,为每个匹配项向结果集中添加一行。找到3行,分别为A1、A2和A3。结果添加为A1B2、A2B2、A3B2
  • 从表B中读取第3行,类为空,转换为“N/A”,散列值
  • 将哈希值与内存中的哈希表进行比较,对于每个匹配项,向结果集中添加一行。找到3行,分别为A1、A2和A3。结果
    SELECT a from Table1 a JOIN JTable1 b ON a.class = b.class
    where a.class is null
    union all
    SELECT a from Table1 a JOIN JTable1 b ON a.class = b.class
    where b.class is null
    
    WITH a as 
    (select NULL as class, 5 as columna from dual
     UNION
     select NULL as class, 7 as columna from dual
     UNION
     select NULL as class, 9 as columna from dual
     UNION
     select 'X' as class, 3 as columna from dual
     UNION
     select 'Y' as class, 2 as columna from dual),
     b as 
     (select NULL as class, 2 as columnb from dual
     UNION
     select NULL as class, 15 as columnb from dual
     UNION
     select NULL as class, 5 as columnb from dual
     UNION
     select 'X' as class, 7 as columnb from dual
     UNION
     select 'Y' as class, 9 as columnb from dual)
        SELECT * from a JOIN b ON (a.class = b.class 
                                  OR (a.class is null AND b.class is null))