Laboratorio 06. Objetivos: Representación interna de un BD. Tablas, índices e índices full-text. Sesiones: 1 (24 de noviembre de 2010) Ejercicio: 1. Representación interna: 1.1. Copiar al repositorio de bases de datos la base de datos enginedb contenida en el archivo zip y adjuntarla a servidor. 1.2. Establecer la visualización del nº de páginas de I/O lógicas y físicas leídas para cada acción que se ejecute (set statistics io on). La mayoría serán lógicas porque entra en las páginas que están en la memoria disponibles. 1.3. Crear una consulta que devuelva el tamaño de fila de la tabla. Esto permitirá estimar el tamaño del árbol o heap que se cree. 1.4. Consultar el nº de páginas utilizado por la tabla ProductNew (sys.sysindexes). 1.5. Crear un índice único no cluster por el campo ProductID, y volver a consultar el nº de páginas. 1.6. Crear un índice cluster por ProductID y ver cómo cambia la organización de las páginas y de los índices. Explicar qué pasa. 1.7. Crear un índice no cluster por los campos Color, Size y ProductName, analizar las páginas de nuevo. 1.8. Construir otros índices, si lo necesita, para ver cómo influye el nº de columnas y el tamaño de éstas en la construcción del árbol y ver el tipo de árbol que construye. 2. Índices full-text 2.1 Copiar al repositorio de bases de datos, la base de datos concesionario contenida en el archivo zip y adjuntarla a servidor. 2.2 Crear en la base de datos concesionario una tabla llamada taller.procedimientos que contenga los siguientes datos (identificador decimal(18,0), descripcion char(50), tipodoc char(5),procedimiento image) almacenando ésta en el filegroup denominado concesionariofilegroup2. 2.1. Crear un catálogo full-text en este mismo filegroup e indizar la descripción y los procedimientos. Establecer que el índice se actualice de forma automática.
2.2. Insertar los datos que se adjuntan. Para ello, deberéis utilizar Access como interfaz. SQL Server no suministra herramientas para cargar ficheros. Descripción TipoDoc Archivo Desmontar puerta.htm Puerta.htm Desmontar volante.htm volante.htm Desmontar parachoques.mht Parachoques.mht Cambio de aceite.htm Aceite.htm 2.3. Realizar las consultas de las transparencias de clase u otras especificadas por vosotros para comprender el funcionamiento de los operadores CONTAINS y FREETEXT. 2.4. Leer el contenido de los documentos indexados y construir consultas que os permitan recuperarlos. 2.5. Realizar consultas en las que se busque por ambos campos, título y contenido del fichero.
EL MOTOR SQL SERVER 2008. Motor de base de datos: http://msdn.microsoft.com/es-es/library/ms191135(sql.90).aspx Estimar el tamaño de una base de datos: http://msdn.microsoft.com/es-es/library/ms187445.aspx Optimización de índices La optimación de índices es una faceta importante en cualquier base de datos de producción. Su función principal es reducir el tiempo de respuesta a las operaciones DML tratando de disminuir los accesos a disco. La selección de los índices apropiados para la estructura de una base de datos y su carga de trabajo, es una compleja operación que busca el equilibrio entre la velocidad de la consulta y el costo de actualización. Los índices con pocas columnas en la clave de índice, necesitan menos espacio en el disco y son menos susceptibles de provocar sobrecargas debido a su mantenimiento. Por otra parte, la ventaja de los índices con más columnas es que pueden llegar a cubrir las consultas. Hay que experimentar para cada base de datos en particular y los procesos que se realizan en ella. En SQL Server, los índices se organizan como árboles B+. El nodo superior del árbol B+ se llama nodo raíz y contiene la entrada al índice. Es decir, cualquier búsqueda, sea ordenada o desordenada, debe pasar por aquí. Incluso un recorrido completo debe encontrar la primera página de datos partiendo del nodo raíz. El nivel inferior de los nodos del índice se denomina nodos de hoja. Los niveles del índice entre el nodo raíz y los nodos hoja se conocen en conjunto como niveles intermedios. En un índice cluster, los nodos hoja contienen las páginas de datos de la tabla subyacente. Por tanto, la tabla completa está ordenada según el índice. También, todo acceso a la tabla se hace desde el nodo raíz. En un índice no cluster, los nodos hoja tienen una referencia al índice agrupado (si existe) o al índice montón (si la tabla no tiene ningún índice agrupado). Cada fila de índice contiene un valor clave y un puntero a una página de nivel inferior en el árbol
B, o bien a una fila de datos en el nivel hoja del índice (clave del índice agrupado o RID del montón (HEAP)). Si la tabla es un montón, lo que significa que no tiene ningún índice agrupado, el localizador de fila es un puntero a la fila. El puntero se genera a partir del identificador (Id.) de archivo, el número de página y el número de la fila dentro de la página. El puntero completo se conoce como Id. de fila (RID «row id» en inglés). Si la tabla tiene un índice agrupado o si el índice está en una vista indizada, el localizador de fila es la clave del índice agrupado para la fila. Si el índice agrupado no es un índice único, SQL Server 2008 hace que las claves duplicadas sean únicas agregando un valor generado internamente denominado valor de unicidad. De este último punto extraemos varias conclusiones: Cuando más ancha sea la clave de un índice agrupado, más ocuparán sus índices no agrupados pues siempre la incluyen. Si el índice agrupado no es único, añade 4 bytes a cada entrada de los índices no agrupados. Por esto en muchos diseños encontramos una clave artificial amén de las naturales que pueda tener una tabla, que es de tipo IDENTITY, sobre el que se crea el índice agrupado. Esto puede hacer más eficientes los índices porque: 1. las comparaciones de enteros son las más rápidas por ser tipos nativos de cualquier procesador 2. los índices no agrupados salen más pequeños y por tanto hay menos lecturas físicas. Aunque también podemos estar añadiendo ineficiencias al: a. crear un campo nuevo que hace más grande la tabla y aumenta las lecturas físicas aunque hoy en día un campo INT añadido no se nota b. los datos pueden estar desordenados y aumentar las lecturas físicas aleatorias que son las más costosas y c. se incluye un campo en todos los índices que nunca se va a usar para cubrir consultas pues es una clave artificial, a diferencia de las naturales que es mucho más fácil que aparezcan en las consultas. En todo caso sí se recomienda utilizar una longitud corta en la clave de los índices agrupados. Los índices agrupados también mejoran si se crean en columnas únicas o que no admitan valores NULL. Hay que examinar la unicidad de las columnas, no sólo porque el índice será más rápido al no tener el contador, sino porque un índice único en lugar de un índice no único con la misma combinación de columnas, proporciona información adicional al optimizador de consultas y, por tanto, resulta más útil. Para calcular el tamaño de una clave de índice, deberíamos ver las propiedades de las columnas en las que se basará el índice para lo que se puede utilizar la vista de catálogo sys.all_columns y sumar la longitud de cada columna que se definirá en la clave de índice. USE restaurante; -- tamaño de fila de tabla SELECT sum(sys.syscolumns.length) size_row FROM sys.syscolumns INNER JOIN sys.sysobjects ON sys.syscolumns.id = sys.sysobjects.id where sys.sysobjects.name='empleado' -- tamaño de cada columna
SELECT sys.syscolumns.name, sys.syscolumns.length FROM sys.syscolumns INNER JOIN sys.sysobjects ON sys.syscolumns.id = sys.sysobjects.id where sys.sysobjects.name='empleado' Para calcular el tamaño del índice o tabla en SQL Server 2008 se deben seguir los pasos descritos en http://msdn.microsoft.com/es-es/library/ms187445.aspx Para estimar el rendimiento de un índice hay que ver el número de niveles que tiene, o lo que es lo mismo, el número de páginas leídas que tiene un acceso al índice. Recordamos que en SQL Server 2008 los índices son árboles B+ balanceados, por lo que siempre leerá el mismo número de páginas independientemente del dato que se busque. Para un índice que ya existe, es fácil conocerlo usando la función INDEXPROPERTY pidiendo la propiedad IndexDepth. Por ejemplo: USE restaurante; SELECT INDEXPROPERTY(OBJECT_ID('empleado'), 'PK_Empleado','IsClustered')AS [Is Clustered], INDEXPROPERTY(OBJECT_ID('empleado'), 'PK_Empleado','IndexDepth') AS [Index Depth], INDEXPROPERTY(OBJECT_ID('empleado'), 'PK_Empleado','IndexFillFactor') AS [Fill Factor]; Nota: FILLFACTOR = fillfactor. Especifica un porcentaje que indica cuánto debe llenar el Database Engine (Motor de base de datos) el nivel hoja de cada página de índice durante la creación o nueva generación del mismo. fillfactor debe tener un valor entero entre 1 y 100. El valor predeterminado es 0. Si el valor de fillfactor es 100 ó 0, el Database Engine (Motor de base de datos) crea índices con páginas hoja llenadas hasta su capacidad, aunque deja algo de espacio en el nivel superior del árbol del índice para admitir al menos una fila de índice adicional. Otro aspecto que se ha de tener en cuenta es la fragmentación del índice como consecuencia de las inserciones y modificaciones en la tabla subyacente. La siguiente instrucción devuelve estadísticas de fragmentación y tamaño de los datos y los índices de la tabla o vista especificada. En el caso de un índice, se devuelve una fila por cada nivel de árbol B en cada partición. En el caso de un montón, se devuelve una fila para la unidad de asignación IN_ROW_DATA en cada partición. En el caso de datos de objetos grandes (LOB), se devuelve una fila para la unidad de asignación LOB_DATA en cada partición. Si en la tabla hay datos de desbordamiento de filas, se devuelve una fila para la unidad de asignación ROW_OVERFLOW_DATA en cada partición. select index_id,index_level, avg_fragmentation_in_percent from sys.dm_db_index_physical_stats (DB_ID('restaurante'), OBJECT_ID('EMPLEADO'), NULL, NULL,
'DETAILED') Si el valor promedio de fragmentación es mayor que 0 o de un número pequeño, entonces requiere reconstrucción el índice. ALTER INDEX PK_EMPLEADO ON EMPLEADO REBUILD La utilización de índices mejoran el rendimiento de las consultas si todos datos para satisfacer las necesidades de la consulta existen en el propio índice. Es decir, sólo se necesitan las páginas de índice y no las páginas de datos de la tabla o el índice agrupado para recuperar todo lo necesario de la tabla o vista indizada. Se reducen así las lecturas físicas globales en el disco. Sin embargo no debemos añadir alegremente columnas incluidas a los índices, pues el coste de actualización es más alto. Recordemos que, cada actualización a un campo va a suponer casi siempre la actualización de los índices, lo que puede provocar que se dividan las hojas con la reestructuración de los nodos intermedios y provocar bastantes escrituras físicas, más el bloqueo de la transacción, todo ello muy costoso. Para bases de datos de procesamiento de transacciones en línea (OLTP). Los índices agrupados no son convenientes: Cuando las columnas clave están sometidas a cambios frecuentes porque esto provoca que se mueva toda la fila. Esta consideración es importante en sistemas de procesamiento de transacciones de gran volumen en los que los datos tienden a ser volátiles Claves con varios campos. Como ya se ha comentado, los valores clave del índice agrupado se utilizan en todos los índices no agrupados como claves de búsqueda, por lo que serán bastante más grandes. El mantenimiento del índice hace aumentar el tiempo necesario para realizar operaciones de modificación, inserción, actualización o eliminación en la tabla subyacente o la vista indizada. Por tanto hay que determinar si la mejora del rendimiento de las consultas compensa el efecto en el rendimiento durante la modificación de datos y en los requisitos de espacio en disco adicionales. Por último, veamos cómo afecta el tamaño del índice mediante un repaso rápido a las páginas y extensiones. Una página es una unidad de 8 KB donde SQL Server guarda datos. Es la unidad más pequeña que SQL Server puede leer o escribir. Por eso, cuando las estadísticas nos dan lecturas lógicas o físicas, se refieren realmente a páginas que han leído, pues aunque se necesite sólo una pequeña porción, lee la página entera. Dentro de dicho coste E/S hay que distinguir si es una lectura lógica o física. Es decir, si la lectura se hace directamente de memoria o si previamente ha habido que traer los datos del disco. En el caso de las lecturas físicas, su coste es mucho mayor y depende del tipo de acceso que se usa (secuencial o aleatorio), el nivel de fragmentación de los datos (tanto externo como interno), así como otros factores. set statistics io on -- muestra cuántas I/O a disco se producen como consecuencia de la ejecución de una instrucción SQL -- nº de páginas que ocupa el índice
SELECT dpages pag_de_datos, reserved, used pag_datos_e_indices, rowcnt filas_datos FROM sys.sysindexes WHERE name='ix_clusterid'