Oracle分区表查询成本与非分区表查询成本

Oracle分区表查询成本与非分区表查询成本,oracle,indexing,partitioning,database-administration,database-partitioning,Oracle,Indexing,Partitioning,Database Administration,Database Partitioning,我有一个表PO_头,有大约2000万条记录。考虑到表的未来负载,我们决定对表进行分区以提高sql查询的性能。下面是用于创建新分区表的查询 CREATE TABLE PO_HEADER_LP PARTITION BY LIST (BUYER_IDENTIFIER) (PARTITION GC66287246AA VALUES ('GC66287246AA') TABLESPACE MITRIX_TABLES, PARTITION GC43837235JK VALUES ('GC43837235

我有一个表PO_头,有大约2000万条记录。考虑到表的未来负载,我们决定对表进行分区以提高sql查询的性能。下面是用于创建新分区表的查询

CREATE TABLE PO_HEADER_LP 
 PARTITION BY LIST (BUYER_IDENTIFIER)
(PARTITION GC66287246AA VALUES ('GC66287246AA') TABLESPACE MITRIX_TABLES,
PARTITION GC43837235JK VALUES ('GC43837235JK') TABLESPACE MITRIX_TABLES,
PARTITION GC84338293AA VALUES ('GC84338293AA') TABLESPACE MITRIX_TABLES,
PARTITION DEFAULTBUID VALUES (DEFAULT) TABLESPACE MITRIX_TABLES) 
AS SELECT * 
   FROM PO_HEADER;

create index PO_HEADER_LP_SI_IDX on PO_HEADER_LP("SUPPLIER_IDENTIFIER") TABLESPACE MITRIX_INDEXES LOCAL;
旧表PO_表头在“买方_标识符”和“供应商_标识符”列上有两个索引,如下所示:

create index PO_HEADER_BI_IDX on  PO_HEADER("BUYER_IDENTIFIER") TABLESPACE MITRIX_INDEXES;
create index PO_HEADER_SI_IDX on  PO_HEADER("SUPPLIER_IDENTIFIER") TABLESPACE MITRIX_INDEXES;
为了测试查询的性能,我对这两个表执行了下面的查询。但是,令我惊讶的是,我发现第二个查询的成本几乎是第一个查询的两倍。任何人都知道,为什么分区表的查询成本比普通表高。提前谢谢

select * from po_header where buyer_identifier='GC84338293AA' and supplier_identifier='GC75987723HT'; --cost: 56,941
select * from po_header_lp where buyer_identifier= 'GC84338293AA' and supplier_identifier='GC75987723HT'; --cost: 93,309
采购订单标题,在买方标识栏和供应商标识栏上具有全局索引

采购订单标题与供应商标识符列上的全局索引

采购订单标题与供应商标识栏上的本地索引

您可以使用此脚本创建本地分区索引

CREATE INDEX PO_HEADER_LOCAL_IDX ON PO_HEADER_LP
(BUYER_IDENTIFIER, SUPPLIER_IDENTIFIER)
LOCAL (
       PARTITION GC66287246AA,  
       PARTITION GC43837235JK,  
       PARTITION GC84338293AA,  
       PARTITION DEFAULTBUID
      );
另外,建议使用以下脚本收集新创建分区表的统计信息:

EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA Name','PO_HEADER_LP');
现在,您可以再次生成以下SQL的执行计划:

select * from po_header_lp where buyer_identifier= 'GC84338293AA' and supplier_identifier='GC75987723HT';

希望这能对您有所帮助。

根据您的DDL,我假设您有三个大买家(比如说每个500万张唱片)和一群小买家。换句话说,这将是列表分区模式的正确设置

您可以验证它是否仅在买方上运行:

EXPLAIN PLAN  SET STATEMENT_ID = 'jara1' into plan_table  FOR
select * from tab_lp where BUYER_ID = 1;
;  
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));

------------------------------------------------------------------------------------------------
| Id  | Operation             | Name   | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |        |  6662K|    82M|  4445   (2)| 00:00:01 |       |       |
|   1 |  PARTITION LIST SINGLE|        |  6662K|    82M|  4445   (2)| 00:00:01 |   KEY |   KEY |
|   2 |   TABLE ACCESS FULL   | TAB_LP |  6662K|    82M|  4445   (2)| 00:00:01 |     2 |     2 |
------------------------------------------------------------------------------------------------
对非分区表执行相同的查询应该会产生更高的成本。为什么? 在分区表中,所选买家(在您的例子中是GC84338293AA,我使用的是代理键)有自己的分区。 所以完全扫描这个分区是最好的访问方式

select * from tab where BUYER_ID = 1;

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  6596K|    81M| 14025   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TAB  |  6596K|    81M| 14025   (1)| 00:00:01 |
--------------------------------------------------------------------------

   1 - filter("BUYER_ID"=1)
对于非分区表(获得大约四分之一的数据),完整表扫描也可以, 当然,的成本更高,因为所有数据都必须扫描

注意-如果您在这里看到较低的成本、不切实际的低
行数和/或
索引访问
, 这是成本低估问题的原因。所以不要担心旧的成本太低,而不是新的太高

下一步是访问买方和供应商。要得到答案,你必须提供答案 补充资料

供应商过滤器的选择性如何

也就是说,如果谓词
buyer\u identifier='GC84338293AA'
返回5M条记录,记录如何返回包含两列的谓词

买方识别码='GC84338293AA'和供应商识别码='GC75987723HT'

是4M还是100张唱片

如果完整谓词只返回比供应商的本地索引少的记录,则可以

如果它返回大量的行(比如分区的四分之一),那么您应该保持完整分区扫描,而不是使用它。 这类似于我对非分区表的评论

估计供应商基数

如果列供应商包含扭曲的数据(这可能会欺骗CBO计算不适当的成本),您可以在此列中明确定义直方图

我使用了这个语句,它计算完整数据(100%对于高度倾斜的数据很重要)以及表和分区的直方图

exec dbms_stats.gather_table_stats(ownname=>user,tabname=>'TAB_LP',granularity=>'all',estimate_percent => 100,METHOD_OPT => 'for columns SUPPLIER_ID size 254');

这适用于我的测试数据,即对于基数较低的供应商,打开了索引访问(在本地无前缀索引上),对于大型供应商,使用了完全分区扫描。

如果要包括执行计划,stack Exchange上有一个DBA社区,这可能比成本更能说明问题。将两个查询的成本与两个不同的表进行比较通常没有意义。有许多不同的统计数据可能是不同的。针对分区表的查询是否实际运行得更快、占用更少的CPU、执行更少的逻辑读取等。?表中是否真的只有3个
buyer\u identifier
值?或者是否有3个买家标识符值占了行的很大一部分,而其他值则小得多?您需要提供两个执行计划(编辑您的问题、格式化文本、无屏幕截图)。新分区表是否也有索引?是否已尝试此本地预固定索引方法。但是,它甚至需要更多的成本和执行查询时间。您是否尝试使用我提到的两列((买方标识符,供应商标识符))?是的,我使用(买方标识符,供应商标识符)创建了本地预固定索引,但它根本不使用索引,而是使用完整的表扫描是表(采购订单头\u LP)统计信息的最新?收集的表静态信息。现在,它使用的是指数,但成本/时间比正常的全球指数要多。@Manu让我了解买家和供应商的分布情况,并重新制定问题(不使用优化器成本),以便能够提供进一步的建议。无论如何,这是一个非常有趣的问题!感谢您的明确解释。我尝试使用买方标识符作为过滤器,正如您所解释的,分区表的所有成本都比较低。但是,当我使用额外的供应商标识作为过滤器时,成本将是一个折腾。但是,使用全局索引时,成本在降低,但与非分区成本不同。在db中,供应商文档数量可能会有所不同,即有些人可能有1/4的记录或更多的总记录。@Manu,再一次,不要害怕CBO成本:)。我添加了直方图的概念,这将有助于更恰当地计算计划和成本。请重新检查我的答案。@Marmite Bomber。在收集统计数据时,您应该始终使用自动样本大小来估计百分比。为什么?因为它使用了更新、更快、更准确的统计数据收集算法。自动样本大小也是一些其他高级统计数据收集工具的要求