AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 11366
Accepted
Bob Jansen
Bob Jansen
Asked: 2012-01-24 01:20:12 +0800 CST2012-01-24 01:20:12 +0800 CST 2012-01-24 01:20:12 +0800 CST

Encontrar valores distintos com eficiência

  • 772

Eu tenho várias tabelas com a chave primária (mês, ano, número) e diferentes cardinalidades diferem um pouco. Para a tupla (mês, ano) a história não vai muito longe, isso provavelmente não crescerá além de 50 a muito longo prazo. Para cada tupla (mês, ano) não há mais de 2 milhões de números únicos. Quero saber quais combinações de mês e ano estão disponíveis. Eu faço isso usando esta consulta:

select month, year from table group by month, year

Isso retorna o resultado correto, mas não parece ser muito eficiente. Qual é uma maneira eficiente de obter esse resultado (utilizando o índice único)?

O consultor de ajuste sugere adicionar um índice mês-ano para esta consulta, mas isso parece um desperdício porque um índice maior já está disponível.

oracle
  • 2 2 respostas
  • 2293 Views

2 respostas

  • Voted
  1. Best Answer
    Jack Douglas
    2012-01-24T02:20:46+08:002012-01-24T02:20:46+08:00

    Você pode usar uma variação da seguinte técnica - que força varreduras repetidas de alcance 'MIN/MAX':

    Suposições

    1. Você pode produzir uma lista de todas as combinações possíveis de ano/mês
    2. numbernão é nulo (o que não pode ser como está no PK, mas mencionei porque há uma maneira de contornar se nulos forem permitidos)

    banco de ensaio:

    create table foo(month, year, num, primary key(month, year, num)) as
    with m as ( select extract(month from d) as month, extract(year from d) as year
                from (select add_months(sysdate,1-level) as d from dual connect by level<50) )
    select month, year, num
    from m cross join 
         (select level as num from dual connect by level<100000 order by dbms_random.random());
    

    consulta normal:

    select distinct month, year from foo;
    --gets=11656
    

    técnica min/max:

    with m as ( select extract(month from d) as month, extract(year from d) as year
                from (select add_months(sysdate,1-level) as d from dual connect by level<50) )
    select month, year, decode(( select min(num)
                                 from foo
                                 where month=m.month and year=m.year )
                               ,null, 'N', 'Y') as has_data_yn
    from m;
    --gets=294
    

    Algumas explicações em resposta aos comentários:

    Em cada caso (o testbed e a consulta min/max), a cláusula de fatoração da subconsulta apenas gerou uma lista de tuplas (ano, mês):

    with m as ( select extract(month from d) as month, extract(year from d) as year
                from (select add_months(sysdate,1-level) as d from dual connect by level<50) )
    select * from m;
    /*
    MONTH                  YEAR                   
    ---------------------- ---------------------- 
    1                      2012                   
    12                     2011                   
    11                     2011                   
    10                     2011           
    ...
    ...
    */
    

    Então a técnica usa uma subconsulta na selectcláusula para verificar se alguma linha está presente para o (mês, ano) - esta subconsulta necessariamente deve produzir apenas no máximo 1 linha:

    select min(num)
    from foo
    where month=m.month and year=m.year;
    

    Isso é muito rápido porque faz uso da natureza ordenada do PK - no entanto, ele precisa ser executado uma vez para cada mês - se houver milhões de linhas para cada mês, isso faz sentido, mas não se houver poucas o suficiente para caber um pequeno número de blocos.

    • 5
  2. Leigh Riffel
    2012-01-25T06:42:15+08:002012-01-25T06:42:15+08:00

    Aqui está uma solução usando a mesma técnica de Jack Douglas (+1). Ele produz um número idêntico de resultados consistentes usando seu testbed, mas se é mais fácil de entender ou não, depende do observador.

    SELECT extract(month from d) m, extract(year from d) y 
    FROM (SELECT add_months(sysdate,1-level) d FROM dual CONNECT BY level < 50)
    WHERE EXISTS (
     SELECT 1 FROM foo WHERE month=extract(month from d) AND year=extract(year from d)
    );
    

    Esta opção usa o select from dual para direcionar a consulta e o select from foo apenas para decidir quais datas manter.

    A mesma consulta também poderia ser escrita assim:

    SELECT * FROM (
       SELECT extract(month from add_months(sysdate,1-level)) m 
            , extract(year from add_months(sysdate,1-level)) y 
          FROM dual CONNECT BY level < 50)
    WHERE EXISTS (
       SELECT 1 FROM foo WHERE month=m AND year=y
    );
    
    • 3

relate perguntas

  • Backups de banco de dados no Oracle - Exportar o banco de dados ou usar outras ferramentas?

  • ORDER BY usando prioridades personalizadas para colunas de texto

  • Interface sqlplus confortável? [fechado]

  • Como encontrar as instruções SQL mais recentes no banco de dados?

  • Como posso consultar nomes usando expressões regulares?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve