搜索多个表的顺序

时间:2015-04-24 05:28:57

标签: sql oracle search select query-performance

我有5个表table1 - table5,行数越来越多。

Table1 have about 1000 rows
Table2 - 10,000 rows 
Table3 - 50,000 rows
Table4 - 100,000 rows
and Table5 - 10,00,000 rows

我想选择包含account_number的行,该行可以在任何表中。

我对搜索account_number表1,表2,...表5的最佳方法感到困惑? 或表5,表4,......表1。 请建议。

注意:预计这些表格会随着时间的推移而增加多达40个数量级。这意味着Table5预计从现在开始每年约有4,00,00,000行,所以我从一开始就要小心,并且想要搜索不超过要求。

5 个答案:

答案 0 :(得分:2)

仅有一百万行的表格,其中包含索引最新收集的统计信息应该不是问题。

收集表格统计信息

EXEC DBMS_STATS.gather_table_stats('SCHEMA_NAME', 'TABLE_NAME');

与最大的表相比,其他表格要小得多。扫描 1000行的表格需要一些毫秒?好的,一两秒钟?没事。

很少有东西肯定取决于它是什么样的环境。 OLAP或OLTP。但是,我们谈论的最多是100万行。它应该足够快。

索引添加到帐号列,因为您将在过滤谓词中使用它,并检查解释计划执行查询之前。

如果您知道获得表5中的行的概率高达95%,那么从表5开始。如果您找到该行,那么非常好并且很幸运。否则,你会留下更小的桌子。

让我们看一个实际的例子:

设置一个包含9,999,999行的大表

SQL> create table big_table
  2  as
  3  select rownum id,
  4                 OWNER, OBJECT_NAME, SUBOBJECT_NAME,
  5                 OBJECT_ID, DATA_OBJECT_ID,
  6                 OBJECT_TYPE, CREATED, LAST_DDL_TIME,
  7                 TIMESTAMP, STATUS, TEMPORARY,
  8                 GENERATED, SECONDARY
  9    from all_objects a
 10   where 1=0
 11  /

Table created.

SQL> alter table big_table nologging;

Table altered.

SQL>
SQL> declare
  2      l_cnt number;
  3      l_rows number := 9999999;
  4  begin
  5      insert /*+ append */
  6      into big_table
  7      select rownum,
  8                 OWNER, OBJECT_NAME, SUBOBJECT_NAME,
  9                 OBJECT_ID, DATA_OBJECT_ID,
 10                 OBJECT_TYPE, CREATED, LAST_DDL_TIME,
 11                 TIMESTAMP, STATUS, TEMPORARY,
 12                 GENERATED, SECONDARY
 13        FROM all_objects A
 14       where rownum <= 9999999;
 15
 16      l_cnt := sql%rowcount;
 17
 18      commit;
 19
 20      while (l_cnt < l_rows)
 21      loop
 22          insert /*+ APPEND */ into big_table
 23          select rownum+l_cnt,
 24                 OWNER, OBJECT_NAME, SUBOBJECT_NAME,
 25                 OBJECT_ID, DATA_OBJECT_ID,
 26                 OBJECT_TYPE, CREATED, LAST_DDL_TIME,
 27                 TIMESTAMP, STATUS, TEMPORARY,
 28                 GENERATED, SECONDARY
 29            from big_table
 30           where rownum <= l_rows-l_cnt;
 31          l_cnt := l_cnt + sql%rowcount;
 32          commit;
 33      end loop;
 34  end;
 35  /

PL/SQL procedure successfully completed.

SQL>

现在我有大表 9,999,999行

SQL> SET TIME ON timing ON
11:36:54 SQL>
11:36:54 SQL> SELECT COUNT(*) FROM big_table;

  COUNT(*)
----------
   9999999

Elapsed: 00:00:01.82
11:36:56 SQL>

创建所需索引

11:36:56 SQL> CREATE INDEX big_indx ON big_table(object_name);

Index created.

Elapsed: 00:00:31.31
11:37:27 SQL>

我在object_name上创建了一个索引,它占用了一些30 seconds。为了更加安全,我在新创建的表上收集了统计数据

11:37:27 SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 'BIG_TABLE');

PL/SQL procedure successfully completed.

Elapsed: 00:00:15.92
11:37:43 SQL>

让我们检查 EXPLAIN PLAN

11:40:16 SQL> EXPLAIN PLAN FOR
11:40:22   2  SELECT DISTINCT OWNER, OBJECT_NAME FROM big_table WHERE OBJECT_NAME='BIG_TABLE';

Explained.

Elapsed: 00:00:00.00
11:40:26 SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1170786741

--------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |           |    23 |   713 |   128   (0)| 00:00:01 |
|   1 |  HASH UNIQUE                         |           |    23 |   713 |   128   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| BIG_TABLE |   194 |  6014 |   128   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                  | BIG_INDX  |   194 |       |     4   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("OBJECT_NAME"='BIG_TABLE')

15 rows selected.

Elapsed: 00:00:00.06
11:40:37 SQL>

所以,解释计划看起来不错。我看到索引范围扫描。所以,我的索引正在使用,这是一个好消息。

现在,让我们看看搜索我感兴趣的行需要多长时间:

11:42:41 SQL> SELECT DISTINCT OWNER, OBJECT_NAME FROM big_table WHERE OBJECT_NAME='BIG_TABLE';

OWNER OBJECT_NAME
----- ---------------
LALIT BIG_TABLE

Elapsed: 00:00:00.01
11:43:05 SQL>

我们看到了什么?甚至不到一秒

答案 1 :(得分:1)

你可以做这样的事情

Select * From table1 Where account_number = 'myAccountNumber'
Union
Select * From table2 Where account_number = 'myAccountNumber'
Union 
Select * From table3 Where account_number = 'myAccountNumber' 
Union
Select * From table4 Where account_number = 'myAccountNumber' 
Union
Select * From table5 Where account_number = 'myAccountNumber'

每个查询的结果合并在一起。然后可以根据喜好对其进行排序。

答案 2 :(得分:1)

试试这个:

select temp.col1, temp.col2, temp.col3,.....
from
(   select col1, col2, col3,.... from table1
    union all
    select col1, col2, col3,.... from table2
    union all
    select col1, col2, col3,.... from table3
    union all
    select col1, col2, col3,.... from table4
    union all
    select col1, col2, col3,.... from table5
 ) temp
 where colX = 'account number';

答案 3 :(得分:1)

您正在寻找的行计数很小,并且联合应该没有问题。但是,如果你想先查看一个表,然后再不进一步查询,那么这样的存储过程就可以了。

DECLARE @AccountNum AS TABLE (account_number VARCHAR(20))

INSERT INTO @AccountNum(account_number ) SELECT account_number FROM Table1

IF EXISTS (SELECT account_number FROM @AccountNum)
BEGIN
 SELECT account_number FROM @AccountNum
 RETURN
END

INSERT INTO @AccountNum(account_number ) SELECT account_number FROM Table2

IF EXISTS (SELECT account_number FROM @AccountNum)
BEGIN
 SELECT account_number FROM @AccountNum
 RETURN
END

我认为联合选项仍然是最佳选择。

答案 4 :(得分:0)

你可以从table1开始直到table5,原因很简单,因为table1的记录数最少,因此Oracle引擎必须搜索较少数量的记录,如果记录在table1中找到则则不必去表2并且明智。

您可以尝试这样:

select * 
from table5
where account_number = 'myAccountNumber'
UNION ALL

select * 
from table4 e 
WHERE NOT EXISTS( SELECT id FROM table5 ee WHERE ee.id = e.id)
and e.account_number = 'myAccountNumber'
UNION ALL

select * 
from table3 e
WHERE NOT EXISTS( SELECT id FROM table5 ee WHERE ee.id = e.id)
    AND NOT EXISTS( SELECT id FROM table4 ee WHERE ee.id = e.id)
and e.account_number = 'myAccountNumber'
UNION ALL

select * from table2 e
WHERE NOT EXISTS( SELECT id FROM table5 ee WHERE ee.id = e.id)
    AND NOT EXISTS( SELECT id FROM table4 ee WHERE ee.id = e.id)
    AND NOT EXISTS( SELECT id FROM table3 ee WHERE ee.id = e.id)
    and e.account_number = 'myAccountNumber'