在搜索期间强制在Oracle中使用主键

时间:2016-09-30 08:51:27

标签: oracle composite-primary-key

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

考虑样本表:

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');

我为用户提供了搜索字段作为主键 - supplier_name,city

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

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;

感谢。

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

索引首先在city_name上的supplier_name上进行组织,因此无法仅根据城市使用该索引进行查询。 请仅根据城市创建第二个索引。这有助于您的查询。

答案 2 :(得分:0)

你正在以错误的方式思考这个问题。

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

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

也就是说,如果你强迫它使用索引,你可以使用提示:

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