Necesito escribir una consulta para recuperar una gran lista de identificadores.
Admitimos muchos backends (MySQL, Firebird, SQLServer, Oracle, PostgreSQL ...), así que necesito escribir un SQL estándar.
El tamaño del conjunto de identificación podría ser grande, la consulta se generaría mediante programación. Entonces, ¿cuál es el mejor enfoque?
1) Escribir una consulta usando IN
SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)
Mi pregunta aquí es. ¿Qué pasa si n es muy grande? Además, ¿qué pasa con el rendimiento?
2) Escribir una consulta usando OR
SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn
Creo que este enfoque no tiene límite n, pero ¿qué pasa con el rendimiento si n es muy grande?
3) Escribir una solución programática:
foreach (var id in myIdList)
{
var item = GetItemByQuery("SELECT * FROM TABLE WHERE ID = " + id);
myObjectList.Add(item);
}
Experimentamos algunos problemas con este enfoque cuando se consulta el servidor de la base de datos a través de la red. Normalmente es mejor hacer una consulta que recupere todos los resultados en lugar de hacer muchas consultas pequeñas. Puede ser que esté equivocado.
¿Cuál sería una solución correcta para este problema?
IN
! Hice la mía como su solución 1 + 3. Solo la consulta final fue una, cadena de consulta larga enviada a SQL para ejecutar.Respuestas:
La opción 1 es la única buena solución.
¿Por qué?
La opción 2 hace lo mismo pero repite el nombre de la columna muchas veces; Además, el motor SQL no sabe de inmediato que desea comprobar si el valor es uno de los valores de una lista fija. Sin embargo, un buen motor SQL podría optimizarlo para tener el mismo rendimiento que con
IN
. Sin embargo, todavía hay un problema de legibilidad ...La opción 3 es simplemente horrible en cuanto al rendimiento. Envía una consulta cada bucle y martilla la base de datos con pequeñas consultas. También evita que use optimizaciones para "el valor es uno de esos en una lista dada"
fuente
Un enfoque alternativo podría ser utilizar otra tabla para contener valores de identificación. Esta otra tabla se puede unir internamente en su TABLE para restringir las filas devueltas. Esto tendrá la gran ventaja de que no necesitará SQL dinámico (problemático en el mejor de los casos), y no tendrá una cláusula IN infinitamente larga.
Truncaría esta otra tabla, insertaría su gran número de filas y luego crearía un índice para ayudar al rendimiento de la unión. También le permitiría separar la acumulación de estas filas de la recuperación de datos, quizás ofreciéndole más opciones para ajustar el rendimiento.
Actualización : aunque podría usar una tabla temporal, no quise decir que debiera o incluso debería. Una tabla permanente utilizada para datos temporales es una solución común con méritos más allá de lo descrito aquí.
fuente
select
declaración en otra tabla. La lista se pasa como la otra tablainner join
contra la que se está enfrentando.Lo que sugirió Ed Guiness es realmente un refuerzo de rendimiento, tuve una consulta como esta
lo que hice :
Luego interior se unió a la temperatura con la mesa principal:
Y el rendimiento mejoró drásticamente.
fuente
La primera opción es definitivamente la mejor opción.
Sin embargo, teniendo en cuenta que la lista de identificadores es muy grande , digamos millones, debe considerar los tamaños de fragmentos como a continuación:
¿Por qué deberías dividirte en trozos?
Siempre ha funcionado a las mil maravillas para mí. Espero que funcione para mis compañeros desarrolladores también :)
fuente
¡Hacer el comando SELECT * FROM MyTable where id in () en una tabla Azure SQL con 500 millones de registros resultó en un tiempo de espera de> 7min!
Hacer esto en su lugar devolvió los resultados de inmediato:
Usa una unión.
fuente
En la mayoría de los sistemas de bases de datos,
IN (val1, val2, …)
y una serie deOR
están optimizados para el mismo plan.La tercera forma sería importar la lista de valores en una tabla temporal y unirla, que es más eficiente en la mayoría de los sistemas, si hay muchos valores.
Es posible que desee leer estos artículos:
fuente
El ejemplo 3 sería el peor de todos porque está accediendo a la base de datos innumerables veces sin razón aparente.
Cargar los datos en una tabla temporal y luego unirse a ellos sería, con mucho, el más rápido. Después de eso, el IN debería funcionar un poco más rápido que el grupo de OR.
fuente
Creo que te refieres a SqlServer, pero en Oracle tienes un límite estricto de cuántos elementos IN puedes especificar: 1000.
fuente