在搜索期间强制在 Oracle 中使用主键
Force use of primary key in Oracle during search
我有这样的场景,我需要搜索和显示来自大量 table 的大量行的记录。我为我的 table 预定义了搜索条件,用户可以为其提供过滤器并点击搜索。
考虑样本 table :
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,城市
如果他输入两个字段,我的查询性能会很好,因为它用于索引扫描
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 |
但是,如果他只输入一个搜索字段,我的查询性能会变差,因为它会进行完整 table 扫描
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;
谢谢。
完整的table 扫描不一定是坏的。您的 table 中只有几行,因此优化器认为执行 FTS 比索引范围扫描更好。一旦 RDBMS 认为它更好,它将立即开始使用 PK 索引,即你有很多行并且对某个供应商的限制显着降低了结果。如果你只想搜索城市而不是供应商,你需要另一个只包含城市的索引(或者至少从城市开始)。请记住,您可能需要在 table 加载批量数据后更新 table 统计数据。使用实际数量的数据测试查询性能始终很重要。
索引首先在 supplier_name 上组织,其次在城市上组织,因此无法将该索引用于仅基于城市的查询。
请仅基于城市创建第二个索引。这将有助于您的查询。
你的想法是错误的。
查询优化器将根据解析查询时(或有时参数更改时)可用的信息选择它认为最佳的查询执行计划。一般来说——如果你在统计等方面给它正确的信息,它通常会做得很好。
您可能认为自己比它更了解,但请记住,您不会在数据库的整个生命周期内监视它。数据发生变化,您希望数据库能够在需要时做出反应并更改执行计划。
也就是说,如果您设置为强制它使用索引,您可以使用提示:
SELECT /*+ INDEX(suppliers suppliers_pk) */
supplier_name, address, city, state, zip_code FROM suppliers where
supplier_name = 'ABCD' ;
我有这样的场景,我需要搜索和显示来自大量 table 的大量行的记录。我为我的 table 预定义了搜索条件,用户可以为其提供过滤器并点击搜索。
考虑样本 table :
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,城市
如果他输入两个字段,我的查询性能会很好,因为它用于索引扫描
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 |
但是,如果他只输入一个搜索字段,我的查询性能会变差,因为它会进行完整 table 扫描
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;
谢谢。
完整的table 扫描不一定是坏的。您的 table 中只有几行,因此优化器认为执行 FTS 比索引范围扫描更好。一旦 RDBMS 认为它更好,它将立即开始使用 PK 索引,即你有很多行并且对某个供应商的限制显着降低了结果。如果你只想搜索城市而不是供应商,你需要另一个只包含城市的索引(或者至少从城市开始)。请记住,您可能需要在 table 加载批量数据后更新 table 统计数据。使用实际数量的数据测试查询性能始终很重要。
索引首先在 supplier_name 上组织,其次在城市上组织,因此无法将该索引用于仅基于城市的查询。 请仅基于城市创建第二个索引。这将有助于您的查询。
你的想法是错误的。
查询优化器将根据解析查询时(或有时参数更改时)可用的信息选择它认为最佳的查询执行计划。一般来说——如果你在统计等方面给它正确的信息,它通常会做得很好。
您可能认为自己比它更了解,但请记住,您不会在数据库的整个生命周期内监视它。数据发生变化,您希望数据库能够在需要时做出反应并更改执行计划。
也就是说,如果您设置为强制它使用索引,您可以使用提示:
SELECT /*+ INDEX(suppliers suppliers_pk) */
supplier_name, address, city, state, zip_code FROM suppliers where
supplier_name = 'ABCD' ;