Cenário: Melhorar estimativas de cardinalidade usando visualizações estatísticas
Em um armazém de dados, informações de tabela de fatos muitas vezes mudam bastante dinamicamente, enquanto que dados da tabela de dimensões são estáticos. Isso significa que dados de atributos de dimensão podem ser positivamente ou negativamente correlacionados com dados de atributo de tabela de fatos.
As estatísticas de tabela de base tradicionais disponíveis atualmente para o otimizador não permitem que ele discernam relações através de tabelas. Estatísticas de distribuição de coluna e tabela sobre visões estatísticas (e MQTs) podem ser usadas para dar ao otimizador as informações necessárias para corrigir esses tipos de erros de estimação de cardinalidade.
select sum(f.sales_price), d2.year
from product d1, period d2, daily_sales f
where d1.prodkey = f.prodkey
and d2.perkey = f.perkey
and d1.item_desc = 'golf club'
and d2.month = 'JUL'
group by d2.yearUm plano de execução de consulta de star join pode ser uma excelente opção para esta consulta, desde que o otimizador possa determinar se a semi-junção envolvendo PRODUTO e DAILY_SALES, ou a semi-junção envolvendo PERÍODO e DAILY_SALES, é a mais seletiva. Para gerar um plano de junção de estrelas eficiente, o otimizador deve ser capaz de escolher a semi-junção mais seletiva para a etapa externa da operação de ANDing do índice.
Os armazéns de dados costumam conter registros para produtos que não estão mais em prateleiras das lojas. Isso pode causar a distribuição de colunas de PRODUTO após a junção para aparecer dramaticamente diferente da sua distribuição antes da junção. Como o otimizador, por falta de melhores informações, determinará a seletividade de predicados locais com base apenas em estatísticas de tabela base, o otimizador pode se tornar excessivamente otimista em relação à seletividade do predicado item_desc
= 'golf club'
Por exemplo, se os tacos de golfe historicamente representam 1% dos produtos fabricados, mas agora representam 20% das vendas, o otimizador provavelmente superestimaria a seletividade de item_desc = 'golf club', pois não há estatísticas que descreva a distribuição de item_desc após a junção. E se as vendas em todos os doze meses forem igualmente prováveis, a seletividade do predicado month = 'JUL' seria em torno de 8% e, assim, o erro em estimar a seletividade do predicado item_desc = 'golf club' causaria equivocadamente que o otimizador executaria a semi-junção aparentemente mais seletiva entre PRODUT e DAILY_SALES como a etapa externa da operação ANDing do plano de junção de estrelas.
O exemplo a seguir fornece uma ilustração passo-a-passo de como configurar visualizações estatísticas para resolver este tipo de problema.
| Coluna | chave da loja | número da loja | cidade | estado | distrito | ... |
|---|---|---|---|---|---|---|
| Atributo | integer
não null chave primária |
CHAR(2) | char(20) | CHAR(5) | char (14) | ... |
| Coluna | chave do cliente | nome | endereço | idade | sexo | ... |
|---|---|---|---|---|---|---|
| Atributo | integer
não null chave primária |
char(30) | char (40) | smallint | char(1) | ... |
| Coluna | chave do produto | categoria | descrição_do_item | preço | cost | ... |
|---|---|---|---|---|---|---|
| Atributo | integer
não null chave primária |
número inteiro | char(30) | decimal (11) | decimal (11) | ... |
| Coluna | chave promocional | promótipo | promodesc | promocional | ... |
|---|---|---|---|---|---|
| Atributo | integer
não null chave primária |
número inteiro | char(30) | decimal (5) | ... |
| Coluna | perkey | calendar_data | mês | período | ano | ... |
|---|---|---|---|---|---|---|
| Atributo | integer
não null chave primária |
data | char(3) | smallint | smallint | ... |
| Coluna | chave da loja | chave do cliente | chave do produto | chave promocional | perkey | sales_preço | ... |
|---|---|---|---|---|---|---|---|
| Atributo | número inteiro | número inteiro | número inteiro | número inteiro | número inteiro | decimal (11) | ... |
Suponha que os gerentes da empresa queiram determinar se os consumidores comprarão ou não um produto novamente se forem oferecidos um desconto em uma visita de retorno. Além disso, suponhamos que este estudo seja feito apenas para a loja '01', que tem 18 locais em todo o território nacional. Tabela 7 mostra informações sobre as diferentes categorias de promoção que estão disponíveis.
| promótipo | promodesc | CONTAR (protótipo) | porcentagem do total |
|---|---|---|---|
| 1 | Clientes de retorno | 1 | 2.86% |
| 2 | Cupom | 15 | 42.86% |
| 3 | Propaganda | 5 | 14.29% |
| 4 | Especial do gerente | 3 | 8.57% |
| 5 | Itens superestocados | 4 | 11.43% |
| 6 | Exibição de corredor final | 7 | 20.00% |
select count(*)
from store d1, promotion d2, daily_sales f
where d1.storekey = f.storekey
and d2.promokey = f.promokey
and d1.store_number = '01'
and d2.promotype = 1 6.15567e+06
IXAND
( 8)
/------------------+------------------\
2.15448e+07 2.15448e+08
NLJOIN NLJOIN
( 9) ( 13)
/---------+--------\ /---------+--------\
1 2.15448e+07 18 1.19694e+07
FETCH IXSCAN FETCH IXSCAN
( 10) ( 12) ( 14) ( 16)
/---+---\ | /---+---\ |
35 35 7.54069e+08 18 63 7.54069e+08
IXSCAN TABLE: DB2DBA INDEX: DB2DBA IXSCAN TABLE: DB2DBA INDEX: DB2DBA
( 11) PROMOTION PROMO_FK_IDX ( 15) STORE STORE_FK_IDX
| |
35 63
INDEX: DB2DBA INDEX: DB2DBA
PROMOTION_PK_IDX STOREX1| Antes De Participar | Após Junção | |||
|---|---|---|---|---|
| Predicado | contagem | porcentagem de linhas qualificadas | contagem | porcentagem de linhas qualificadas |
| número_da_loja = '01' | 18 | 28.57% | 2.15448e+08 | 28.57% |
| promótipo = 1 | 1 | 2.86% | 2.15448e+07 | 2.86% |
Como a probabilidade de promotype = 1 é menor do que a de store_number = '01', o otimizador escolhe a semi-junção entre PROMOTION e DAILY_SALES como a perna externa da operação ANDing do plano de junção de estrelas. Isso leva a uma contagem estimada de aproximadamente 6 155 670 produtos vendidos usando o tipo de promoção 1-uma estimativa de cardinalidade incorreta que é desativada por um fator de 2.09 (12 889 514 ÷ 6 155 670 ≈ 2.09).
- Crie uma view representando a junção de STORE com DAILY_SALES.
create view sv_store_dailysales as (select s.* from store s, daily_sales ds where s.storekey = ds.storekey) - Crie uma view representando a junção da PROMOÇÃO com DAILY_SALES.
create view sv_promotion_dailysales as (select p.* from promotion.p, daily_sales ds where p.promokey = ds.promokey) - Faça as visualizações estatísticas de visualizações, ativando-as para otimização de consulta:
alter view sv_store_dailysales enable query optimization alter view sv_promotion_dailysales enable query optimization - Execute o comando RUNSTATS para coletar estatísticas sobre as visualizações:
runstats on table db2dba.sv_store_dailysales with distribution runstats on table db2dba.sv_promotion_dailysales with distribution - Execute a consulta novamente para que ele possa ser re-otimizado. Mediante a reotimização, o otimizador corresponderá SV_STORE_DAILYSALES e SV_PROMOTION_DAILYSALES com a consulta, e utilizará as estatísticas da visualização para ajustar a estimativa de cardinalidade das semi-joias entre as tabelas de fato e dimensão, causando uma inversão da ordem original das semi-joias escolhidas sem essas estatísticas. O novo plano é o seguinte:
1.04627e+07 IXAND ( 8) /------------------+------------------\ 6.99152e+07 1.12845e+08 NLJOIN NLJOIN ( 9) ( 13) /---------+--------\ /---------+--------\ 18 3.88418e+06 1 1.12845e+08 FETCH IXSCAN FETCH IXSCAN ( 10) ( 12) ( 14) ( 16) /---+---\ | /---+---\ | 18 63 7.54069e+08 35 35 7.54069e+08 IXSCAN TABLE:DB2DBA INDEX: DB2DBA IXSCAN TABLE: DB2DBA INDEX: DB2DBA DB2DBA ( 11) STORE STORE_FK_IDX ( 15) PROMOTION PROMO_FK_IDX | | 63 35 INDEX: DB2DBA INDEX: DB2DBA STOREX1 PROMOTION_PK_IDX
| Antes De Participar | After Join (sem visualizações estatísticas) | Após Join (com visualizações estatísticas) | ||||
|---|---|---|---|---|---|---|
| Predicado | contagem | porcentagem de linhas qualificadas | contagem | porcentagem de linhas qualificadas | contagem | porcentagem de linhas qualificadas |
| número_da_loja = '01' | 18 | 28.57% | 2.15448e+08 | 28.57% | 6.99152e+07 | 9.27% |
| promótipo = 1 | 1 | 2.86% | 2.15448e+07 | 2.86% | 1.12845e+08 | 14.96% |
store_number = '01' filtrará mais linhas do que promotype = 1. Desta vez, o otimizador estima que existam aproximadamente 10462700 produtos vendidos. Esta estimativa é desativada por um fator de 1.23 (12 889 514 ÷ 10 462 700 ≈ 1.23), que é uma melhoria significativa sobre a estimativa sem visualizações estatísticas (na Tabela 8).