Pourquoi ce script de base de données ne fonctionne pas correctement et comment le savoir ?

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Après des heures pour essayer de débugger un script pour recopier une base de données dans une autre, j’abandonne et je viens solliciter votre aide car je ne comprends vraiment pas où se trouve le problème. J’ai une table table_name dans une première base de données que je veux recopier dans une autre table table_name dans une autre base de données. Les bases de données étant grandes, je veux aussi enregistrer l’avancée du recopiage de chaque ligne et enregistrer les éventuels erreurs.

Alors j’établis d’abord les connexions et je crée les curseurs

conn_origin = mysql.connector.connect(...) #J'ai testé les connexions, elles marchent bien
conn_copy = mysql.connector.connect(...)

cursor_origin = conn_origin.cursor()
cursor_copy = conn_copy.cursor()

Comme j’ai un fichier qui enregistre l'id de chaque ligne bien recopiée, j’aimerais bien s’il y a un problème récupérer cet id et commencer à partir de la ligne d’après, donc je définis cette fonction :

def find_id(file_path):
  with open(file_path, 'r') as f:
    for line in f:
      pass
    return int(''.join(char for char in line if char.isdigit()))

Maintenant je peux créer la fonction qui va recopier les données :

def copy_data(incrementer, table_name, table_columns):
  #Je récupère le dernier id et je commence à partir de lui, ou j'initialise à 1
  if os.path.isfile("copy_logs.txt"):
    n_rows = find_id("copy_logs.txt")+1
  else:
    n_rows = 1
    
  file1 = open("copy_logs.txt", 'a')
  file2 = open("errors_logs.txt", 'a')
  
  #Je désactive les contraintes sur les clés étrangères dans la table de copie
  disable_fk = """SET foreign_key_checks=0"""
  cursor_copy.execute(disable_fk)
  
  #Je récupère la taille de la table originale pour effectuer une boucle while
  length_query = """SELECT count(id) FROM """+table_name
  cursor_origin.execute(length_query)
  result = cursor_origin.fetchone()
  length = result[0]
  
  #Je crée un format pour les valeurs à insérer et les noms de colonnes
  n_elements = len(table_columns)
  table_format = '('
  for i in range(n_elements):
    if i==n_elements-1:
      table_format += '%s)'
    else:
      table_format += '%s,'
  columns = '('+','.join(table_columns)+')'
  
  #Je mets la requête de recopiage
  copy_query = """INSERT INTO """+table_name+' '+columns+""" VALUES """+table_format
  
  #J'initialise à False une variable erreur pour arrêter complètement le script
  #en cas d'erreur
  erreur = False
  
  #Maintenant la boucle pour recopier la table
  while n_rows<length:
    #Je mets ici un bloc try-except pour récupèrer les lignes à recopier
    try:
      retrive_query = """SELECT * FROM """+table_name+""" WHERE id BETWEEN """+str(n_rows)+""" AND """+str(n_rows+incrementer-1)
      cursor_origin.execute(retrieve_query)
      rows = cursor_origin.fetchall()
    except:
      file2.write("Il y a eu un problème.")
      error = True
      break
    
    #Je mets ici une boucle pour recopier les lignes une par une
    for row in rows:
      try:
        cursor_copy.execute(copy_query, row)
        conn_copy.commit()
        file1.write("On a recopié la ligne : "+str(row[0])+"\n")
      except:
        file2.write("Il y a eu un problème à la ligne : "+str(row[0])+"\n")
        error = True
        break
    
    #Il faut tout arrêter s'il y a une seule erreur
    if error:
      break
    
    n_rows += incrementer
    
  file1.close()
  file2.close()

Et bien sûr je ferme les connexions à la fin :

conn_origin.close()
conn_copy.close()

J’ai remarqué ça pendant plusieurs vains essais, le script se déroule jusqu’à la fin, c’est à dire jusqu’à ce que n_rows>length. Ma table initiale est de taille 467 586, et je trouve que mon copy_logs s’étend bizarrement jusqu’à 468 000. Je ne vois pas comment c’est possible, j’ai bien for row in rows et c’est bien l'id, row[0], que j’écris dans le fichier texte.

Autre problème, c’est que quand je regarde la taille de la table d’arrivée, celle dans laquelle j’insère des valeurs, je trouve qu’elle est de taille 421 359. Donc il y a 46 227 lignes qui n’ont pas été recopié, je ne sais pour quelle raison, et que ces raisons n’ont pas été captées par les blocs try-except.

Je ne comprends vraiment pas d’où viennent ces problèmes, j’ai aussi essayé de mettre des try-except à chaque fois qu’il y a un execute mais en vain. Toujours les mêmes problèmes.

Je sais que pour recopier une table dans une autre on peut directement faire une grande requête et utiliser fetchmany() mais on m’a demandé explicitement d’opérer de cette façon là.

J’espère que vous pourrez m’aider à y voir plus clair car j’ai beau à me casser la tête et à essayer de débugger le code je n’y arrive pas. Merci d’avance pour toute idée, clarification ou autre.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte