El Clustered Index es uno de los índices mas importantes que tenemos, y una de sus razones es que solo podemos disponer de uno por tabla y todo tipo de consultas que utilicen rango de valores serán muy beneficiadas por este tipo de índices.
Ahora bien, por defecto cuando creamos una Primary Key se genera de forma automática por esos campos el Clustered Index de nuestra tabla.
Muchos desarrolladores que hacen diseños de tablas prestan poca atención a este detalle. En este Post vamos a analizar los impactos de performance que podemos tener con solo el hecho de no definir de forma adecuada nuestro CLustered Index.
Si creo una tabla (o la modifico) desde el modo de diseño, cuando agregue una primary key veremos una ventana como la siguiente
Aquí podemos observar que la opción de “Create as Clustered” esta en Yes para nuestra Primary Key.
También sucede lo mismo si lo hacemos vía código como muestra el siguiente ejemplo
use tempdb
go
drop table movimientos
drop table articulos
drop table numeros
drop table fechas
create table movimientos (id bigint identity PRIMARY KEY,
articulo varchar(50),
fecha datetime,
cantidad int
)
go
sp_help movimientos
Bien lo que haremos ahora es crear una tabla similar a la anterior pero que la primary key no sea el Clustered, porque? porque en mi tabla de movimientos las consultas de rango son de fecha a fecha y no de ID, con lo cual si pongo un indice CLustered para este tipo de consultas voy a mejorar su tiempo de respuesta.
Para ello primero creamos una copia de movimientos con SELECT INTO para no copiar índices
select *
into movimientos2 from movimientos
Ahora crearemos el indice Clustered por la columna Fecha y un indice Non Clustered por ID
create clustered index ix3 on movimientos2(fecha)
create index ix4 on movimientos2(id)
También le vamos a crear a la tabla movimientos un indice por fecha ya que no lo tenia pero en este caso será en Non Clustered
create index ix2 on movimientos(fecha)
Con el siguiente código veremos como han quedado cada una de estas tablas con relación a los índices
exec sp_helpindex movimientos
exec sp_helpindex movimientos2
Aquí podemos observar bien que ambas tablas tienen índices por los mismos campos solamente con la diferencia del Clustered que en la segunda lo hemos puesto por fecha ya que es una tabla la cual sus querys son muy usadas por ese campo y en rangos (una clásica tabla de movimientos)
Bien, ahora lo que haremos es ejecutar una query en ambas tablas (la misma Query) y ver los resultados del Query Plan
select articulo
from movimientos
where fecha >= '20091101'
and fecha < '20100101'
select articulo
from movimientos2
where fecha >= '20091101'
and fecha < '20100101'
Como podemos observar el primer Query representa un 94% del tiempo total de ambas ejecuciones y el segundo un 6%, siendo este ultimo mucho mas performante.
Aquí podemos ver lo que ha sucedido con solo el hecho de aplicar el clustered a la columna adecuada, y como mensaje: es muy pero muy importante definir bien el Clustered , este post esta destinado a mostrar que dejarlo por Defecto no es una buena idea y que cada tabla debería tener un estudio de que columnas deberían ser el Clustered Index
Aquí también les dejo el Script completo para que puedan jugar con el mismo y ver los resultados.