Saltar al contenido

Errores de desarrollo de bases de datos cometidos por desarrolladores de aplicaciones

Nuestro equipo de expertos despúes de algunos días de trabajo y de recopilar de información, obtuvimos la respuesta, queremos que resulte útil para ti para tu trabajo.

Solución:

1. No utilizar índices adecuados

Este es relativamente fácil, pero aún sucede todo el tiempo. Las claves externas deben tener índices. Si está utilizando un campo en un WHERE deberías (probablemente) tener un índice. Dichos índices a menudo deberían cubrir varias columnas en función de las consultas que necesita ejecutar.

2. No hacer cumplir la integridad referencial

Su base de datos puede variar aquí, pero si su base de datos admite integridad referencial, lo que significa que se garantiza que todas las claves externas apunten a una entidad que existe, debería usarla.

Es bastante común ver este error en las bases de datos MySQL. No creo que MyISAM lo admita. InnoDB lo hace. Encontrará personas que están usando MyISAM o aquellas que están usando InnoDB pero que no lo están usando de todos modos.

Más aquí:

  • ¿Qué importancia tienen las restricciones como NOT NULL y FOREIGN KEY si siempre controlaré la entrada de mi base de datos con php?
  • ¿Son realmente necesarias las claves externas en el diseño de una base de datos?
  • ¿Son realmente necesarias las claves externas en el diseño de una base de datos?

3. Uso de claves primarias naturales en lugar de sustitutas (técnicas)

Las claves naturales son claves basadas en datos externos significativos que son (aparentemente) únicos. Algunos ejemplos comunes son los códigos de producto, los códigos de estado de dos letras (EE. UU.), Los números de seguro social, etc. Las claves primarias técnicas o sustitutas son aquellas que no tienen ningún significado fuera del sistema. Se inventan únicamente para identificar la entidad y normalmente son campos de incremento automático (SQL Server, MySQL, otros) o secuencias (sobre todo Oracle).

En mi opinión deberías siempre utilizar claves sustitutas. Este problema ha surgido en estas preguntas:

  • ¿Qué le parecen sus claves principales?
  • ¿Cuál es la mejor práctica para las claves primarias en tablas?
  • ¿Qué formato de clave principal usaría en esta situación?
  • Claves sustitutas frente a claves naturales / comerciales
  • ¿Debería tener un campo de clave principal dedicado?

Este es un tema algo controvertido sobre el que no obtendrá un acuerdo universal. Si bien puede encontrar algunas personas que piensan que las claves naturales están bien en algunas situaciones, no encontrará ninguna crítica de las claves sustitutas que no sean posiblemente innecesarias. Eso es un pequeño inconveniente si me preguntas.

Recuerde, incluso los países pueden dejar de existir (por ejemplo, Yugoslavia).

4. Redacción de consultas que requieran DISTINCT trabajar

A menudo ve esto en consultas generadas por ORM. Mire la salida del registro de Hibernate y verá que todas las consultas comienzan con:

SELECT DISTINCT ...

Este es un atajo para garantizar que no devuelva filas duplicadas y, por lo tanto, obtenga objetos duplicados. A veces también verá gente haciendo esto. Si lo ve demasiado, es una verdadera bandera roja. Eso no DISTINCT es malo o no tiene aplicaciones válidas. Lo hace (en ambos aspectos), pero no es un sustituto ni una solución provisional para escribir consultas correctas.

De Why I Hate DISTINCT:

En mi opinión, donde las cosas comienzan a empeorar es cuando un desarrollador está creando una consulta sustancial, uniendo tablas y, de repente, se da cuenta de que aspecto como si estuviera obteniendo filas duplicadas (o incluso más) y su respuesta inmediata … su “solución” a este “problema” es lanzar la palabra clave DISTINCT y MARICÓN
todos sus problemas se van.

5. Favorecer la agregación sobre las combinaciones

Otro error común de los desarrolladores de aplicaciones de bases de datos es no darse cuenta de cuánto más costosa es la agregación (es decir, el GROUP BY cláusula) se pueden comparar con combinaciones.

Para darle una idea de cuán extendido está esto, he escrito sobre este tema varias veces aquí y he recibido muchas votaciones negativas por ello. Por ejemplo:

De la declaración SQL – “unirse” vs “agrupar por y tener”:

Primera consulta:

SELECT userid
FROM userrole
WHERE roleid IN (1, 2, 3)
GROUP by userid
HAVING COUNT(1) = 3

Tiempo de consulta: 0.312 s

Segunda consulta:

SELECT t1.userid
FROM userrole t1
JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2
JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3
AND t1.roleid = 1

Tiempo de consulta: 0,016 s

Eso es correcto. La versión de unión que propuse es veinte veces más rápido que la versión agregada.

6. No simplificar consultas complejas mediante vistas

No todos los proveedores de bases de datos admiten vistas, pero para aquellos que sí lo hacen, pueden simplificar enormemente las consultas si se utilizan con prudencia. Por ejemplo, en un proyecto utilicé un modelo Party genérico para CRM. Esta es una técnica de modelado extremadamente poderosa y flexible, pero puede dar lugar a muchas uniones. En este modelo había:

  • Partido: personas y organizaciones;
  • Rol del partido: cosas que hicieron esas partes, por ejemplo, Empleado y Empleador;
  • Relación de rol de partido: cómo se relacionan esos roles entre sí.

Ejemplo:

  • Ted es una Persona, siendo un subtipo de Partido;
  • Ted tiene muchos roles, uno de los cuales es Empleado;
  • Intel es una organización, que es un subtipo de un Partido;
  • Intel tiene muchas funciones, una de las cuales es Empleador;
  • Intel emplea a Ted, lo que significa que existe una relación entre sus respectivos roles.

Así que hay cinco mesas unidas para vincular a Ted con su empleador. Supone que todos los empleados son personas (no organizaciones) y proporciona esta vista de ayuda:

CREATE VIEW vw_employee AS
SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name
FROM person p
JOIN party py ON py.id = p.id
JOIN party_role child ON p.id = child.party_id
JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT'
JOIN party_role parent ON parent.id = prr.parent_id = parent.id
JOIN party p2 ON parent.party_id = p2.id

Y de repente tiene una vista muy simple de los datos que desea, pero en un modelo de datos muy flexible.

7. No desinfectar la entrada

Este es uno enorme. Ahora me gusta PHP, pero si no sabes lo que estás haciendo, es muy fácil crear sitios vulnerables a ataques. Nada lo resume mejor que la historia del pequeño Bobby Tables.

Datos proporcionados por el usuario a través de URL, datos de formulario. y galletas siempre debe ser tratado como hostil y desinfectado. Asegúrese de obtener lo que espera.

8. No utilizar declaraciones preparadas

Las declaraciones preparadas son cuando compila una consulta menos los datos utilizados en inserciones, actualizaciones y WHERE cláusulas y luego suminístrelo más tarde. Por ejemplo:

SELECT * FROM users WHERE username = 'bob'

vs

SELECT * FROM users WHERE username = ?

o

SELECT * FROM users WHERE username = :username

dependiendo de su plataforma.

He visto que las bases de datos se ponen de rodillas al hacer esto. Básicamente, cada vez que una base de datos moderna encuentra una nueva consulta, tiene que compilarla. Si encuentra una consulta que ha visto antes, le está dando a la base de datos la oportunidad de almacenar en caché la consulta compilada y el plan de ejecución. Al realizar muchas consultas, le está dando a la base de datos la oportunidad de averiguarlo y optimizarlo en consecuencia (por ejemplo, fijando la consulta compilada en la memoria).

El uso de declaraciones preparadas también le brindará estadísticas significativas sobre la frecuencia con la que se usan ciertas consultas.

Las declaraciones preparadas también lo protegerán mejor contra los ataques de inyección SQL.

9. No normalizar lo suficiente

La normalización de la base de datos es básicamente el proceso de optimizar el diseño de la base de datos o cómo organiza sus datos en tablas.

Esta semana me encontré con un código en el que alguien había implosionado una matriz y la había insertado en un solo campo de una base de datos. Normalizar eso sería tratar el elemento de esa matriz como una fila separada en una tabla secundaria (es decir, una relación de uno a muchos).

Esto también surgió en el Mejor método para almacenar una lista de ID de usuario:

He visto en otros sistemas que la lista se almacena en una matriz PHP serializada.

Pero la falta de normalización se presenta de muchas formas.

Más:

  • Normalización: ¿Qué tan lejos es suficiente?
  • SQL por diseño: por qué necesita la normalización de la base de datos

10. Normalizar demasiado

Esto puede parecer una contradicción con el punto anterior pero la normalización, como muchas cosas, es una herramienta. Es un medio para un fin y no un fin en sí mismo. Creo que muchos desarrolladores olvidan esto y comienzan a tratar un “medio” como un “fin”. Las pruebas unitarias son un excelente ejemplo de esto.

Una vez trabajé en un sistema que tenía una enorme jerarquía para los clientes que era algo como:

Licensee ->  Dealer Group -> Company -> Practice -> ...

de modo que tuvo que unir unas 11 tablas antes de poder obtener datos significativos. Fue un buen ejemplo de normalización llevada demasiado lejos.

Más concretamente, la desnormalización cuidadosa y considerada puede tener enormes beneficios de rendimiento, pero debe tener mucho cuidado al hacer esto.

Más:

  • Por qué demasiada normalización de la base de datos puede ser algo malo
  • ¿Hasta dónde llevar la normalización en el diseño de bases de datos?
  • Cuándo no normalizar su base de datos SQL
  • Quizás normalizar no es normal
  • La madre de todos los debates de normalización de bases de datos sobre codificación de terror

11. Usando arcos exclusivos

Un arco exclusivo es un error común cuando se crea una tabla con dos o más claves externas donde una y solo una de ellas puede ser no nula. Gran error. Por un lado, se vuelve mucho más difícil mantener la integridad de los datos. Después de todo, incluso con integridad referencial, nada impide que se establezcan dos o más de estas claves externas (a pesar de las complejas restricciones de verificación).

De una guía práctica para el diseño de bases de datos relacionales:

Hemos desaconsejado encarecidamente la construcción de arcos exclusivos siempre que sea posible, por la buena razón de que pueden resultar difíciles de escribir y plantear más dificultades de mantenimiento.

12. No realizar ningún análisis de rendimiento en las consultas.

El pragmatismo reina supremo, particularmente en el mundo de las bases de datos. Si se adhiere a los principios hasta el punto de que se han convertido en un dogma, es muy probable que haya cometido errores. Tome el ejemplo de las consultas agregadas de arriba. La versión agregada puede parecer “agradable”, pero su rendimiento es lamentable. Una comparación de desempeño debería haber terminado el debate (pero no lo hizo), pero más al grano: lanzar opiniones tan mal informadas en primer lugar es ignorante, incluso peligroso.

13. Dependencia excesiva de UNION ALL y, en particular, de los constructos UNION

UNION en términos de SQL simplemente concatena conjuntos de datos congruentes, lo que significa que tienen el mismo tipo y número de columnas. La diferencia entre ellos es que UNION ALL es una concatenación simple y debe preferirse siempre que sea posible, mientras que UNION hará implícitamente un DISTINCT para eliminar tuplas duplicadas.

Las UNIONES, como DISTINCT, tienen su lugar. Hay aplicaciones válidas. Pero si se encuentra haciendo muchos de ellos, particularmente en subconsultas, probablemente esté haciendo algo mal. Ese podría ser un caso de construcción de consultas deficiente o un modelo de datos mal diseñado que lo obligue a hacer tales cosas.

Las UNIONES, especialmente cuando se utilizan en combinaciones o subconsultas dependientes, pueden paralizar una base de datos. Intentar evítelos siempre que sea posible.

14. Uso de condiciones OR en consultas

Esto puede parecer inofensivo. Después de todo, los AND están bien. O también debería estar bien, ¿verdad? Incorrecto. Básicamente una condición AND restringe el conjunto de datos mientras que una condición OR crece pero no de una manera que se preste a la optimización. Particularmente cuando las diferentes condiciones OR pueden cruzarse, lo que obliga al optimizador a realizar una operación DISTINCT en el resultado.

Malo:

... WHERE a = 2 OR a = 5 OR a = 11

Mejor:

... WHERE a IN (2, 5, 11)

Ahora su optimizador de SQL puede convertir efectivamente la primera consulta en la segunda. Pero puede que no. Simplemente no lo hagas.

15. No diseñar su modelo de datos para que se preste a soluciones de alto rendimiento.

Este es un punto difícil de cuantificar. Normalmente se observa por su efecto. Si se encuentra escribiendo consultas complicadas para tareas relativamente simples o si las consultas para encontrar información relativamente sencilla no son eficientes, entonces probablemente tenga un modelo de datos deficiente.

De alguna manera, este punto resume todos los anteriores, pero es más una advertencia de que hacer cosas como la optimización de consultas a menudo se hace primero cuando debería hacerse en segundo lugar. En primer lugar, debe asegurarse de tener un buen modelo de datos antes de intentar optimizar el rendimiento. Como dijo Knuth:

La optimización temprana es la raíz de todo mal

16. Uso incorrecto de las transacciones de la base de datos

Todos los cambios de datos para un proceso específico deben ser atómicos. Es decir, si la operación tiene éxito, lo hace en su totalidad. Si falla, los datos no se modifican. – No debería haber posibilidad de cambios a medio hacer.

Idealmente, la forma más sencilla de lograr esto es que todo el diseño del sistema debe esforzarse por admitir todos los cambios de datos a través de declaraciones INSERT / UPDATE / DELETE individuales. En este caso, no se necesita un manejo especial de transacciones, ya que su motor de base de datos debería hacerlo automáticamente.

Sin embargo, si algún proceso requiere que se realicen múltiples declaraciones como una unidad para mantener los datos en un estado consistente, entonces es necesario un Control de Transacciones apropiado.

  • Comience una transacción antes del primer extracto.
  • Confirme la transacción después del último extracto.
  • Ante cualquier error, deshaga la transacción. ¡Y muy NB! No olvide omitir / abortar todas las declaraciones que siguen después del error.

También se recomienda prestar especial atención a las subteltias de cómo la capa de conectividad de la base de datos y el motor de la base de datos interactúan a este respecto.

17. No comprender el paradigma “basado en conjuntos”

El lenguaje SQL sigue un paradigma específico que se adapta a tipos específicos de problemas. A pesar de varias extensiones específicas del proveedor, el lenguaje tiene dificultades para lidiar con problemas que son triviales en idiomas como Java, C #, Delphi, etc.

Esta falta de comprensión se manifiesta de varias formas.

  • Imponer de forma inapropiada demasiada lógica procesal o imperativa en la base de datos.
  • Uso inadecuado o excesivo de cursores. Especialmente cuando una sola consulta sería suficiente.
  • Suponiendo incorrectamente que los disparadores se disparan una vez por fila afectada en actualizaciones de varias filas.

Determine una clara división de responsabilidades y esfuércese por utilizar la herramienta adecuada para resolver cada problema.

Errores de programación y diseño de bases de datos clave cometidos por desarrolladores

  • Diseño y uso egoísta de la base de datos. Los desarrolladores a menudo tratan la base de datos como su almacén personal de objetos persistentes sin tener en cuenta las necesidades de otras partes interesadas en los datos. Esto también se aplica a los arquitectos de aplicaciones. El diseño deficiente de la base de datos y la integridad de los datos dificultan el trabajo de terceros con los datos y pueden aumentar sustancialmente los costos del ciclo de vida del sistema. Los informes y MIS tienden a ser un primo pobre en el diseño de aplicaciones y solo se hacen como una ocurrencia tardía.

  • Abusar de datos desnormalizados. Exagerar los datos desnormalizados y tratar de mantenerlos dentro de la aplicación es una receta para los problemas de integridad de los datos. Utilice la desnormalización con moderación. No querer agregar una combinación a una consulta no es una excusa para desnormalizar.

  • Miedo de escribir SQL. SQL no es ciencia espacial y en realidad es bastante bueno para hacer su trabajo. Las capas de mapeo O / R son bastante buenas para realizar el 95% de las consultas que son simples y encajan bien en ese modelo. A veces, SQL es la mejor manera de hacer el trabajo.

  • Políticas dogmáticas de ‘No procedimientos almacenados’. Independientemente de si cree que los procedimientos almacenados son malos, este tipo de actitud dogmática no tiene cabida en un proyecto de software.

  • No comprender el diseño de la base de datos. La normalización es tu amiga y no es ciencia espacial. La unión y la cardinalidad son conceptos bastante simples: si está involucrado en el desarrollo de aplicaciones de base de datos, realmente no hay excusa para no comprenderlos.

  1. No usar el control de versiones en el esquema de la base de datos
  2. Trabajando directamente contra una base de datos en vivo
  3. No leer y comprender conceptos de bases de datos más avanzados (índices, índices agrupados, restricciones, vistas materializadas, etc.)
  4. No probar la escalabilidad … los datos de prueba de solo 3 o 4 filas nunca le darán la imagen real de un rendimiento real en vivo
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *