Soy un novato en las bases de datos pero tengo un problema que parece que no puedo resolver. Lo siento de antemano si esto es demasiado largo, estoy tratando de resumir todos mis esfuerzos para que sepa exactamente lo que he hecho hasta ahora. Tengo una aplicación que tiene un poco de lógica y luego hace 3 consultas a una base de datos. La primera consulta verifica si existe un valor, segundo comprueba si existe otro valor (relacionado) y el tercero, si no existe, agrega un valor relacionado. Piense en mí haciendo una consulta sobre el número 2, y si existe, verifico 3 y lo agrego si es necesario. Hago este ciclo una gran cantidad de veces (estoy viendo consultas generales pero sospecho que este programa es más pesado que leído). Solía usar solo una tabla hash en mi programa, pero como agregué varios procesos tuve problemas de sincronización, así que decidí usar una base de datos para que varios núcleos puedan trabajar en esto al mismo tiempo.¿Cómo puedo aumentar las consultas de lectura/segundo en mi base de datos?
Al principio probé, mysql y usé un motor de almacenamiento de memoria (todo cabía en la memoria), hice una clave primaria compuesta para replicar el diccionario que tenía en mi programa, lo indexé, deshabilité el bloqueo pero solo pude obtener alrededor de 11,000 consultas/segundo de eso.
Probé Redis (escuché que era como Memcache) y creé la misma clave/valor dict que tengo antes (aquí está el modo real Can I make two columns unique to each other? or use composite primary key's in redis?) y eliminé todas las cosas de fsync, así que espero que nunca llegue al disco duro I/O pero todavía solo obtiene alrededor de 30,000 consultas/segundo. Miré las mejoras del sistema (estoy usando Linux) haciendo que el programa se ejecute en un ramdrive, etc. pero el resultado es similar.
Tengo un script de configuración e intenté hacer esto en ec2 usando la instancia de cpu alta pero el resultado es similar (las consultas no aumentan mucho para ambas soluciones). Estoy algo desconcertado, pero no quiero rendirme porque leo sobre personas en stackoverflow hablando de cómo han obtenido 100,000k + consultas en una versión independiente. Siento que mi modelo de datos es muy simple (dos columnas de INT o I pueden hacer que sea una cadena con ambas INT combinadas, pero eso no parece disminuir la velocidad) y una vez que los datos son creados (y consultados por otro proceso) tengo no hay necesidad de persistencia (que es también la razón por la que intento no escribir en un disco duro). ¿Qué configuración me falta que permita a los desarrolladores obtener este tipo de rendimiento? ¿Se requiere alguna configuración especial fuera de la creación de la tabla? o es la única forma de obtener ese tipo de rendimiento a través de bases de datos distribuidas? Sé que el problema está en la base de datos porque cuando apago el proceso medio de la base de datos mi aplicación de Python llega al 100% en cada núcleo que se ejecuta (aunque no escribe nada), me hace pensar que el proceso de espera (para las lecturas, Sospecho) es lo que está desacelerando (tengo un montón de memoria/CPU libre, así que me pregunto por qué no está maximizando, tengo 50% de CPU y 80% de mi memoria libre durante estos trabajos, así que no tengo ni idea que esta pasando).
Tengo mysql, redis y hbase. Espero que haya algo que pueda hacer para que una de estas soluciones funcione tan rápido como me gustaría, pero si no lo hago, estoy de acuerdo con cualquier solución (en realidad es solo una tabla temporal que los procesos distribuidos pueden consultar).
¿Qué puedo hacer?
Gracias!
Actualización: como se solicita en los comentarios, aquí hay un código (después de la lógica de la aplicación específica que parece ir bien):
cursor.execute(""" SELECT value1 FROM data_table WHERE key1='%s' AND value1='%s' """ % (s - c * x, i))
if cursor.rowcount == 1:
cursor.execute(""" SELECT value1 FROM data_table WHERE key1='%s' AND value1='%s' """ % (s, i+1))
if cursor.rowcount == 0:
cursor.execute (""" INSERT INTO data_table (key1, value1) VALUES ('%s', '%s')""" % (s, i+1))
conn.commit() #this maybe not needed
#print 'commited ', c
anterior es el código con 3 búsquedas en MySQL.También he intentado hacer una gran consulta (pero era de hecho más lento):
cursor.execute ("""
INSERT INTO data_table (key1, value1)
SELECT '%s', '%s'
FROM dual
WHERE (SELECT COUNT(*) FROM data_table WHERE key1='%s' AND value1='%s')
= 1
AND NOT EXISTS
(SELECT * FROM data_table WHERE key1='%s' AND value1='%s')
""" % ((s), (i+1), (s - c * x), (i), (s), (i+1)))
Aquí está el diseño de la tabla de MySQL:
cursor.execute ("DROP TABLE IF EXISTS data_table")
cursor.execute ("""
CREATE TABLE data_table(
key1 INT SIGNED NOT NULL,
value1 INT SIGNED NOT NULL,
PRIMARY KEY (key1,value1)
) ENGINE=MEMORY
""")
cursor.execute("CREATE INDEX ValueIndex ON data_table (key1, value1)")
en Redis, su simlair a la estructura 3 consulta (ya fue el más rápido que pude conseguir en MySQL, excepto que no necesito hacer una búsqueda si el valor existe, sólo sobreescribirla guardar una consulta):
if r_server.sismember(s - c * x, i):
r_server.sadd(s, i + 1)
Mi estructura de datos para Redis es en el relacionado pregunta (básicamente es al ist, 3 => 1 2 3 en lugar de mysql que tiene 3 filas para volver a aplicar 3 = 1, 3 = 2, 3 = 3.
Espero que ayude, cualquier otra pregunta, por favor hágamelo saber.
Es posible que pueda lograr esto con una consulta optimizada, guardando viajes redondos a la base de datos. Necesitamos más información, como las consultas, el esquema y la lógica. –
@MarcusAdams Gracias por el comentario. Actualicé la pregunta con mi código mysql y redis. – Lostsoul