AWS RDS MySQL se ralentiza con el tiempo

AWS RDS MySQL se ralentiza con el tiempo

He leído muchas publicaciones sobre este tema, pero ninguna habla sobre la base de datos MySQL de AWS RDS. Desde hace tres días, estoy ejecutando un script de Python en una instancia AWS EC2 que escribe filas en mi base de datos MySQL de AWS RDS. Tengo que escribir 35 millones de filas, así que sé que esto llevará algún tiempo. Periódicamente verifico el rendimiento de la base de datos y tres días después (hoy) me doy cuenta de que la base de datos se está ralentizando. Cuando empezó, las primeras 100.000 filas se escribieron en sólo 7 minutos (este es un ejemplo de las filas con las que estoy trabajando)

0000002178-14-000056    AccountsPayableCurrent  us-gaap/2014        20131231    0   USD 266099000.0000

Después de tres días, se escribieron 5.385.662 filas en la base de datos, pero ahora se necesitan casi 3 horas para escribir 100.000 filas. ¿Lo que está sucediendo?

La instancia EC2 que estoy ejecutando es t2.small. Aquí puedes consultar las especificaciones si lo necesitas:ESPECIFICACIONES EC2 . La base de datos RDS que estoy ejecutando es db.t2.small. Consulta las especificaciones aquí:ESPECIFICACIONES DE RDS

Adjuntaré aquí algunos cuadros sobre el rendimiento de la base de datos y la instancia EC2: CPU de base de datos/Memoria de base de datos/IOPS de escritura de base de datos/Rendimiento de escritura de base de datos/ Red EC2 en (bytes)/Salida de red EC2 (bytes)

Sería genial si pudieras ayudarme. Muchas gracias.

EDITAR 1: ¿Cómo inserto filas? Como dije antes, tengo un script de Python ejecutándose en una instancia EC2, este script lee archivos de texto, hace algunos cálculos con estos valores y luego escribe cada fila "nueva" en la base de datos. Aquí hay una pequeña parte de mi código. ¿Cómo leo los archivos de texto?

for i in path_list:
  notify("Uploading: " + i)
  num_path = "path/" + i + "/file.txt"
  sub_path = "path/" + i + "/file.txt"

  try:
    sub_dict = {}
    with open(sub_path) as sub_file:
      for line in sub_file:
        line = line.strip().split("\t")
        sub_dict[line[0]] = line[1] # Save cik for every accession number
        sub_dict[line[1] + "-report"] = line[25] # Save report type for every CIK
        sub_dict[line[1] + "-frecuency"] = line[28] # Save frecuency for every CIK

    with open(num_path) as num_file:
      for line in num_file:
        num_row = line.strip().split("\t")

        # Reminder: sometimes in the very old reports, cik and accession number does not match. For this reason I have to write 
        # the following statement. To save the real cik.

        try: 
          cik = sub_dict[num_row[0]]
        except:
          cik = num_row[0][0:10]

        try: # If there is no value, pass
          value = num_row[7]
          values_dict = {
                  'cik': cik, 
                  'accession': num_row[0][10::].replace("-", ""),  
                  'tag': num_row[1], 
                  'value': value, 
                  'valueid': num_row[6], 
                  'date': num_row[4]
                  }

          sql = ("INSERT INTO table name (id, tag, value_num, value_id, endtime, cik, report, period) "
              "VALUES ('{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}')".format(
                  values_dict['cik'] + values_dict['accession'] + values_dict['date'] + values_dict['value'].split(".")[0] + "-" + values_dict['tag'], 
                  values_dict['tag'], 
                  float(values_dict['value']), 
                  values_dict['valueid'], 
                  values_dict['date'], 
                  int(values_dict['cik']), 
                  sub_dict[values_dict['cik'] + "-report"], 
                  sub_dict[values_dict['cik'] + "-frecuency"]
                  ))

          cursor.execute(sql)
          connection.commit()

Sé que no hay except:que catear las trydeclaraciones, pero esto es sólo una parte del guión. Creo que la parte importante es cómo inserto cada fila. En caso de que no necesite hacer cálculos con los valores, usaré Load Data Infilepara escribir los archivos de texto en la base de datos. Simplemente me doy cuenta de que tal vez no sea una buena idea commitcada vez que inserto una fila. Intentaré comprometerme después de aproximadamente 10.000 filas.

Respuesta1

Uso de instancias T2 y T3 (incluidas instancias db.t2 db.t3)Crédito de CPUsistema. Cuando la instancia está inactiva, acumula créditos de CPU que luego puede usar para ejecutarse más rápido durante períodos cortos de tiempo.Rendimiento explosivo. Una vez que agotas los créditos, se ralentiza a unRendimiento de referencia.

Una opción es habilitarT2/T3 Ilimitadoconfiguración en su configuración de RDS que permitirá que la instancia se ejecute a máxima velocidad durante el tiempo que sea necesario, pero pagará por los créditos adicionales necesarios.

La otra opción es cambiar el tipo de instancia a db.m5 o algún otro tipo que no sea T2/T3 que admita un rendimiento constante.

Aquí hay una más profundaexplicación de los créditos de la CPUy cómo se acumulan y gastan:¿Sobre aclarar las condiciones de trabajo t2 y t3?

Espero que ayude :)

Respuesta2

  • Las de una sola fila INSERTsson 10 veces más lentas que las de 100 filas INSERTso LOAD DATA.

  • Los UUID son lentos, especialmente cuando la tabla crece.

  • UNIQUEEs necesario comprobar los índices.antesterminando un iNSERT.

  • Los no únicos INDEXesse pueden hacer en segundo plano, pero aun así requieren algo de carga.

Proporcione SHOW CREATE TABLEel método utilizado para INSERTing. Puede que haya más consejos.

Respuesta3

Cada vez que confirma un índice de transacción, es necesario actualizarlo. La complejidad de actualizar un índice está relacionada con el número de filas de la tabla, por lo que a medida que aumenta el número de filas, la actualización del índice se vuelve progresivamente más lenta.

Suponiendo que está utilizando tablas InnoDB, puede hacer lo siguiente:

SET FOREIGN_KEY_CHECKS = 0;
SET UNIQUE_CHECKS = 0;
SET AUTOCOMMIT = 0;
ALTER TABLE table_name DISABLE KEYS;

Luego haga las inserciones, pero agrupelas de modo que una declaración inserte (por ejemplo) varias docenas de filas. Como INSERT INTO table_name VALUES ((<row1 data>), (<row2 data>), ...). Cuando las inserciones hayan terminado,

ALTER TABLE table_name ENABLE KEYS;
SET UNIQUE_CHECKS = 1;
SET FOREIGN_KEY_CHECKS = 1;
COMMIT;

Puede ajustar esto a su propia situación, por ejemplo, si la cantidad de filas es enorme, tal vez desee insertar medio millón y luego confirmar. Esto supone que su base de datos no está "activa" (es decir, los usuarios leen/escriben activamente en ella) mientras realiza las inserciones, porque está deshabilitando las comprobaciones en las que de otro modo podría confiar cuando ingresan datos.

información relacionada