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 / 30851
Accepted
codewaggle
codewaggle
Asked: 2012-12-21 08:09:08 +0800 CST2012-12-21 08:09:08 +0800 CST 2012-12-21 08:09:08 +0800 CST

Procedimento armazenado do MySQL: percorrer a tabela, excluir linhas. Problema lógico: não sai do loop por causa da opção LIMIT na consulta

  • 772

Eu criei um procedimento para percorrer grandes tabelas InnoDB e excluir um pedaço de linhas, depois pausar e repetir até que o valor máximo do campo permitido seja alcançado.

O log binário está habilitado, mas estou deixando-o na NONDETERMINISTICconfiguração padrão, então não acho que isso importe.

O comando CALL inclui o número de linhas a serem excluídas por linha ( num_rows) e o último valor de campo a ser excluído ( maxId). (Estou usando o id de chave primária).

A primeira parte funciona corretamente, faz um loop e exclui um pedaço de linhas a cada passagem.

Há uma Ifinstrução para verificar o último id ( @z) do pedaço atual em relação maxIda , ele deve sair do loop se o último id for nulo ou for maior que o maxId. Mas nunca dispara e sai do loop.

Não consigo determinar o que fiz de errado, pensamentos?


ATUALIZAÇÃO:
Eu determinei a origem do problema, mas não tenho certeza de como corrigi-lo.

O último id @zdo bloco a ser excluído é definido com uma instrução de limite na @sql_text2consulta.

Mas, no final, a opção limite nessa consulta faz com que ela retorne um conjunto de resultados vazio porque o deslocamento é maior que o conjunto de resultados e as linhas a serem retornadas são um.

Por exemplo, executei a consulta que seria executada no final e ela retorna um conjunto de resultados vazio (números alterados para maior clareza). Usando idpara keyfield:

SELECT id FROM table_name WHERE id >= 7000 ORDER BY id LIMIT 1000,1;

A consulta @sql_text2como seria executada pelo procedimento (com INTO @z):

SELECT id INTO @z FROM table_name WHERE id >= 7000 ORDER BY id LIMIT 1000,1;

O último id na tabela é 7817.

A instrução diz para obter 1000 linhas começando com o último id excluído na passagem anterior (7000) e retornar uma linha (a última linha) do conjunto de resultados.

O último id do conjunto de resultados seria 7999, mas isso não existe na tabela.

Portanto, não tenho certeza de qual valor está atribuído @ze não posso verificar se ele é acionadoLEAVE loop_label;

No IFbloco, eu estava verificando is nulle adicionei um cheque = ""e ainda não corresponde. Alguém sabe qual valor seria atribuído @zno caso de um conjunto de resultados vazio?

Eu encontrei isso nos documentos para "Variáveis ​​definidas pelo usuário":

Se você se referir a uma variável que não foi inicializada, ela terá um valor NULL e um tipo de string.

@zfoi inicializado e usado anteriormente, que status ele tem quando atribuído a um conjunto de resultados vazio como seu valor?

Existe um comando como a isset()função PHP


SOLUÇÃO:
O comentário de @a1ex07 teve uma correção. Defina @zcomo null no início do loop.

Eu não entendo porque isso resolveu o problema embora.

Eu pensei que talvez fosse porque @zsó é definido dentro do loop e, portanto, é redefinido toda vez que o loop começa, mas tentei configurar @zantes do início do loop (para null e depois 1), mas isso causou o problema original.

Poderia ter algo a ver com a definição @ado valor de @zno final do loop?

Ainda estou curioso sobre qual valor é atribuído @zpor @sql_text2na última passagem.


Aqui está a instrução de criação do procedimento, seguida pela instrução Call usada para implementá-la.
Atualização O código a seguir foi atualizado com a correção e funciona corretamente:

delimiter //

Create PROCEDURE `removeProcessed`(table_name VARCHAR(255), keyField VARCHAR(255), maxId INT, num_rows INT)
BEGIN
  SET @table_name = table_name;
  SET @keyField = keyField;
  SET @maxId = maxId;
  SET @num_rows = num_rows;

  SET @sql_text1 = concat('SELECT MIN(',@keyField,') INTO @a FROM ',@table_name);
  PREPARE stmt1 FROM @sql_text1;
  EXECUTE stmt1;
  DEALLOCATE PREPARE stmt1;

  loop_label:  LOOP
    SET @z = NULL;
    SET @sql_text2 = concat('SELECT ',@keyField,' INTO @z FROM ',@table_name,' WHERE ',@keyField,' >= ',@a,' ORDER BY ',@keyField,' LIMIT ',@num_rows,',1');
    PREPARE stmt2 FROM @sql_text2;
    EXECUTE stmt2;
    DEALLOCATE PREPARE stmt2;

    If @z is null THEN
      LEAVE loop_label;
    ELSEIF @z = "" THEN
      LEAVE loop_label;
    ELSEIF @z > @maxId THEN
      LEAVE loop_label;
    END IF;

    SET @sql_text3 = concat('DELETE FROM ',@table_name,' WHERE ',@keyField,' >= ',@a,' AND ',@keyField,' <= ',@z);
    PREPARE stmt3 FROM @sql_text3;
    EXECUTE stmt3;
    DEALLOCATE PREPARE stmt3;

    SET @a = @z;
    SELECT SLEEP(1);
  END LOOP;

  SET @sql_text4 = concat('DELETE FROM ',@table_name,' WHERE ',@keyField,' <= ',@maxId);
  PREPARE stmt4 FROM @sql_text4;
  EXECUTE stmt4;
  DEALLOCATE PREPARE stmt4;
END
//

delimiter ;


CALL db_name.removeProcessed('table_name', 'key_field_name', 1300731617, 100000);
mysql stored-procedures
  • 1 1 respostas
  • 28780 Views

1 respostas

  • Voted
  1. Best Answer
    rubo77
    2013-02-20T16:59:46+08:002013-02-20T16:59:46+08:00

    Há duas soluções possíveis:

    definido @zcomo null no início do seu loop (antes de SET @sql_text2 = concat('....)


    ou em vez de

    SELECT id INTO @z FROM table_name WHERE id >= 7000 ORDER BY id LIMIT 1000,1;
    

    usa isto:

    SET @z = (SELECT id FROM table_name WHERE id >= 7000 ORDER BY id LIMIT 1000,1);
    

    Explicação:

    Quando nenhuma linha é encontrada, a variável permanece inalterada em relação ao seu valor anterior... se você estiver fazendo algo assim SELECT ... INTO, não redefinirá o valor se nada for encontrado.
    consulte: https://dba.stackexchange.com/a/35207/12923

    • 4

relate perguntas

  • Existem ferramentas de benchmarking do MySQL? [fechado]

  • 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

    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