【问题标题】:Force use of primary key in Oracle during search在搜索期间强制使用 Oracle 中的主键
【发布时间】:2016-09-30 08:51:26
【问题描述】:

我有一个场景,我需要从包含大量行的大表中搜索和显示记录。我为我的表预先定义了搜索条件,用户可以为其提供过滤器并单击搜索。

考虑一个示例表:

CREATE TABLE suppliers 
( supplier_name varchar2(50) NOT NULL,
  address varchar2(50),
  city varchar2(50) NOT NULL,
  state varchar2(25),
  zip_code varchar2(10),
  CONSTRAINT "suppliers_pk" PRIMARY KEY (supplier_name, city)
);


INSERT INTO suppliers VALUES ('ABCD','XXXX','YYYY','ZZZZ','95012');
INSERT INTO suppliers VALUES ('EFGH','MMMM','NNNN','OOOO','95010');
INSERT INTO suppliers VALUES ('IJKL','EEEE','FFFF','GGGG','95009');

我已经为用户提供了搜索字段作为主键 - 供应商名称,城市

如果他输入两个字段,我的查询性能会很好,因为它用于索引扫描

SELECT supplier_name, address, city, state, zip_code FROM suppliers where supplier_name = 'ABCD' and city = 'ZZZZ';

| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     1 |   102 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| SUPPLIERS    |     1 |   102 |     1   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | suppliers_pk |     1 |       |     1   (0)| 00:00:01 |

但是,如果他只输入其中一个搜索字段,我的查询性能会变差,因为它用于全表扫描

SELECT supplier_name, address, city, state, zip_code FROM suppliers where supplier_name = 'ABCD' ;

| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |     1 |   102 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| SUPPLIERS |     1 |   102 |     3   (0)| 00:00:01 |

当我在搜索中没有所有关键字段时,有没有办法强制 oracle 认为它是主键搜索,如下所示(这显然不起作用)

SELECT supplier_name, address, city, state, zip_code FROM suppliers where supplier_name = 'ABCD' and city = city;

谢谢。

【问题讨论】:

  • Oracle 可能会执行跳过扫描索引搜索,如果它认为这比全表扫描更合适且更有效。一般来说,假设统计数据是最新的,优化器非常擅长使用可用索引选择最佳计划。如果它认为它不能进行跳过扫描,也许您需要在city 上建立一个单独的索引?让它使用 PK 索引不太可能是有效的 - 它可能会进行完整的索引扫描,然后仍然必须获取相关行的数据块。
  • 您的表中只有 3 行。添加 10 000 行,收集统计数据并分析结果。
  • 谢谢,我确实在一张有数百万行的表上进行了尝试,它进行的是 INDEX RANGE SCAN 而不是 FTS。

标签: oracle composite-primary-key


【解决方案1】:

你想错了。

查询优化器将根据在解析查询时(或有时在参数更改时)可用的信息为查询选择它认为最佳的执行计划。一般来说——如果你在统计数据等方面给它正确的信息,它通常会做得很好。

您可能认为您比它更了解,但请记住,您不会在数据库的整个生命周期内监控它。数据发生变化,您希望数据库能够在需要时做出反应并更改执行计划。

也就是说,如果你设置强制它使用索引,你可以使用一个提示:

SELECT /*+ INDEX(suppliers suppliers_pk) */
supplier_name, address, city, state, zip_code FROM suppliers where   
supplier_name = 'ABCD' ;

【讨论】:

    【解决方案2】:

    全表扫描不一定是坏事。您的表中只有几行,因此优化器认为执行 FTS 比索引范围扫描更好。当 RDBMS 认为它更好时,它将立即开始使用 PK 索引,即您有很多行并且对某个供应商的限制会显着降低结果。如果您只想搜索城市而不是供应商,则需要另一个仅包含城市的索引(或至少以城市开头)。请记住,您可能必须在使用批量数据加载表格后更新表格统计信息。使用真实的数据量测试查询性能始终很重要。

    【讨论】:

      【解决方案3】:

      索引首先在供应商名称上组织,其次在城市上,因此不能使用该索引仅基于城市进行查询。 请仅根据城市创建第二个索引。这将有助于您的查询。

      【讨论】:

      • That isn't necessarily true。尽管在这种情况下,优化器认为跳过扫描效率不高,可能是因为有很多供应商,所以它对这种方法的选择性不够。
      猜你喜欢
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 2012-05-07
      相关资源
      最近更新 更多