
Vamos a empezar con una serie de varios artículos sobre los índices en SQL Server, un aspecto fundamental en nuestra base de datos que marcará todo su funcionamiento. A lo largo de los próximos días vamos a profundizar en este tema partiendo desde lo más básico. Empezaremos viendo las estructuras fundamentales de las tablas, lo que nos llevará a adentrarnos en los principales tipos de índices. Esos conocimientos nos ayudarán a entender el resto de índices y cómo afectan al rendimiento de nuestra base de datos. La mejor parte es que al final de la serie habremos aprendido cómo mejorar y optimizar nuestros índices y por tanto, las consultas que leen datos de esas tablas.
Estructura de una tabla en SQL Server
Como a estas alturas ya sabréis, en SQL Server los datos se almacenan en tablas con columnas y filas. Lo que ya no todo el mundo sabe es que estas tablas a su vez se almacenan en páginas de 8 kb. Cada una de estas páginas es una unidad indivisible, son los átomos de nuestra base de datos. Todas nuestras tablas tendrán al menos una página y será exclusiva. Esto es importante, cada página sólo contendrá datos de un solo objeto (tabla o índice). A medida que nuestras tablas crezcan irán ocupando más y más páginas pero siempre con estos requisitos que hemos comentado. Cuando se borren datos ese espacio se quedará libre pero no se liberará, estará reservado para almacenar futuros datos de esa tabla.
La tabla más básica que podemos crear se llama HEAP (montón traducido literalmente). Será una tabla donde los datos que escribimos se van añadiendo en el primer espacio libre que encuentre en las páginas sin ningún orden. Empezará llenando secuencialmente el espacio de las páginas pero cuando quede espacio libre por algún borrado se añadirá ahí.
Índices Clustered en SQL Server
Lo contrario a una tabla HEAP es una tabla con un índice clustered (agrupado). Los datos se escribirán en páginas, ordenados siempre por la columna (o las columnas) del índice clustered. Como si de un diccionario se tratase, SQL Server sabe cual es el primer y el último dato de cada página, lo que facilita en gran medida las búsquedas por estas columnas. Como se trata de la propia ordenación de los datos sólo puede haber un índice clustered por cada tabla.
Índices Nonclustered en SQL Server
Los índices nonclustered (no agrupados) son un objeto separado de la tabla, sólo incluyen algunas de las columnas y se almacenan en páginas separadas. Un índice nonclustered será por tanto una copia de la tabla original con solo parte de las columnas y ordenado de manera diferente. Tenga una tabla un índice clustered o sea un HEAP podremos crear tantos índices nonclustered como queramos.
¿Cómo lee los datos SQL Server?
Con lo que ya sabemos nos podemos hacer una idea de como SQL Server va a acceder a la información que tenemos almacenada y empezar a comprender la importancia de los índices. Vamos a empezar con una tabla HEAP como la que bajo estas líneas (podéis ampliar la imagen haciendo click en ella):

Como veis tenemos una tabla de personas con un ID, nombre, apellido y una fecha de modificación. Supongamos que tenemos que buscar la fecha de modificación del usuario número 2, ¿cómo lo haríais vosotros?. Pensadlo un momento. Si habéis pensado en empezar a leer la columna id hasta llegar al 2 y después recorrer horizontalmente la tabla hasta la columna fecha de modificación, felicidades habéis pensado como SQL Server. Ahora bien, esta no parece la forma más efectiva de consultar información, ¿verdad?. ¿Y si la tabla en vez de 20 tuviera 20.000 registros? ¿Y 20.000.000? Lo mejor será crear un índice clustered por el campo ID para así tenerlo ordenado, ¿no creéis?
Como hemos comentado el índice clustered es la propia tabla ordenada por lo que tendremos todos los datos igual que en nuestra tabla HEAP pero ordenados por la columna ID en este caso.

Ahora es mucho más fácil buscar los datos de una persona si nos dan su ID, ¿a que si?. Pero, ¿qué pasaría si la pregunta ahora fuese por la fecha de modificación de los usuarios que se llaman Gigi? Tendríamos el mismo problema que antes, deberíamos recorrer la columna nombre hasta encontrar el que buscamos. Es incluso peor cuando estamos hablando de datos que no son únicos, aunque hayamos encontrado un Gigi puede ser que haya más, no lo sabremos hasta que no terminemos con toda la tabla. Es entonces el momento de crear un índice nonclustered por el nombre y el id para ayudarnos en esta tarea. Veámoslo:

Ahora si, podemos consultar nuestro índice nonclustered hasta ver que Gigi es el ID 9 y que el siguiente registro ya tiene otro valor por lo que solo hay una persona que se llama así. Usaremos nuestro índice nonclustered para encontrar el ID y luego en nuestro índice clustered iremos directamente al registro que necesitamos.
Si en este punto pensáis que os lleva más trabajo mirar primero el índice nonclustered y después el clustered que directamente leer todo el índice clustered que solo tiene 20 registros no os preocupeis, SQL piensa igual. Los índices no se usan en tablas pequeñas, aunque existan. En esos casos siempre va a tardar menos en leer la tabla entera que en usar los índices. Pero esto lo veremos más adelante, queda mucha serie de índices, veremos cosas nuevas y profundizaremos en lo que hemos visto. Estad atentos.