2009-05-21 17 views

Respuesta

81

El pedido de columnas tuvo un gran impacto en el rendimiento en algunas de las bases de datos que he ajustado, abarcando SQL Server, Oracle y MySQL. Este post tiene good rules of thumb:

  • primarios columnas clave primeros
  • columnas de clave externa próximos.
  • columnas buscados de manera frecuente al lado
  • columnas actualiza con frecuencia más adelante
  • columnas anulables pasado.
  • columnas anulables usados ​​menos después de columnas anulables utilizados con más frecuencia

Un ejemplo de diferencia de rendimiento es una búsqueda en el índice. El motor de base de datos encuentra una fila según algunas condiciones en el índice y recupera una dirección de fila.Ahora dicen que busca SomeValue, y es en esta tabla:

SomeId int, 
SomeString varchar(100), 
SomeValue int 

El motor tiene que adivinar dónde comienza SomeValue, porque someString tiene una longitud desconocida. Sin embargo, si cambia el orden de:

SomeId int, 
SomeValue int, 
SomeString varchar(100) 

Ahora el motor sabe que SomeValue se puede encontrar 4 bytes después del comienzo de la fila. Entonces, el orden de las columnas puede tener un impacto considerable en el rendimiento.

EDITAR: Sql Server 2005 almacena campos de longitud fija al inicio de la fila. Y cada fila tiene una referencia al comienzo de un varchar. Esto niega completamente el efecto que he enumerado arriba. Entonces, para las bases de datos recientes, el orden de las columnas ya no tiene ningún impacto.

+0

Cada motor de base de datos que conozco reserva 100 bytes para SomeString, incluso si es nulo –

+0

Wow, no lo sabía. ¿No tiene que buscar todo el bloque de todos modos, por lo que realmente no está ahorrando tiempo en IO, solo la velocidad de cálculo al calcular el desplazamiento. –

+0

Por lo tanto, esto tendría algún impacto en "seleccionar SomeValue from t" ... (¿seguramente más que ver con devolver ese valor de muchas filas en lugar de búsquedas de índices?) ¿Pero cuánto impacto? – araqnid

4

No, el orden de las columnas en una tabla de base de datos SQL es totalmente irrelevante, excepto para fines de visualización/impresión. No tiene sentido reordenar columnas: la mayoría de los sistemas ni siquiera proporcionan una forma de hacerlo (excepto descartar la tabla anterior y recrearla con el nuevo orden de las columnas).

Marc

EDIT: desde la entrada de Wikipedia sobre la base de datos relacional, aquí está la parte pertinente que para mí muestra claramente que la orden de las columnas debe Nunca ser motivo de preocupación:

Una relación se define como una conjunto de n-tuplas. Tanto en matemáticas como en el modelo de base de datos relacional, un conjunto es desordenado colección de elementos, aunque algunos DBMS imponen un orden a sus datos. En matemáticas, una tupla tiene un orden y permite la duplicación. E.F. Codd originalmente tuplas definidas usando esta definición matemática. Más tarde, fue una de las grandes ideas de E.F. Codd que el uso de nombres de atributos en lugar de un orden sería mucho más conveniente (en general) en un lenguaje de computadora basado en las relaciones. Esta idea todavía se usa hoy.

+0

He visto que la diferencia de columna tiene un gran impacto con mis propios ojos, así que no puedo creer que esta sea la respuesta correcta. Aunque la votación lo pone primero. Hrm. – Andomar

+0

¿En qué entorno SQL estaría? –

+1

El mayor impacto que he visto fue en Sql Server 2000, donde mover una tecla externa hacia adelante aceleró algunas consultas de 2 a 3 veces. Esas consultas tenían exploraciones de tablas grandes (1M + filas) con una condición en la clave externa. – Andomar

4

legibilidad de la salida cuando se tiene que escribir:

select * from <table> 

en el software de gestión de base de datos?

Es una razón muy espúrea, pero por el momento no se me ocurre nada más.

5

Algunas aplicaciones mal escritas pueden depender del orden/índice de la columna en lugar del nombre de la columna. No deberían serlo, pero sucede. Cambiar el orden de las columnas rompería tales aplicaciones.

+2

Los desarrolladores de aplicaciones que hacen que su código dependa del orden de las columnas de una tabla MERECEN tener sus aplicaciones rotas. Pero los usuarios de la aplicación no merecen la interrupción. – spencer7593

0

La única vez que tendrá que preocuparse por el orden de las columnas es si su software se basa específicamente en esa orden. Normalmente esto se debe al hecho de que el desarrollador se volvió flojo e hizo un select * y luego se refirió a las columnas por índice en lugar de por nombre en su resultado.

6

Durante la capacitación de Oracle en un trabajo anterior, nuestro DBA sugirió que poner todas las columnas que no admiten nulos antes de las que aceptan valores nulables era ventajoso ... aunque TBH no recuerdo los detalles de por qué. ¿O tal vez solo los que probablemente se actualizarán deberían ir al final? (Tal vez pospone tener que mover la fila si se expande)

En general, no debería hacer ninguna diferencia. Como dices, las consultas siempre deben especificar columnas en lugar de confiar en el orden de "seleccionar *". No sé de ningún DB que les permita ser cambiado ... bueno, no sabía que MySQL lo permitiera hasta que lo mencionó.

+4

Tenía razón, Oracle no escribe columnas NULL finales en el disco, ahorrando algunos bytes. Ver http://www.dba-oracle.com/oracle_tips_ault_nulls_values.htm – Andomar

+0

absolutamente, puede hacer una gran diferencia en el tamaño del disco – Alex

+0

¿Es ese el enlace que quiso decir? Está relacionado con la no indexación de null en índices en lugar de orden de columnas. – araqnid

1

Como suele ser el caso, el factor más importante es el siguiente tipo que tiene que trabajar en el sistema. Intento primero tener las columnas de clave principal, las columnas de clave externa en segundo lugar y luego el resto de las columnas en orden descendente de importancia/importancia para el sistema.

+0

Normalmente comenzamos con la última columna "creada" (marca de tiempo para cuando se inserta la fila). Con tablas antiguas, por supuesto, puede tener varias columnas agregadas después de eso ... Y tenemos la tabla ocasional donde una clave primaria compuesta se cambió a una clave sustituta por lo que la clave principal está varias columnas más. – araqnid

0

Si va a utilizar UNION mucho, facilita la combinación de columnas si tiene una convención sobre su pedido.

+0

¡Parece que su base de datos necesita normalizarse! :) –

+0

¡Hola! Tómalo, no dije mi base de datos. :) –

+0

Existen razones legales para usar UNION;) Ver http://www.postgresql.org/docs/current/static/ddl-partitioning.html y http://stackoverflow.com/questions/863867/database-speed-optimization-few-tables-with-many-rows-or-many-tables-with-few-r – voyager

36

Actualización:

En MySQL, puede haber una razón para hacer esto.

Dado que los tipos de datos variables (como VARCHAR) se almacenan con longitudes variables en InnoDB, el motor de base de datos debe atravesar todas las columnas anteriores en cada fila para averiguar el desplazamiento de la dada.

El impacto puede ser tan grande como 17% para columnas 20.

Ver esta entrada en mi blog para más detalles:

En Oracle, arrastrando NULL columnas no consumen espacio, es por eso que siempre se les debe poner al final de la tabla .

También en Oracle y en SQL Server, en caso de una fila grande, puede ocurrir ROW CHAINING.

ROW CHANING es dividir una fila que no cabe en un bloque y extenderla sobre los bloques múltiples, conectados con una lista vinculada.

La lectura de columnas posteriores que no se ajustaban al primer bloque requerirá atravesar la lista vinculada, lo que dará como resultado una operación adicional I/O.

Ver this page para la ilustración de ROW CHAINING en Oracle:

Es por eso que usted debe poner columnas que utilice con frecuencia al comienzo de la tabla, y columnas que no utilice a menudo, o columnas que tienden a ser NULL, hasta el final de la mesa.

Nota importante:

Si te gusta esta respuesta y desea votar por ella, por favor, también votar por @Andomar's answer.

Respondió la misma pregunta, pero parece que se trata de una votación negativa sin ningún motivo.

+1

¿Estás diciendo que esto sería lenta: seleccione tinyTable.id, tblBIG.firstColumn, tblBIG.lastColumn de tinyTable combinación interna tblBIG en tinyTable.id = tblBIG.fkID Si los registros son tblBIG más de 8 KB (en cuyo caso se produciría alguna fila de encadenamiento) y la unión sería sincrónica ... Pero esto sería rápido: seleccione tinyTable.id, tblBIG.firstColumn de tinyTable combinación interna tblBIG en tinyTable.id = tblBIG .fkID Como no usaría la columna en otros bloques, no es necesario para atravesar la lista vinculada ¿Lo entendí bien? – jfrobishow

+1

@jfrobishow: correcto. – Quassnoi

+0

Obtengo solo el 6%, y eso es para col1 contra _any_ other column. –

2

La única razón por la que puedo pensar es para depurar y combatir incendios. Tenemos una tabla cuya columna de "nombre" aparece alrededor del décimo en la lista. Es difícil cuando seleccionas rápidamente * de la tabla donde identificamos (1,2,3) y luego tienes que desplazarte para ver los nombres.

Pero eso es todo.

0

En general, lo que sucede en SQL Server cuando se cambia el orden de las columnas a través de Management Studio, es que crea una tabla temporal con la nueva estructura, mueve los datos a esa estructura desde la anterior, descarta la anterior y cambia el nombre uno nuevo. Como se puede imaginar, esta es una opción muy pobre para el rendimiento si tiene una mesa grande. No sé si mi SQL hace lo mismo, pero es una razón por la cual muchos de nosotros evitamos reordenar columnas. Como select * nunca debe usarse en un sistema de producción, agregar columnas al final no es un problema para un sistema bien diseñado. En general, el orden de las columnas en la tabla no debe ser alterado.

0

Como se señaló, existen numerosos problemas potenciales de rendimiento. Una vez trabajé en una base de datos donde poner columnas muy grandes al final mejoraba el rendimiento si no hacía referencia a esas columnas en su consulta. Aparentemente, si un registro abarcaba varios bloques de disco, el motor de la base de datos podría dejar de leer bloques una vez que obtuviera todas las columnas que necesitaba.

Por supuesto, cualquier implicación en el rendimiento depende en gran medida no solo del fabricante que está utilizando, sino también de la versión. Hace unos meses noté que nuestro Postgres no podía usar un índice para una comparación "me gusta". Es decir, si escribió "somecolumn like 'M%'", no fue lo suficientemente inteligente como para omitir las M y salir cuando encontró la primera N. Estaba planeando cambiar un grupo de consultas para usar "between". Luego obtuvimos una nueva versión de Postgres y se manejó de manera inteligente. Me alegro de que nunca llegué a cambiar las consultas. Obviamente no es directamente relevante aquí, pero mi punto es que cualquier cosa que haga por consideraciones de eficiencia podría quedar obsoleta con la próxima versión.

El orden de las columnas es casi siempre muy relevante para mí porque de forma rutinaria escribo código genérico que lee el esquema de la base de datos para crear pantallas. Por ejemplo, mis pantallas de "editar un registro" casi siempre se crean leyendo el esquema para obtener la lista de campos y luego mostrarlos en orden. Si cambio el orden de las columnas, mi programa seguirá funcionando, pero la visualización puede ser extraña para el usuario. Al igual que, espera ver nombre/dirección/ciudad/estado/zip, no ciudad/dirección/zip/nombre/estado. Claro, podría poner el orden de visualización de las columnas en código o en un archivo de control o algo así, pero cada vez que agreguemos o eliminemos una columna tendremos que acordarnos de actualizar el archivo de control. Me gusta decir cosas una vez.Además, cuando la pantalla de edición se crea exclusivamente a partir del esquema, agregar una nueva tabla puede significar escribir cero líneas de código para crear una pantalla de edición para él, lo cual es genial. (Bueno, está bien, en la práctica, generalmente tengo que agregar una entrada al menú para llamar al programa de edición genérico, y en general, he abandonado el genérico "seleccionar un registro para actualizar" porque hay demasiadas excepciones para que sea práctico .)

1

Más allá del ajuste de rendimiento obvio, acabo de encontrarme con un caso de esquina en el que las columnas de reordenación hacían que fallara una secuencia de comandos sql (previamente funcional).

De la documentación "TIMESTAMP y columnas DATETIME no tienen propiedades automáticas a menos que se especifican explícitamente, con esta excepción: Por defecto, la primera columna TIMESTAMP tiene tanto CURRENT_TIMESTAMP DEFAULT y ON UPDATE CURRENT_TIMESTAMP si no se especifica de forma explícita" https://dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html

Por lo tanto, un comando ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL; funcionará si ese campo es la primera marca de tiempo (o fecha y hora) en una tabla, pero no de lo contrario.

Obviamente, puede corregir ese comando alter para incluir un valor predeterminado, pero el hecho de que una consulta que funcionó dejó de funcionar debido a un reordenamiento de columna hizo que me doliera la cabeza.

Cuestiones relacionadas