Pregunto porque muchas de las preguntas que veo en SQL equivalen a: "Esto es lento. ¿Cómo puedo acelerarlo?" ¿O hay tutoriales que dicen "Haz esto de esta manera y no de esa manera ya que es más rápido".
Me parece que una gran parte de SQL es saber cómo se realizaría una expresión y, a partir de ese conocimiento, elegir estilos de expresión que funcionen mejor. Esto no cuadra con un aspecto de la programación declarativa: el de dejar el sistema para decidir la mejor manera de realizar el cálculo con usted, solo especificando qué debe producir el cálculo.
¿No debería importarle un motor SQL si lo usó in
, exists
o join
si es verdaderamente declarativo, no debería simplemente darle la respuesta correcta en un tiempo razonable si es posible por cualquiera de los tres métodos? Este último ejemplo es impulsado por esta publicación reciente que es del tipo mencionado en mi párrafo inicial.
Índices
Supongo que el ejemplo más fácil que podría haber usado se relaciona con la creación de un índice para una tabla. El error aquí en w3schools.com incluso trata de explicarlo como algo invisible para el usuario que está allí por razones de rendimiento. Su descripción parece colocar índices SQL en el campo no declarativo y se agregan a mano de forma rutinaria por razones puramente de rendimiento.
¿Es el caso de que su lugar es un DB SQL ideal que es mucho más declarativo que el resto, pero porque es bueno que uno no se entere?
fuente
select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)
. Debería ser trivial ver cómo reafirmar eso con unexists
o ajoin
.Respuestas:
SQL es teóricamente declarativo. Pero sabes lo que dicen sobre la diferencia entre teoría y práctica ...
En esencia, el concepto de "programación declarativa" nunca ha sido realmente efectivo, y probablemente nunca lo será hasta que tengamos un compilador basado en IA que sea capaz de mirar el código y responder a la pregunta "¿cuál es la intención de este código?" inteligentemente, de la misma manera que lo haría la persona que lo escribió. En el corazón de cada lenguaje declarativo hay un montón de código imperativo que intenta frenéticamente resolver ese problema sin la ayuda de una IA.
A menudo funciona sorprendentemente bien, porque los casos más comunes son casos comunes , que las personas que escribieron la implementación del lenguaje conocían y encontraron buenas maneras de manejarlo. Pero luego se encuentra con un caso límite que el implementador no consideró, y ve que el rendimiento se degrada rápidamente ya que el intérprete se ve obligado a tomar el código mucho más literalmente y manejarlo de una manera menos eficiente.
fuente
I rarely hit an edge case in any of them that couldn't be solved within the framework.
Sí, ese es el punto: tener que encontrar una manera de resolverlos dentro del marco porque el marco no es lo suficientemente inteligente como para resolverlo de la manera en que lo declaró originalmente.Estaba pensando en esto hace unos días después de una optimización de SQL. Creo que podemos estar de acuerdo en que SQL es un "lenguaje declarativo" en la definición de Wikipedia:
Si piensa cuántas cosas se hacen detrás de las cortinas (mirar estadísticas, decidir si un índice es útil, buscar una unión anidada, combinada o hash, etc.), debemos admitir que solo damos un alto nivel lógica, y la base de datos se encargó de toda la lógica de flujo de control de bajo nivel.
También en este escenario, a veces el optimizador de la base de datos necesita algunas "sugerencias" del usuario para dar los mejores resultados.
Otra definición común de lenguaje "declarativo" es (no puedo encontrar una fuente autorizada):
Si aceptamos esta definición, nos encontramos con los problemas descritos por el OP.
El primer problema es que SQL nos brinda múltiples formas equivalentes de definir "el mismo resultado". Probablemente sea un mal necesario: cuanto más poder expresivo le otorguemos a un idioma, es más probable que tenga diferentes formas de expresar lo mismo.
Como ejemplo, una vez me han pedido que optimice esta consulta:
Como los tipos eran mucho menos que el cliente y había un índice en la
cust_type
tabla de clientes, he logrado una gran mejora al reescribirlo como:En este caso específico, cuando le pregunté al desarrollador qué quería lograr, él me dijo "Quería todos los tipos de clientes para los que tenía al menos un cliente", que por cierto es exactamente cómo se podría describir la consulta del optimizador.
Entonces, si pudiera encontrar una consulta equivalente y más eficiente, ¿por qué el optimizador no puede hacer lo mismo?
Mi mejor conjetura es que es por dos razones principales:
SQL expresa lógica:
dado que SQL expresa una lógica de alto nivel, ¿realmente queremos que el optimizador nos "engañe" a nosotros y a nuestra lógica? Gritaría con entusiasmo "sí" si no fuera por todas las veces que tuve que forzar al optimizador a elegir la ruta de ejecución más eficiente. Creo que la idea podría ser permitir que el optimizador haga su mejor esfuerzo (también revisando nuestra lógica) pero dándonos un "mecanismo de pista" para que salga al rescate cuando algo se vuelva loco (sería como tener la rueda + frenos en Un coche autónomo).
Más opciones = más tiempo
Incluso el mejor optimizador RDBMS no prueba TODAS las rutas de ejecución posibles, ya que deben ser realmente rápidas: ¿qué tan bueno sería optimizar una consulta de 100ms a 10ms si necesito pasar cada 100ms eligiendo la mejor ruta? Y eso es con el optimizador respetando nuestra "lógica de alto nivel". Si también probara todas las consultas SQL equivalentes, el tiempo del optimizador podría crecer varias veces.
Otro buen ejemplo de reescritura de consultas que no es capaz de hacer RDBMS es (de esta interesante publicación de blog )
de lo que se puede escribir así (se requieren funciones analíticas)
fuente