我有一个场景,我需要搜索&显示来自包含大量行的大型表的记录。我为我的表预先定义了搜索条件,用户可以为其提供过滤器&点击搜索。
考虑样本表:
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;
感谢。
答案 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' ;