Consulta Insert Lenta
Buenos Tardes.
En primer lugar me presento . Soy Jose Carlos un informático que esta aprendiendo a la vez que luchando con el mundo SQL y busco un poco vuestra ayuda. Actualmente me he encotnrado una query que se demora muchisimo y estoy seguro que tiene q existir otra forma de realizarla. No obstante no consigo encontrarla. La query en si es un Insert que en el where tiene una subquery para comprobar que no inserta dos veces lo mismo. He probado con group by y demas pero no consigo solucionar este "bucle" de insercion consulta insercion etc. Os pongo la query .
Muchas gracias de antemano por la ayuda |
Así, sólo con la SQL es bastante difícil saber dónde puede estar el problema.
Lo primero sería que comentaras con qué motor trabajas (esto por situarnos), luego lo suyo sería que intentarás acceder al PLAN DE EJECUCIÓN de la consulta. Si supueramos el gestor y kla herramientas que estás utilizando podríamos decirte cómo obtenerlo. Una vez visto el plan, deberías poder saber qué parte de la consulta está tardando más de la cuenta. El SELECT, la INSERCIÓN (triggers), las ORDENACIONES, el GROUP BY, la SUBSELECT,... Y una vez que sepas la parte que está tardando podrás intuir qué es lo que hay que optimizar. Imagino que tienes definidas PK's, índices,... |
Cita:
Hay maneras mucho mas faciles de solventar tu problema: - Podrias definir claves primarias compuestas - O podrias usar un trigger para validar la insercion Por otra parte, una consulta SQL de ese tamaño a mi me resulta alarmante Otros problemas que hacen que sea lenta es que usas mucho strings, convertis entre varios tipos de datos, y no es una subconsulta, son tres |
Es que eso no es un "insert", eso es un insert con un select anidado...
y un count distinct y un sum, y otro sum, y un count(*) !!! y otro exists con otro select anidado, y un not exists con otro select anidado... y un group by y todo aderezado de montones de campos de texto, concatenaciones de campos, ... No es un insert, es un desastre :D Me temo que tendrás que ir poco a poco, probando cada parte del código para ir mejorándolo y afinándolo. |
Ahi lo que veo mas problematico son los EXIST y mas que todo el NOT EXIST. Normalmente eso no es muy eficiente de hacer.
Que el SELECT de insercion sea "grande" no es en si el problema (es posible hacer inserciones de 1-4GB -dependiendo de motor y parametros- en unos <200 segundos en hardware medio medio, siempre y cuando todo este alineado ;) ). Asi que pon atencion a lo que te estan diciendo que eso se puede mejorar bastante... |
Explain Plan y Aclaraciones
Os comento un poco mas. Esta query ya existía en un PL SQL y me alarmo mucho. Y estoy intento optmizarla , por no decir hacerla bien. Al hacer prueba comprobé que uno de los principales problemas era el tema de comprobar si estaba insertado ya en al tabla en la que había insertado.
Aunque llevo dándole vueltas y se q esta mal , no se me ocurre que hacer.Por eso acudo a vuestra ayuda. Por cierto la info que me solicitabais . BBDD Oracle 10g Programa con el que trabajo TOAD Explain plan Plan Por cierto muchísimas gracias por la ayuda que dais. Un saludo |
Cita:
|
Clave
El problema es que en esa tabla se hacen otras inserciones que si pueden repetirse . Solo son las que vienen las de este insert las que no.
|
Cita:
|
Clave
No se puede repetir los que provienen de ese insert (para ser mas exacto de ese select) . Seguidamente tiene otros insert que se basan en select distintos y si podrían repetirse.
es decir al solucion de una clave , la contemple pero me encontré con ese problema. Lo que pensé como "solución intermedia" es una tabla temporal con la clave y después un insert con un select de la tabla temporal. La cosa es que me niego a pensar que sea la mejora solución.... |
Sigo sin entender. ¿Es un campo que no puede repetir datos si los inserta "un usuario", pero sí puede repetir datos si los inserta "otro usuario"?
Un campo admite/no admite repetir información, pero no vale eso de a veces sí y a veces no. ¿Cómo sabes que cuando se insertó estaba permitido que se repetiera o no? Está mal ideada la estructura... eso no puede funcionar así. |
Clave
Buenas Casimiro siento sino me he explicado bien.
Actualmente tengo una tabla TablaA esta tabla se rellena por varios insert (5 en total) Estos insert hacen select a tablas distintas: Insert INTO TABLA_A Select TablaB Insert INTO TABLA_A Select TablaGrande Insert INTO TABLA_A Select TablaC Insert INTO TABLA_A Select TablaD Insert INTO TABLA_A Select TablaE Al insertarlos solo me interesa que no se repitan los de la TablaGrande. Es decir pueden existir en TABLA_A dos personas iguales , siempre y cuando no provengan de las TABLA_GRANDE. Por este motivo no puedo poner clave, ya que de la tabla C y tabla D si pueden existir registros duplicados. Esta premisa es la que me rompe la cabeza. Ya que sino con las claves como bien dijiste se solucionaría el problema. Un saludo y de nuevo gracias por la ayuda y perdón por no explicarme bien desde el principio. |
Sigo sin entender, o tienes mal los conceptos. A ver si con un sencillo ejemplo nos entendemos.
Una tabla tiene campos, ejemplo: No quieres que se repita el campo nombre ¿es eso? Tienes varias opciones, pero NO VALE permitir nombres repetidos si lo hace "alguien" y no permitir nombres repetidos si lo hace "otro alguien" (Sea "alguien" lo que sea) Eso es básico. Esa lógica no puede variarse, salvo que quieras encontrarte con graves problemas. Y en tu caso necesitarás un campo para saber quién hace el insert y realizar unos controles u otros, dependiendo del caso. |
Veo que seguimos sin entendernos. jejejeje
No es un problema de conceptos. En la tabla_A en ningún momento he dicho que no se puedan repetir. Lo único que quiero es que no se repitan si viene de la TABLA_GRANDE. Un ejemplo Si tengo 5 controles de puertas y quiero tener un registro de quien ha entrado por cada puerta (A,B,C yD) y cuantas veces. Pero hay una puerta (TABLA_X) que es de paso y pasan demasiadas veces y solo me interesa saber si alguien ha pasado y no cuantas veces. Es decir en la tabla final , tendría Tabla A Juan Nuñez Juan Nuñez Tabla B Juan Nuñez Juan Nuñez Juan Nuñez Tabla X Juan Nuñez Juan Nuñez Juan Nuñez Pedro Perez Pedro Perez Pedro Perez Pedro Perez Pedro Perez Tabla C Juan Nuñez Juan Nuñez Pedro Perez Pedro Perez Pedro Perez Tabla X Juan Nuñez- puerta A Juan Nuñez- puerta A Juan Nuñez- puerta B Juan Nuñez- puerta B Juan Nuñez- puerta B Juan Nuñez- puerta C Juan Nuñez- puerta C Pedro Perez- puerta X Pedro Perez- puerta C Pedro Perez- puerta C Pedro Perez- puerta C Juan Nuñez como paso por otras antes no la ingreso, pero si me interesa saber todos sus registros. Pedro Perez no paso antes por ninguna y si varias veces por X . Ingreso solo 1 vez en la X y las veces de la otra. Es un ejemplo que se me acaba de ocurrir cercano a lo que busco. Espero que ahora este mas claro. Un saludo y muchas gracias |
Cita:
|
Porque son insert distintos. Que recogen los datos de tablas distintas.
|
Ya, pero eso lo sabes tú :D
El insert, la tabla, la base de datos, la sql, .... ¿cómo saben que viene de "tabla_grande" y no debe permitir repetidos y de los otros debe? |
Porque solo en el insert que pongo al principio del hilo es en el que hago la comprobación. El resto de insert se limitan a insertar los datos recogidos
|
Veamos, un día estás revisando datos y te encuentras con:
Cita:
|
Porque hay otra columna que t dice de donde viene. En el ejemplo ponía puerta a. Por ejemplo.
|
Cita:
Enfocate en el PLAN porque esto es lo mas clave. No tengo ni idea de ORACLE, nunca lo he usado pero todos los RDBMS siguen unas lineas universales. Leyendo el plan (y que conste que me voy por pura intuición!): https://docs.oracle.com/database/121...htm#TGSQL94854 1- Estas accesando un servidor REMOTO mediante un link. REMOTE REMOTE Esto me parece que a la larga es lo mas critico. Si el servidor esta fuera de una red interna con una excelente conectividad (donde el Throughput sea constante) esto podria ser una fuente cuasi-invisible de problemas. Las redes tienden a tener velocidad variable, y un analisis de promedios siempre sera errado. Puedes usar una tarea que jale esos datos de forma continua y poner todo local? Ademas, no se como rayos hace ORACLE aqui y si ese LINK es contra otro ORACLE, pero dudo que pueda ver los indices y estadisticas del servidor remoto. 2- NESTED LOOPS es un indicativo que el motor no puede beneficiarse de indices ni de las estadisticas de rendimiento. Esto es RE-MALO, porque es un JOIN que sera EXPONENCIAL: http://use-the-index-luke.com/sql/jo...oin-n1-problem (Enormemente te recomiendo que estudies no solo este link, sino este sitio). 3- TABLE ACCESS FULL TABLE Es un table-scan, o sea, no hay indice ni estadisticas, es menos malo que un NESTED LOOP porque no es un join, y es malo A MENOS QUE los datos que jale sean pocos, sean sequenciales. Esto es lo mas notable del PLAN. Casi siempre los costos de SORT y GROUP seran secundarios y solo parecerán problemas cuando se combinan con table scans y loops. ----------- La clave para el desempeño en toda BD, y en especial, el modelo relacional, es tener un esquema bien diseñado (o sea, SANO). Una BD al igual que un humano es feliz si los datos son UNICOS, ASCENDENTES, DIFERENCIADOS y CONTINUOS. Eso es lo que en términos mas técnicos logra los pasos de normalizar y desnormalizar la información. Luego el uso adecuado de INDICES+NORMALIZACION para el lado de LECTURA, pero para el de INGESTA/ESCRITURA/MASIVO es lo *contrario*: Si puedes prescindir de indices y desnormalizar mucho mejor. Esto es la indicacion de que hacer cuando se esta agregando mucho dato de muchas fuentes con potencialmente ninguna posibilidad de indices y todo eso (por ejemplo, cuando los datos vienen de texto plano): Es mejor poder *TRAGAR RAPIDO* contra una tabla sin indices y desnormalizada, luego *agregar indices* y luego jalar de esa para el resto de los pasos. Asi es como se hace en un datawharehouse. Ahora bien, eso es un batch, y muchas veces si los datos son pocos (unos cuantos GB por ingesta) o se quiere ser "casi tiempo real" entonces lo que debes es armar una "linea fluida de datos (data pipeline)", lo cual es con buen hardware (ideal disco SSD y RAM >32GB) y/o poder jalar en STREAMS constantes particionados. ------- Dejando la teoria: Si el acceso remoto no se puede obviar, intenta DESNORMALIZAR ALLA MISMO!. Ten los datos "pre-amasados" quizas usando una VISTA MATERIALIZADA: https://docs.oracle.com/cd/B10501_01...7/repmview.htm Una vez que tienes los datos preparados, en el lado de lectura revisa el tema de los indices y ten en cuenta lo explicado. ----- Ahora si los datos van a crecer bastante, hacer todo desde el motor puede ser un problema (si ademas ese esta encargado de servir el lado transaccional) y puede que te toque mejor armar un PIPELINE, que es eso? Un programa que de forma continua vaya alimentando la tabla destino desde las de lectura pero fuera del motor y que pueda operar "lento" pero con una rata constante de memoria/cpu. Pero ojo, solo si esto amerita por el aumento constante de la ingesta. |
Guau . Me pongo ahora mismo a estudiar todo lo que me mandas.
Muchisimas gracias por el tiempo que te ha tomado. Actualizare con lo que logre. Si alguien tiene alguna otra idea , estoy abierto a mas sugerencias. |
Divide y vencerás, esa es la idea que puedo ofrecerte. Te imaginas una vez soluciones ese problema y tengas una instruccion Sql de ese tamaño, pasado tres meses tengas que solucionar algún error en la aplicación que tenia ducha consulta, tu crees que vas a entender que hacia ducha consulta, a menos que la documentes muy bien. Solo digo que es preferible trabajar un poco mas y dividir hasta donde nos permita la aplicación, la ingeniería del software y el análisis y diseño de sistemas, ya que el 60% del tiempo se consume en mantenimiento, osea mas que el desarrollo. Que quiero decir con esto que debemos poner esfuerzo en que nuestras aplicaciones sean fácil de mantener y modificar para que tengan una vida util.
Enviado desde mi SM-G900H mediante Tapatalk |
Hola,
yo haría lo siguiente: 1.- Ejecutar la consulta sólo, ya te meterás con el insert luego. 2.- Tomar el tiempo 3.- Cambiar los EXISTS y NOT EXISTS por cláusulas left join o similar. Te supondrá un poco de trabajo pero creo que puede ser más efciente. 4.- Una vez hecho esto, probar a cambiar el orden de las cláusulas de las where, para ver si dependiendo del mismo te utiliza índices o no. Si no sabes cómo, pregunta. Ya nos dirás. Saludos
|
La franja horaria es GMT +2. Ahora son las 17:37:03. |
Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi