shopkeeper
la tabla tiene los siguientes campos:
id (bigint),amount (numeric(19,2)),createddate (timestamp)
Digamos que tengo la tabla anterior. Quiero obtener los registros de ayer y generar un informe al tener la cantidad impresa en centavos.
Una forma de hacerlo es realizar cálculos en mi aplicación Java y ejecutar una consulta simple
Date previousDate ;// $1 calculate in application
Date todayDate;// $2 calculate in application
select amount where createddate between $1 and $2
y luego recorrer los registros y convertir la cantidad a centavos en mi aplicación Java y generar el informe
Otra forma es como realizar cálculos en la consulta sql misma:
select cast(amount * 100 as int) as "Cents"
from shopkeeper where createddate between date_trunc('day', now()) - interval '1 day' and date_trunc('day', now())
y luego recorrer los registros y generar el informe
De una manera, todo mi procesamiento se realiza en la aplicación Java y se activa una consulta simple. En otro caso, todas las conversiones y cálculos se realizan en la consulta SQL.
El caso de uso anterior es solo un ejemplo, en un escenario real, una tabla puede tener muchas columnas que requieren un procesamiento similar.
¿Puede decirme qué enfoque es mejor en términos de rendimiento y otros aspectos y por qué?
fuente
Respuestas:
Depende de muchos factores, pero lo más importante:
Como siempre, si lo hace traer la parte posterior de datos de la aplicación en el servidor, reduciendo al mínimo las columnas y filas será a su ventaja. Asegurarse de que la consulta esté ajustada e indexada adecuadamente ayudará a cualquier escenario.
Re su nota:
Recorrer los registros casi siempre es algo incorrecto en sql: se prefiere escribir una operación basada en conjuntos.
Como regla general , prefiero mantener el trabajo de la base de datos al mínimo "almacenar estos datos, obtener estos datos"; sin embargo, siempre hay ejemplos de escenarios en los que una consulta elegante en el servidor puede ahorrar mucho ancho de banda.
También considere: si esto es computacionalmente costoso, ¿se puede almacenar en caché en algún lugar?
Si desea una precisa "que es mejor"; codifíquelo en ambos sentidos y compárelo (señalando que un primer borrador de cualquiera de los dos probablemente no esté 100% sintonizado). Pero tenga en cuenta el uso típico de eso: si, en realidad, se llama 5 veces (por separado) a la vez, simule eso: no compare un solo "1 de estos frente a 1 de esos".
fuente
Permítanme usar una metáfora: si quieren comprar un collar de oro en París, el orfebre podría sentarse en Ciudad del Cabo o París, eso es cuestión de habilidad y gusto. Pero nunca enviarías toneladas de mineral de oro desde Sudáfrica a Francia por eso. El mineral se procesa en el sitio minero (o al menos en el área general), solo se envía el oro. Lo mismo debería ser cierto para aplicaciones y bases de datos.
En lo que respecta a PostgreSQL , puede hacer casi cualquier cosa en el servidor, de manera bastante eficiente. El RDBMS sobresale en consultas complejas. Para necesidades de procedimiento, puede elegir entre una variedad de lenguajes de script del lado del servidor : tcl, python, perl y muchos más. Sin embargo, sobre todo uso PL / pgSQL .
El peor de los casos sería ir repetidamente al servidor para cada fila de un conjunto más grande. (Eso sería como enviar una tonelada de mineral a la vez).
En segundo lugar , si envía una cascada de consultas, cada una dependiendo de la anterior, mientras que todo se puede hacer en una consulta o procedimiento en el servidor. (Eso es como enviar el oro y cada una de las joyas con un barco separado, secuencialmente).
Ir y venir entre la aplicación y el servidor es costoso. Para servidor y cliente. Intente reducir eso, y ganará: ergo: utilice procedimientos del lado del servidor y / o SQL sofisticado cuando sea necesario.
Acabamos de terminar un proyecto donde empaquetamos casi todas las consultas complejas en las funciones de Postgres. La aplicación entrega parámetros y obtiene los conjuntos de datos que necesita. Rápido, limpio, simple (para el desarrollador de la aplicación), la E / S se reduce al mínimo ... un collar brillante con una baja huella de carbono.
fuente
En este caso, probablemente sea un poco mejor hacer el cálculo en SQL, ya que es probable que el motor de la base de datos tenga rutinas aritméticas decimales más eficientes que Java.
Generalmente, sin embargo, para los cálculos de nivel de fila no hay mucha diferencia.
Donde sí hace la diferencia es:
fuente
No hay blanco / negro con respecto a qué partes de la lógica de acceso a datos deben realizarse en SQL y qué partes deben realizarse en su aplicación. Me gusta la redacción de Mark Gravell , distinguiendo entre
El poder y la expresividad de SQL están muy subestimados. Desde la introducción de las funciones de ventana , se pueden realizar muchos cálculos no estrictamente orientados a conjuntos de manera muy fácil y elegante en la base de datos.
Siempre se deben seguir tres reglas generales, independientemente de la arquitectura general de la aplicación:
En mi experiencia, con un DBA decente y un conocimiento decente sobre su base de datos decente, no se encontrará con los límites de CPU de sus DB muy pronto.
Algunas lecturas adicionales donde se explican estas cosas:
fuente
En general, haga las cosas en SQL si hay posibilidades de que también otros módulos o componentes en el mismo u otros proyectos necesiten obtener esos resultados. una operación atómica realizada en el lado del servidor también es mejor porque solo necesita invocar el proceso almacenado desde cualquier herramienta de administración de db para obtener valores finales sin más procesamiento.
En algunos casos esto no se aplica, pero cuando lo hace tiene sentido. También en general, el db box tiene el mejor hardware y rendimiento.
fuente
Si está escribiendo sobre ORM o escribiendo aplicaciones casuales de bajo rendimiento, use cualquier patrón que simplifique la aplicación. Si está escribiendo una aplicación de alto rendimiento y está pensando cuidadosamente en la escala, ganará moviendo el procesamiento a los datos. Recomiendo encarecidamente mover el procesamiento a los datos.
Pensemos en esto en dos pasos: (1) transacciones OLTP (pequeño número de registros). (2) OLAP (escaneos largos de muchos registros).
En el caso de OLTP, si desea ser rápido (10k - 100k transacciones por segundo), debe eliminar la contención de bloqueo, bloqueo y bloqueo muerto de la base de datos. Esto significa que necesita eliminar largas paradas en las transacciones: los viajes de ida y vuelta desde el cliente a la base de datos para mover el procesamiento al cliente son una de esas paradas largas. No puede tener transacciones de larga duración (para hacer lectura / actualización atómica) y tener un rendimiento muy alto.
Re: escala horizontal. Las bases de datos modernas se escalan horizontalmente. Esos sistemas ya implementan HA y tolerancia a fallas. Aproveche eso e intente simplificar el espacio de su aplicación.
Veamos OLAP: en este caso, debería ser obvio que arrastrar posiblemente terrabytes de datos de vuelta a la aplicación es una idea horrible. Estos sistemas están diseñados específicamente para operar de manera extremadamente eficiente contra datos en columnas comprimidos y preorganizados. Los sistemas OLAP modernos también se escalan horizontalmente y tienen sofisticados planificadores de consultas que dispersan el trabajo horizontalmente (moviendo internamente el procesamiento a los datos).
fuente
Si realizar cálculos en el front-end o en el backend está muy decidido si podemos determinar nuestro objetivo en la implementación del negocio. En algún momento, el código Java podría funcionar mejor que un código SQL bien escrito o viceversa. Pero aún si está confundido, puede intentar determinar primero:
Hay muchos otros aspectos que puede pensar antes de decidir dónde colocar el código. Una percepción es totalmente errónea: todo se puede hacer mejor en Java (código de la aplicación) y / o todo se puede hacer mejor con el db (código sql).
fuente
Forme un punto de vista de rendimiento: esta es una operación aritmética muy simple que casi con certeza se puede realizar mucho más rápido que en realidad obtener los datos de los discos que subyacen en la base de datos. Además, calcular los valores en la cláusula where es probable que sea muy rápido en cualquier tiempo de ejecución. En resumen, el cuello de botella debe ser el disco IO, no el cálculo de los valores.
Según la legibilidad, creo que si usa un ORM, debe hacerlo en el entorno del servidor de aplicaciones, porque el ORM le permitirá trabajar con los datos subyacentes muy fácilmente, utilizando operaciones basadas en conjuntos. Si va a escribir SQL sin formato de todos modos, no hay nada de malo en hacer el cálculo allí, su SQL también se vería un poco mejor y más fácil de leer si se formatea correctamente.
fuente
Crucialmente, el "rendimiento" no está definido.
El que más me importa es el tiempo de desarrollador.
Escribe la consulta SQL. Si es demasiado lento o el DB se convierte en un cuello de botella, reconsidere. En ese momento, podrá comparar los dos enfoques y tomar una decisión basada en datos reales relevantes para su configuración (hardware y cualquier pila en la que se encuentre).
fuente
No creo que se puedan razonar las diferencias de rendimiento sin ejemplos y puntos de referencia específicos, pero tengo otra opinión:
¿Cuál puedes mantener mejor? Por ejemplo, es posible que desee cambiar su front-end de Java a Flash, o HTML5, o C ++, o algo más. Una gran cantidad de programas han pasado por ese cambio, o incluso existen en más de un idioma, para empezar, porque necesitan trabajar en múltiples dispositivos.
Incluso si tiene una capa intermedia adecuada (del ejemplo dado, parece que ese no es el caso), esa capa podría cambiar y JBoss podría convertirse en Ruby / Rails.
Por otro lado, es poco probable que reemplace el back-end de SQL con algo que no sea una base de datos relacional con SQL e incluso si lo hace, tendrá que volver a escribir el front-end desde cero, por lo que el punto es discutible.
Mi idea es que si haces cálculos en la base de datos, será mucho más fácil escribir una segunda capa frontal o intermedia más adelante, porque no tienes que volver a implementar todo. Sin embargo, en la práctica, creo que "dónde puedo hacer esto con un código que la gente entienda" es el factor más importante.
fuente
Para simplificar cómo responder a esto sería mirar el equilibrio de carga. Desea colocar la carga donde tenga la mayor capacidad (si tiene sentido). En la mayoría de los sistemas, es el servidor SQL el que rápidamente se convierte en un cuello de botella, por lo que la respuesta probable es que no desea que SQL haga una onza de trabajo más de lo necesario.
También en la mayoría de las arquitecturas son los servidores SQL los que constituyen el núcleo del sistema y los sistemas externos que se agregan.
Pero la matemática anterior es tan trivial que, a menos que esté presionando su sistema al límite, el mejor lugar para colocarlo es donde desea colocarlo. Si las matemáticas no fueran triviales, como calcular sen / cos / tan para, por ejemplo, un cálculo de distancia, entonces el esfuerzo podría no ser trivial y requerir una planificación y prueba cuidadosas.
fuente
Las otras respuestas a esta pregunta son interesantes. Sorprendentemente, nadie ha respondido su pregunta. Te preguntas:
Más información: Para la pregunta uno, desea asegurarse de que agregar las fracciones funciona sin errores de redondeo. Creo que el valor numérico 19,2 es razonable para el dinero y en el segundo caso los enteros están bien. Usar un flotador por dinero está mal por esta razón.
Para la pregunta dos, me gusta tener el control total como programador de la fecha que se considera "ahora". Puede ser difícil escribir pruebas unitarias automáticas cuando se utilizan funciones como now (). Además, cuando tiene un script de transacción más largo, puede ser bueno establecer una variable igual a now () y usar la variable para que toda la lógica use exactamente el mismo valor.
fuente
Permítanme tomar un ejemplo real para abordar esta pregunta.
Necesitaba calcular un promedio móvil ponderado en mis datos de OHL, tengo alrededor de 134000 velas con un símbolo para cada una.
¿Cuál es mejor?
Requisitos
Para alentarlo, esta es la versión de Python para hacer un promedio móvil ponderado
WMA hecho a través del código
WMA a través de SQL
¡Lo creas o no, la consulta se ejecuta más rápido que la versión Pure Python de hacer un PROMEDIO DE MOVIMIENTO PONDERADO! Fui paso a paso a escribir esa consulta, así que aguanta y harás bien
Velocidad
0.42141127300055814 segundos Python
0.23801879299935536 segundos SQL
Tengo 134000 registros OHLC falsos en mi base de datos divididos entre 1000 acciones, por lo que es un ejemplo de dónde SQL puede superar a su servidor de aplicaciones
fuente