Artículo
· 21 jun, 2024 Lectura de 9 min

Determinando los tamaños de los globales y tablas en InterSystems IRIS

Spoilers: Realizar verificaciones diarias de integridad (IntegrityChecks) no sólo es una práctica recomendada, sino que también proporciona una instantánea de los tamaños y densidad de los globales.

Actualización 2024-04-16:  A partir de IRIS 2024.1, muchas de las utilidades que comentaremos a continuación ofrecen ahora un modo para estimar el tamaño con un error <2% en promedio, con mejoras significativas en el rendimiento y los requisitos de E/S. Aunque sigo recomendando realizar verificaciones regulares de integridad, hay situaciones donde se necesitan respuestas más urgentes.

  • EstimatedSize^%GSIZE- Ejecuta %GSIZE en modo de estimación.
  • ##class(%Library.GlobalEdit).GetGlobalSize(directory, globalname, .allocated, .used. 2)  - Para estimar el tamaño de un global programáticamente y devolver el espacio asignado o reservado y el espacio utilizado. Nota el parámetro final debe ser "2".
  • CALL %SYS.GlobalQuery_Size('directory', '','*',,,2) - Recuperar tamaños estimados de globals mediante SQL

Seguir el tamaño de los datos es una de las actividades más importantes para comprender la salud del sistema, rastrear la actividad del usuario y planificar la capacidad necesaria. Los productos de InterSystems almacenan datos en una estructura de árbol llamada globals. Este artículo discute cómo determinar los tamaños de globals, y por lo tanto el tamaño de tus datos. El enfoque se centra medir esos tamaños equilibrando el impacto en los sistemas y la precisión la medida.

Las tablas SQL son simplemente una proyección de los globals subyacentes. Actualmente, para ver el tamaño de una tabla es necesario examinar los tamaños correspondientes de los globals. Se está desarrollando un mecanismo más eficiente basado en muestras. Comprender la relación entre tablas y globals puede requerir algunos pasos adicionales, que se discuten a continuación.

Datos

El tipo específico de datos que se necesita recolectar varía dependiendo de la pregunta específica que se esté tratando de responder. Existe una diferencia fundamental entre el espacio "asignado" para una global y el espacio "utilizado" por una global que vale la pena considerar. En general, el espacio asignado suele ser suficiente, ya que corresponde al espacio utilizado en disco. Sin embargo, hay situaciones donde el espacio utilizado y los datos de empaquetado son esenciales, por ejemplo, al determinar si un global se está almacenando de manera eficiente después de una purga grande de datos

  • Espacio Asignado - Estas son unidades de bloques de 8KB. Generalmente, solo un global puede utilizar un bloque. Por lo tanto, incluso el global más pequeño ocupa al menos 8KB. Este es también funcionalmente el tamaño en disco del global. Determinar el espacio asignado solo requiere examinar bloques de punteros inferiores (y bloques de datos que contienen cadenas grandes). Excepto en escenarios raros o forzados, típicamente hay varios órdenes de magnitud menos bloques de punteros que bloques de datos. Esta métrica suele ser suficiente para entender las tendencias de crecimiento si se recolecta regularmente.
  • Espacio Utilizado - "Utilizado" es la suma de los datos almacenados dentro del global y la información de gestión necesarios. A menudo, los globals asignan más espacio en disco del que realmente se utiliza como función de los patrones de uso y nuestra estructura de bloques.
    • Empaquetado - Calcular el espacio real utilizado también proporcionará información sobre el "empaquetado" del global: qué tan densamente se almacenan los datos. A veces puede ser necesario o deseable almacenar los globals de manera más eficiente, especialmente si no se actualizan con frecuencia. Para sistemas con actualizaciones, inserciones o eliminaciones aleatorias, un empaquetado del 70% generalmente se considera óptimo para el rendimiento. Este valor fluctúa según la actividad. La holgura frecuentemente se correlaciona con las eliminaciones.
    • Coste de E/S - Lamentablemente, una gran precisión conlleva grandes requisitos de E/S. Iterar bloque por bloque de 8KB a través de una base de datos grande no sólo llevará mucho tiempo, sino que también puede impactar negativamente el rendimiento en sistemas que ya están cerca de sus límites previstos. Esto es mucho más costoso que determinar si un bloque está asignado. Esta operación tomará un tiempo del orden de (# de procesos paralelos) / (latencia de lectura) * (tamaño de la base de datos - espacio libre) para devolver una respuesta.

InterSystems proporciona varias herramientas para determinar el tamaño de los globals dentro de una base de datos específica. Generalmente, se necesita conocer tanto el nombre del global como la ruta completa del directorio de base de datos subyacente para determinar el tamaño. Para implementaciones más complejas, se requiere realizar cálculos para determinar el tamaño total de un global distribuido en múltiples bases de datos mediante el mapeo de nivel de subíndice.

Determinación de nombres globales

  • Utiliza el Extent Manager para listar los globals asociados con una tabla.  
    • SQL: Call %ExtentMgr.GlobalsUsed('Package.Class.cls')
  • Revisa la definición de almacenamiento dentro del Portal de Gestión, dentro de VS Code (o Studio), o consultando %Dictionary.StorageDefinition.
    • SQL: SELECT DataLocation FROM %Dictionary.StorageDefinition WHERE parent = 'Package.ClassName'
    • ObjectScript: write ##class(%Dictionary.ClassDefinition).%OpenId("Package.ClassName").Storages.GetAt(1).DataLocation
  • Las Globals con nombres Hasheados son comunes cuando las tablas se definen utilizando DDLs, es decir, CREATE TABLE. Este comportamiento puede modificarse especificando USEEXTENTSET y DEFAULTGLOBAL. El uso de globals con nombres hasheados y almacenar solo un índice por global ha demostrado beneficios en el rendimiento. Utilizo la siguiente consulta para listar los globales no evidentes en un espacio de nombres.
    • SQL para todas las Clases:
      SELECT Parent, DataLocation, IndexLocation, StreamLocation 
      FROM %Dictionary.StorageDefinition
      WHERE Parent->System = 0 AND DataLocation IS NOT NULL
    • SQL para Clases específicas:
      CALL %ExtentMgr.GlobalsUsed('Package.Class.cls')

Determinación de la ruta de la base de datos:

  • Para las implementaciones más simples donde un namespace no tiene asignaciones globales adicionales para datos de aplicación, a menudo es posible sustituir "." por el directorio. Este truco sintáctico indicará a la API que busque en el directorio actual del namespace actual.
  • Para implementaciones orientadas a SQL, CREATE DATABASE sigue nuestras mejores prácticas y crea DOS bases de datos: una para el código y otra para los datos. Es recomendable verificar la base de datos predeterminada de globales para el espacio de nombres dado en el Portal de Gestión o en el CPF.
  • Es posible determinar programáticamente el directorio de destino para un global particular (o subíndice) en el namespace actual:  
    • ObjectScript:
      set global = "globalNameHere" 
      set directory = $E(##class(%SYS.Namespace).GetGlobalDest($NAMESPACE, global),2,*)
  • Para implementaciones más complejas con muchos mareos de globals, puede ser necesario iterar a través de Config.MapGlobals en el espacio de nombres %SYS y sumar los tamaños de los globales:
    • SQL: SELECT Namespace, Database, Name FROM Config.MapGlobals

Determinación de tamaños globales:

Una vez determinado el nombre del global y la ruta de la base de datos de destino, es posible recopilar información sobre el tamaño del global. Aquí tenéis algunas opciones:

  • Verificación de Integridad: Realizar verificaciones de integridad nocturnas es una buena práctica. Una práctica aún mejor es realizarlas contra una copia de seguridad restaurada para verificar también el proceso de copia de seguridad y restauración, al mismo tiempo que se descarga la E/S al otro sistema. Este proceso verifica la integridad física de los bloques de la base de datos leyendo cada bloque asignado. Muestra en una tabla el espacio asignado de todos los globals y también el promedio de empaquetado de los bloques a lo largo del camino.
    • Echa un vistazo a la excelente publicación de Ray sobre Integrity Check performance.
    • En IRIS 2022.1 y versiones posteriores, las Verificaciones de Integridad ahora pueden incluso procesar en múltiples procesos un único global.
    • Ejemplo de Salida de Verificación de Integridad:
      Global: Ens.MessageHeaderD                            0 errors found   
      Top Pointer Level:    # of blocks=1      8kb (2% full)   
      Pointer Level:        # of blocks=25      200kb (19% full)   
      Bottom Pointer Level: # of blocks=3,257      25MB (79% full)   
      Data Level:           # of blocks=2,630,922      20,554MB (88% full)   
      Total:                # of blocks=2,634,205      20,579MB (88% full)   
      Elapsed Time = 238.4 seconds, Completed 01/17/2023 23:41:12  
  • %Library.GlobalEdit.GetGlobalSize – Los siguientes APIs pueden utilizarse para determinar rápidamente el tamaño asignado de un único global. Esto aún puede llevar algún tiempo para globals de varios terabytes.
    • ObjectScript: w ##class(%Library.GlobalEdit).GetGlobalSize(directory, globalName, .allocated, .used, 1)
    • Python embebido:
      import iris 
      allocated = iris.ref("")
      used =iris.ref("")
      fast=1
      directory = "/path/to/database"
      global = "globalName"
      iris.cls('%Library.GlobalEdit').GetGlobalSize(directory, global, allocated, used, fast)
      allocated.value
      used.value
  • %Library.GlobalEdit.GetGlobalSizeBySubscript – Esto es útil para determinar el tamaño de un subíndice o un rango de subíndices. Por ejemplo, determinar el tamaño de un índice incluirá todos los descendientes dentro del rango especificado. Advertencia: a partir de IRIS 2023.1 no existe una opción rápida ("fast") para devolver solo el tamaño asignado. Leerá todos los bloques de datos dentro del rango especificado.
    • ObjectScript: ##class(%Library.GlobalEdit).GetGlobalSizeBySubscript(directory, startingNode, EndingNode, .size)
  • %SYS.GlobalQuery.Size – Esta API es útil para examinar múltiples globals dentro de una base de datos, ya sea con filtros o sin ellos. Hay disponible un Procedimiento Almacenado SQL para clientes que interactúan principalmente con IRIS a través de SQL.
    • SQL: CALL %SYS.GlobalQuery_Size('database directory here', '','*',,,1)
  • ^%GSIZE – Ejecutar esta utilidad ya clásica y seleccionar "mostrar detalles" leerá cada bloque de datos para determinar el tamaño de los datos. Sin filtrar la lista de globales, podría leer casi toda la base de datos bloque por bloque con un solo hilo.
    • Ejecutar ^%GSIZE con detalles es la opción más lenta para determinar los tamaños de los globales. ¡Es mucho más lento que nuestras Verificaciones de Integridad, que están altamente optimizadas!
    • Hay otro punto de entrada adicional que devolverá el tamaño asignado para un global específico, incluido cuando está limitado a un subíndice. Desafortunadamente, no funciona en rangos de subíndices.
    • ObjectScript: write $$AllocatedSize^%GSIZE("global(""subscript"")")
  • Tamaño de la base de datos – El caso más sencillo para determinar el tamaño de un global es cuando hay solo un global dentro de una base de datos única. Simplemente resta el espacio total libre dentro de la base de datos del tamaño total de la base de datos. El tamaño de la base de datos está disponible desde el sistema operativo o a través de SYS.Database. A menudo utilizo una variación de este enfoque para determinar el tamaño de un global desproporcionadamente grande al restar la suma de todos los demás globales en la base de datos.
    • ObjectScript: ##class(%SYS.DatabaseQuery).GetDatabaseFreeSpace(directory, .FreeSpace)
    • SQL: call %SYS.DatabaseQuery_FreeSpace()
    • Embedded Python:
    • import iris
      freeSpace = iris.ref("")
      directory = "/path/to/database"
      iris.cls('%SYS.DatabaseQuery').GetDatabaseFreeSpace(directory, freeSpace)
      freeSpace.value  
  • Los Globals Privados de Proceso (PPGs, por sus siglas en inglés) son globales especiales con un alcance limitado a un proceso y que son almacenados dentro de IRISTEMP. A menudo no son enumerados por otras herramientas. Cuando IRISTEMP se expande rápidamente o reporta poco espacio libre, los PPGs suelen ser la explicación. Considerad examinar el uso por proceso de PPGs a través de %SYS.ProcessQuery.  
    • SQL: SELECT PID, PrivateGlobalBlockCount FROM %SYS.ProcessQuery ORDER BY PrivateGlobalBlockCount DESC

Preguntas para los lectores:

  1. ¿Con qué frecuencia seguís el tamaño de vuestros globales?
  2. ¿Qué hacéis con la información del tamaño de los globales?
  3. Para los usuarios centrados en SQL, ¿seguís el tamaño de los índices individuales?

 

Como extra, os recuerdo que disponéis de un paquete muy útil llamado SQL Utilities (de Benjamin de Boe) que incorporan mucho de lo que se trata en este artículo y aprovechan todas las ventajas de las nuevas funcionalidades del estimador de tamaño de globals.

Comentarios (0)1
Inicie sesión o regístrese para continuar