La tabla sobre la que se realizan las operaciones tiene una clave primaria IDENTITY, un campo CHAR(80) y otro VARCHAR(80) con el mismo valor predeterminado (una cadena de 14 caracteres), y por último un campo DATETIME con la fecha actual como valor predeterminado.
En ambos test, realizados sobre un SQL Server 2008 RTM 32x, Dual Core y 3Gb RAM, se comprueba el tiempo que se tarda en realizar todas esas inserciones:
- Sin ningún tipo de índice
- Con un índice sobre el campo CHAR(80)
- Con un índice sobre el campo VARCHAR(80)
- Con un índice sobre el campo DATETIME
- Con un índice sobre los campos DATETIME y CHAR(80)
- Con un índice sobre los campos CHAR(80) y DATETIME
- Con un índice sobre los campos CHAR(80) y DATETIME y otro índice sobre CHAR(80)
Los resultados (en milisegundos) de ejecutar 10 veces cada uno de los test (la última fila son los valores medios) son los siguientes:
1 |
2 |
3 |
4 |
5 |
6 |
7 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Bucle |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Masivo |
|
Resultaba obvio pensar que las inserciones con índices son siempre más lentas que sin ellas, pero los datos lo confirman: en el caso del bucle suponen casi el doble de media, mientras que en el otro caso son casi seis veces más.
Los datos también confirman que, cuanto más “ancho” es el índice (cuanto más ocupan las columnas que lo componen), más tarda la inserción.
Otra obviedad es que, a más índices, más lento se vuelve la inserción: siempre respecto de la inserción más lenta, en el caso del bucle supone 1.5 veces más, mientras que en el caso de la inserción masiva, supone casi el doble.
También era lógico pensar que un INSERT… SELECT de 100.000 registros iba a suponer menos tiempo que un bucle del mismo número de iteraciones en las que en cada una de ellas se inserta un registro. Pero aquí acaban las evidencias y empiezan las cosas curiosas:
Por ejemplo, ¿por qué el test número 5 (índice DATETIME+CHAR(80) ) es más lento en la inserción masiva que en el bucle? Es el único caso en el que esto ocurre. De hecho, sería lógico pensar que el test número 5 y el 6 arrojaran valores similares, ya que lo componen los mismos campos con la única diferencia del orden en los mismos. Sin embargo, mientras que en la inserción masiva arroja valores prácticamente iguales (apenas un 1% de desviación), para el bucle hay una gran diferencia a favor del test número 5 (40% más rápido de media). Es más, si vemos las pruebas del menor a menor tiempo por tamaño del índice, vemos que:
Test núm. |
Posición |
||
B |
M |
||
4 (8 bytes) | 1º | 1º | |
3 (14 bytes) | 3º | 2º | |
2 (80 bytes) | 4º | 3º | |
5 (88 bytes) | 2º | 4º | |
6 (88 bytes) | 5º | 5º | |
7 (88 + 8 bytes) | 6º | 6º | |
Realmente el que se adapta a la lógica que podríamos presuponer es el test de inserción masiva (columna “M”), en el que podemos ver que a mayor tamaño del índice, más tarda en ejecutarse la operación. Sin embargo, para las inserciones individuales (columna “B”) hay un baile de números curioso, apareciendo como invitado sorpresa el test número 5 en el segundo lugar. Podríamos pensar que a SQL Server le gustan más los números en la primera columna de un índice (un campo fecha internamente no es más que un número) que los caracteres, pero entonces esa misma conclusión deberíamos aplicarla respecto a la inserción masiva y, sin embargo, vemos que esto no se cumple.
La verdad es que no se me ocurre ahora mismo ninguna razón que explique el por qué de este comportamiento. He repetido el test varias veces y siempre da valores similares. Si alguno de vosotros tiene alguna idea al respecto, que deje un comentario, a ver si entre todos somos capaces de comprenderlo.
Dejando este último punto a un lado, ahora ya podemos saber cómo afecta tener índices de más (duplicados parcial o totalmente, o poco usados) en nuestra base de datos. No hemos descubierto nada que no intuyéramos, pero al menos ya podemos corroborarlo con cifras.