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 / 240768
Accepted
gertvdijk
gertvdijk
Asked: 2019-06-18 14:27:48 +0800 CST2019-06-18 14:27:48 +0800 CST 2019-06-18 14:27:48 +0800 CST

Poda de partição eficiente com ORDER BY na mesma coluna que PARTITION BY RANGE + LIMIT?

  • 772

Eu configurei uma tabela no MariaDB (10.4.5, atualmente RC) com o InnoDB usando particionamento por uma coluna cujo valor é somente incrementado e novos dados são sempre inseridos no final. Nesse caso, o particionamento faz sentido para acelerar algumas consultas e manter partições novas/ativas em unidades rápidas e antigas/arquivadas em discos giratórios lentos. Para acelerações de inserção está funcionando muito bem! (Uma espécie de abordagem TimescaleDb, mas sem tempo e sem PostgreSQL.)

SELECTs por intervalo na mesma coluna também funcionam bem; ele só começará a ler (o índice de) as partições do intervalo especificado. Tudo legal até agora.

Agora, também tenho consultas que não têm uma cláusula nessa coluna, mas são ordenadas de forma decrescente por essa coluna (ou seja, dados novos primeiro), junto com um limite, que normalmente atingiria apenas uma ou duas partições mais recentes (rápidas, em cache índice). No entanto, parece que o MySQL/MariaDB começa a abrir partições do primeiro ao último, não importa qual seja a ordem especificada. É realmente tão burro? Além disso, não consegui encontrar mais ninguém com essa dúvida, o que me preocupa um pouco. (Às vezes significa que estou perdendo algo realmente óbvio.)

Para ficar mais concreto aqui - para testes, tenho a seguinte tabela:

CREATE TABLE `mytable` (
  `user_id` bigint(20) unsigned NOT NULL,
  `my_id` bigint(20) unsigned NOT NULL,
  `data` varbinary(123) DEFAULT NULL,
  PRIMARY KEY (`user_id`,`my_id`),
  UNIQUE KEY `my_id_idx` (`my_id`)  -- I was hoping this one could help me
) ENGINE=InnoDB ROW_FORMAT=COMPACT
 PARTITION BY RANGE (`my_id`)
(PARTITION `p0` VALUES LESS THAN (10000000) ENGINE = InnoDB,
 PARTITION `p10M` VALUES LESS THAN (20000000) ENGINE = InnoDB,
 PARTITION `p20M` VALUES LESS THAN (30000000) ENGINE = InnoDB,
 PARTITION `p30M` VALUES LESS THAN (40000000) ENGINE = InnoDB,
 [...]
) 

E eu executo uma consulta como:

SELECT 
    user_id,
    my_id,
    LENGTH(data) AS data_len
FROM
    mytable
    -- tried to optimize with index hints:
    -- USE INDEX FOR ORDER BY (MY_ID_IDX)
    -- USE INDEX FOR ORDER BY (PRIMARY)
    -- USE INDEX FOR ORDER BY (MY_IDX, PRIMARY)
WHERE
    user_id = 1234567
ORDER BY my_id DESC
LIMIT 10;

Descobri que ele começa a procurar TODOS os dados user_id = 1234567primeiro, mostrando primeiro a carga pesada de E / S nos discos giratórios, depois finalmente chegando ao armazenamento rápido para obter o conjunto completo e cortando as últimas LIMIT 10linhas ... o que estavam todos em armazenamento rápido, então perdemos minutos de tempo para nada! Hum.

Meus dados são muito grandes e não podemos ter todos os índices na memória - contamos com 'o suficiente' do índice no disco para ser armazenado em cache na camada de armazenamento. Mas mesmo que todos os índices couberem no cache, os dados precisam vir de discos e alguns usuários têm uma quantidade ENORME de dados aqui (> 10 milhões de linhas) e é simplesmente ineficiente fazer essa classificação na memória assim. Então, espero encontrar uma maneira de fazer com que o MariaDB procure a última quantidade LIMIT de linhas e pare de ler.

Como humano, você começaria a procurar na última partição primeiro, porque ela ORDER BY my_id DESCe as partições mais recentes contêm os valores mais altos para ela. No entanto, como eu digo ao MySQL/MariaDB para fazer isso?

explain partitionsresultado (para todas as variantes USE INDEX listadas acima é o mesmo):

  select_type: SIMPLE
        table: mytable
   partitions: p0M,p10M,p20M,p30M, ... (~ hundred here)
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 8
          ref: const
         rows: 9999999 (worst-case)
        Extra: Using where

Na verdade, ao contrário do que eu esperava, nem está tendo melhor desempenho se fizer a consulta em ordem crescente , usando a partição first-to-new. Ele ainda solicitará todos os índices de todas as partições e descobrirá que só precisava de um ...

Ouvi algo sobre um índice global para partições em versões futuras do MySQL, mas duvido que realmente ajude aqui, dado o tamanho enorme ..., e já recebeu a dica pelo próprio layout de particionamento no meu caso. A informação que encontro sobre 'remoção de partição' parece não ter relação com a ordenação das leituras; apenas sobre cláusulas na consulta.

Qualquer ajuda é apreciada.:-)

As partições mais novas serão criadas dinamicamente e não é realmente viável dar uma dica sobre uma partição específica. Minha situação é que as partições "mais recentes" são rápidas, "mais antigas" são "lentas", "mais antigas" são "super lentas" - assumindo que nada armazenado em cache na camada de armazenamento é demais. Além disso, estou usando um proxy (SPIDER) em uma máquina separada que deve fornecer aos clientes uma única interface para consulta, sem precisar saber sobre o layout de particionamento dos back-ends, então prefiro uma maneira de fazer isso ' automático'.

mysql mariadb
  • 1 1 respostas
  • 823 Views

1 respostas

  • Voted
  1. Best Answer
    Rick James
    2019-06-18T15:54:37+08:002019-06-18T15:54:37+08:00

    Parabéns. Acho que você encontrou um caso em que o particionamento não pode ser tão rápido quanto o não particionamento.

    WHERE user_id = 1234567
    ORDER BY my_id DESC
    LIMIT 10;
    

    Necessidades INDEX(user_id, my_id)nessa ordem e sem particionamento. Assim, tocaria 10 linhas e sairia.

    Com o particionamento que você possui, ele deve verificar cada partição, reunir as linhas encontradas em cada partição, classificá-las e parar na 10ª.

    "Particionar não é uma panacéia de desempenho".

    Você tem outras consultas para as quais isso se PARTITION BY RANGEbeneficia? Se assim for, você pode ter uma situação de troca. Ou seja, que algumas consultas são executadas mais rapidamente, outras mais lentas.

    Em geral, se houver um número razoavelmente limitado de "usuários" e você estiver inserindo novas linhas para cada usuário continuamente, não há problema em ter um "ponto de acesso" por usuário.

    Isso leva a

    PRIMARY KEY(user_id, my_id)
    

    com my_idúnico de alguma forma. Não precisa ser declarado UNIQUE. Se for AUTO_INREMENT, então isso funciona bem:

    my_id INT AUTO_INCREMENT,
    PRIMARY KEY(user_id, my_id)  -- to cluster by user
    INDEX(my_id)   -- to keep AUTO_INCREMENT happy
    

    Com isso, a maioria das consultas como essa funciona com bastante eficiência:

    WHERE user_id = 12345
      AND ((other stuff))
    

    O cache no buffer_pool é mais importante do que SSD vs HDD. E o número de blocos tocados é importante para o desempenho.

    A INSERTsnecessidade de um bloco por usuário. Eventualmente, haverá uma divisão de bloco. Mas então, ele está de volta a um bloco ativo (um "ponto de acesso").

    SELECTs, mesmo que os blocos desejados não estejam no buffer_pool, tendem a ser eficientes devido ao fato WHERE user_id=...de as linhas desejadas estarem em muito poucos blocos. Isso é especialmente verdade para o SELECT ... LIMIT 10que você mencionou.

    Os blocos são armazenados em cache. inteiros INDEXes não são. A consulta em questão examinará apenas 1 (talvez 2) bloco no layout não particionado. O restante do índice vai e vem com base na atividade.

    10 milhões de linhas é 'grande'; 1 bilhão de linhas é 'enorme'. Índices globais provavelmente demoram anos para MySQL e MariaDB; não prenda a respiração.

    Qual é o valor de innodb_buffer_pool_size? Quanta RAM?

    • 3

relate perguntas

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

  • Quando é o momento certo para usar o MariaDB em vez do MySQL e por quê?

  • Como um grupo pode rastrear alterações no esquema do banco de dados?

Sidebar

Stats

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

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 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

    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
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • 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
    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

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