0 Seguidores · 168 Publicaciones

SQL is un lenguaje estándar para el almacenamiento, manipulación y recuperación de datos en bases de datos relacionales.

Artículo Dani Fibla · ago 9, 2021 3m read

¡Hola desarrolladores!

A veces, cuando desarrollamos una maqueta o una Prueba de Concepto (PoC), necesitamos una interfaz sencilla que proporcione datos en IRIS en JSON contra consultas SQL.

Y recientemente contribuí con un sencillo módulo que hace exactamente eso:

acepta una sentencia SQL y devuelve JSON.

¿Cómo se instala? Solo llama:

zpm "install sql-rest"

Si lo instalas en un namespace X, configurará un endpoint /sql en tu sistema, que aceptará solicitudes POST con una sentencia SQL  y te devolverá el resultado para los datos disponibles en el namespace X.

0
0 540
Artículo Ricardo Paiva · sep 9, 2019 3m read

¡Hola desarroladores!

¿Os parece que las consultas sobre el rango de fechas son demasiado lentas? ¿Os parece que el rendimiento de SQL es bajo?  ¡Tengo un curioso truco que podría ayudaros a solucionar estos problemas! (¡Los desarrolladores de SQL odian que sepáis estas cosas!)*

Si tenéis una clase que guarda los registros de hora cuando se añaden datos, entonces esos datos se ordenarán con vuestros valores IDKEY, es decir, TimeStamp1 < TimeStamp2  si y solo si la condición ID1 < ID2 se cumple para todos los valores ID y TimeStamp en la tabla - entonces podéis utilizar esta información para aumentar el rendimiento de las consultas en relación con los rangos de TimeStamp. Echad un vistazo a la siguiente tabla:

1
0 1240
Artículo Ricardo Paiva · jul 29, 2021 2m read

En SQL, la condición más frecuente WHERE se relaciona principalmente con el contenido de las filas en las que trabajas.
Por lo tanto, debe calcularse y verificarse para cada fila a la que accedas.
Distinto es el caso (y por eso la llamé ESTÁTICA) de una condición WHERE independiente de las filas a las que accedes.

0
0 178
Pregunta Yuri Marx · jun 9, 2021

¿Es posible ver el plan de ejecución de una sentencia SQL en IRIS?

Como esto:

explain plan for
select  e.ename,r.rname
from    employees  e
join    roles       r on (r.id = e.role_id)
join    departments d on (d.id = e.dept_id)
where   e.staffno <= 10
and     d.dname in ('Department Name 1','Department Name 2');

Que devuelve esto:

1
0 182
Artículo Ricardo Paiva · jun 10, 2021 2m read

En los buenos tiempos, calcular el tamaño de los datos, flujos e índices para una clase/tabla era fácil - solo había que ejecutar %GSIZE y revisar los globals D, S, e I, respectivamente.

Sin embargo, hoy en día el sharding, los nombres de los globals optimizados y los índices en globals separados producen una salida %GSIZE parecida a esta:

            Global Size Display of /irissys/data/IRIS/mgr/irisshard/
                              1:35 PM  Dec 02 2020

          IRIS.Msg       1     IRIS.MsgNames       1     IRIS.SM.Shard       1
       IS.DGoWeK.1   24359       IS.DGoWeK.2       3       IS.DGoWeK.3    2810
       IS.DGoWeK.4    2542        IS.V0Zli.1     373        IS.V0Zli.2       2
        IS.k22Ht.1  238028        IS.k22Ht.2       3        IS.k22Ht.3   25819
        IS.k22Ht.4    7426       ISC.Src.Jrn       1           ROUTINE       1
           oddBIND       1            oddCOM       1            oddDEF       1
            oddDEP       1            oddEXT       1           oddEXTR       1
            oddMAP       1           oddMETA       1            oddPKG       1
           oddPROC       1        oddPROJECT       1            oddSQL       1
 oddStudioDocument       1     oddStudioMenu       1           oddTSQL       1
            oddXML       1           rBACKUP       1              rINC       1
          rINCSAVE       1            rINDEX       1       rINDEXCLASS       1
         rINDEXEXT       7         rINDEXSQL       1              rMAC       1
          rMACSAVE       1              rMAP       1              rOBJ       1

      TOTAL:  301403

Claro, se pueden seguir las definiciones de almacenamiento y descodificar para entender a donde se fue el espacio, pero ya no es obvio.

Introduce en ClassSize query una función con valores de tabla (tvf) personalizada, que muestre los globals relacionados con las clases, su tamaño y su función.

Llámala con dos argumentos:

  • package: dónde buscar clases persistentes
  • fast: si es verdadero devuelve solo el espacio asignado

Esta es la apariencia de una combinación de clases sharded y non-sharded:

La limitación es que, de momento, solo la información sobre el shard actual es devuelta para las clases sharded.

0
0 154
Artículo Eduardo Anglada · jun 9, 2021 3m read
Este es un ejemplo de código que funciona en IRIS 2020.1 y en Caché 2018.1.3 
No se mantendrá sincronizado con las nuevas versiones      
¡NO está soportado por el servicio de soporte de InterSystems!   

Los globals en Caché, Ensemble e IRIS normalmente son invisibles a través de SQL. En este ejemplo se muestra cómo verlos desde SQL. Los globals se muestran como el contenido de una tabla con sus subíndices y su contenido almacenado.
El global que se quiere mostrar se pasa a SQL por medio de una condición estática WHERE que requiere de 3 parámetros:

  • el nombre del global (obligatorio)
  • el subíndice de inicio (opcional)
  • el subíndice de parada (opcional)

Solo con proporcionar el nombre del global se obtiene todo su contenido. Los globals también se pueden obtener usando la referencia extendida y, como se trata de una tabla SQL, se pueden aplicar todas las condiciones adicionales que queramos.

Ten cuidado: Poner correctamente las comillas entre SQL y Caché/Ensemble/IRIS puede ser todo un desafío.

Por ejemplo:
select * from zrcc_G.dump where zrcc_G.Dump('^|"CACHE"|Sample.PersonD',2,4)=1

ID         Global           Subscript         Value
1   ^|"CACHE"|Sample.PersonD    (2) $lb("",792533244,"GlobaDynamics Holdings Inc.",64256,"C1787","Y5365","A5","A658","R1770","","Ironhorse,Alice D.","T3710","O3","I4011","W8367","557-37-6758",83059958205089661,"1841-01-02 00:00:00")
2   ^|"CACHE"|Sample.PersonD    (3) $lb("",862705606,"TeleLateral Associates",34553,"V8155","T8918","X9","V8732","K1167","","Eisenstien,Peter E.","H208","C8","Q2015","Q3357","702-46-8467",57275722714358892,"2020-06-23 13:27:18")
3   ^|"CACHE"|Sample.PersonD    (4) $lb("",677194559,"RoboSoft Group Ltd.",52738,"F4851","Z364","S8","O6888","O4367","","Eagleman,Clint C.","C8051","R6","V1659","C9814","664-33-8809",-53705244349891319,"2020-06-23 13:27:18")

select TOP 15 * from zrcc_G.dump where zrcc_G.Dump('^%SYS','"JOURNAL"')=1

ID  Global         Subscript             Value
1   ^%SYS   ("JOURNAL")            0
2   ^%SYS   ("JOURNAL","ALTDIR")   "C:\InterSystems\IRIS\altjournal\"
3   ^%SYS   ("JOURNAL","CURDIR")   "C:\InterSystems\IRIS\mgr\journal\"
4   ^%SYS   ("JOURNAL","CURRENT")  "1^C:\InterSystems\IRIS\mgr\journal\20200801.009"
5   ^%SYS   ("JOURNAL","EXPSIZE")  0
6   ^%SYS   ("JOURNAL","LAST")     "1^C:\InterSystems\IRIS\mgr\journal\20200801.009"
7   ^%SYS   ("JOURNAL","LIFESPAN","FILE")   "2,2"
8   ^%SYS   ("JOURNAL","MAXSIZE")    1073741824
9   ^%SYS   ("JOURNAL","PREFIX")   ""
10  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.001")    "2019-11-07 17:38:30"
11  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.002")    "2019-11-07 17:38:30"
12  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.003")    "2019-11-07 17:38:30"
13  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.004")    "2019-11-07 17:38:30"
14  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191104.005")    "2019-11-08 08:39:47"
15  ^%SYS   ("JOURNAL","PURGED","c:\intersystems\iris\mgr\journal\20191105.001")    "2019-11-08 08:39:47"
0
0 159
Artículo Eduardo Anglada · mayo 27, 2021 8m read

En este artículo voy a mostrar los resultados de una comparación entre IRIS y Postgress manejando datos Astronómicos.

Introducción

Desde siempre el cielo nocturno nos ha fascinado. Todos hemos soñado con las estrellas y la posibilidad de que haya vida en otros planetas.

0
1 235
Artículo David Reche · jul 23, 2019 5m read

¡Hola a tod@s!

Cuando hablo con alguien de perfil técnico por primera vez acerca de InterSystems IRIS, siempre comienzo hablando de que en el centro de todo InterSystems IRIS es una Base de Datos Multimodelo. En mi opinión, esta es la mayor ventaja (desde la visión de Sistemas de Bases de Datos), ya que:

  • ¿Quieres obtener un resumen o partes específicas de tus datos? Usa SQL!
  • ¿Necesitas trabajar de forma intensiva con un registro? Usa Objetos!
  • ¿Quieres establecer un valor y conoces la clave? Piensalo de nuevo. Usa globals!

Y en todos los casos, el dato está almacenado de forma única. ¡Tú eliges la manera en la que quieres acceder al mismo!!

De un primer vistazo es una bonita historia - corta, concisa y con un mensaje; pero cuando se empieza a trabajar con InterSystems IRIS, comienzan a surgir  preguntas: ¿Cómo están relacionados las clases, las tablas y los globals? ¿Qué son cada uno para el otro? ¿Cómo se almacenan realmente los datos?

En este artículo voy a tratar de responder estas preguntas y explicar qué está pasando realmente.

3
0 618
Artículo Ricardo Paiva · mayo 13, 2021 13m read

El orden es una necesidad para todos, pero no todos lo entienden de la misma manera (Fausto Cercignani)

Nota de traducción: este articulo se publicó originalmente basado en Caché. Para esta traducción se revisó todo el contenido usando InterSystems IRIS.

Descargo de responsabilidad: En este artículo se utilizan el ruso y el alfabeto cirílico como ejemplos, pero esto solamente es importante para las personas que utilizan InterSystems IRIS en lugares en los que no se habla inglés.Ten en cuenta que este artículo se refiere principalmente a las compilaciones de NLS, que son diferentes a las compilaciones de SQL. Las compilaciones en SQL (por ejemplo, SQLUPPER, SQLSTRING, EXACT que significa que no hay compilación, TRUNCATE, etc.) son funciones reales que se aplican de manera explícita a algunos valores, y cuyos resultados a veces se almacenan explícitamente en los subíndices de los globals. De hecho, cuando se almacenan en subíndices, de forma natural estos valores seguirían la compilación de NLS (“Compilaciones de SQL y NLS”).

En InterSystems IRIS, todo se almacena en globals: datos, metadatos, clases, rutinas. Los globals son persistentes. Los nodos de los globals se ordenan por los valores de los subíndices, y son almacenados en dispositivos de almacenamiento, sin un orden establecido de inserción, pero de forma ordenada para un mejor resultado en las búsquedas y disk fetch performance:

USER>set ^a(10)=""
USER>set ^a("фф")=""
USER>set ^a("бб")=""
USER>set ^a(2)=""
USER>zwrite ^a
^a(2)=""
^a(10)=""
^a("бб")=""
^a("фф")=""

Durante el proceso de clasificación, InterSystems IRIS distingue números y cadenas - 2 se maneja como un número y se clasifica antes que 10. El comando ZWrite y las funciones $Order y $Query devuelven subíndices en el mismo orden en que se almacenan estos subíndices: primero se almacena una cadena vacía (la cual no se puede utilizar como subíndice), después los números negativos, cero, los números positivos, y luego las cadenas en el orden que se define en la compilación (compilación).

La compilación estándar en InterSystems IRIS se llama (como era de esperar) IRIS standard, y clasifica cada cadena de acuerdo a sus códigos de caracteres Unicode.

La compilación de las matrices locales en el proceso actual se define en local (Management Portal > System administration > Configuration > System Configuration > National Language Settings > Locale Definitions). La configuración local rusa para las instalaciones Unicode en InterSystems IRIS es rusw y la compilación predeterminada para rusw es Cyrillic3. Otras posibles compilaciones en la rusw local son IRIS standard, Cyrillic1, Cyrillic3, Cyrillic4, Ukrainian1.

ClassMethod ##class(%Collate).SetLocalName() configura la compilación de las matrices locales en el proceso actual:

USER>write ##class(%Collate).GetLocalName()
Cyrillic3
USER>write ##class(%Collate).SetLocalName("IRIS standard")
1
USER>write ##class(%Collate).GetLocalName()
IRIS standard
USER>write ##class(%Collate).SetLocalName("Cyrillic3")
1
USER>write ##class(%Collate).GetLocalName()
Cyrillic3

Por cada compilación, hay una compilación alterna que clasifica los números como cadenas. El nombre de esa compilación contiene la variable “string” al final:

USER>write ##class(%Collate).SetLocalName("IRIS standard string")
1
USER>kill test

USER>set test(10) = "", test(2) = "", test("фф") = "", test("бб") = ""

USER>zwrite test
test(10)=""
test(2)=""
test("бб")=""
test("фф")=""

USER>write ##class(%Collate).SetLocalName("IRIS standard")
1
USER>kill test

USER>set test(10) = "", test(2) = "", test("фф") = "", test("бб") = ""

USER>zwrite test
test(2)=""
test(10)=""
test("бб")=""
test("фф")=""

IRIS standar y Cyrillic3

IRIS standar clasifica los caracteres según sus códigos:

 write ##class(%Library.Collate).SetLocalName("IRIS standard"),!
 write ##class(%Library.Collate).GetLocalName(),!
 set letters = "абвгдеёжзийклмнопрстуфхцчщщьыъэюя"
 set letters = letters _ $zconvert(letters,"U")
 kill test

 //fill local array “test” with data
 for i=1:1:$Length(letters) {
     set test($Extract(letters,i)) = ""
 }

 //print test subscripts in sorted order
 set l = "", cnt = 0
 for  {
     set l = $Order(test(l))
     quit:l=""
     write l, " ", $Ascii(l),","
     set cnt = cnt + 1
     write:cnt#8=0 !
 }

USER>do ^testcol
1
IRIS standard
Ё 1025,А 1040,Б 1041,В 1042,Г 1043,Д 1044,Е 1045,Ж 1046,
З 1047,И 1048,Й 1049,К 1050,Л 1051,М 1052,Н 1053,О 1054,
П 1055,Р 1056,С 1057,Т 1058,У 1059,Ф 1060,Х 1061,Ц 1062,
Ч 1063,Щ 1065,Ъ 1066,Ы 1067,Ь 1068,Э 1069,Ю 1070,Я 1071,
а 1072,б 1073,в 1074,г 1075,д 1076,е 1077,ж 1078,з 1079,
и 1080,й 1081,к 1082,л 1083,м 1084,н 1085,о 1086,п 1087,
р 1088,с 1089,т 1090,у 1091,ф 1092,х 1093,ц 1094,ч 1095,
щ 1097,ъ 1098,ы 1099,ь 1100,э 1101,ю 1102,я 1103,ё 1105,

Las letras cirílicas se imprimen en el mismo orden que aparecen en el alfabeto ruso, excepto la “ё” y la “Ё”. Sus códigos de caracteres Unicode están desordenados. “Ё” debe compilarse entre “Е” y “Д”, y “ё” entre “е” y “д”. Por eso la configuración local rusa necesita su propia compilación - Cyrillic3, que tiene las letras en el mismo orden que el alfabeto ruso:

USER>do ^testcol
1
Cyrillic3
А 1040,Б 1041,В 1042,Г 1043,Д 1044,Е 1045,Ё 1025,Ж 1046,
З 1047,И 1048,Й 1049,К 1050,Л 1051,М 1052,Н 1053,О 1054,
П 1055,Р 1056,С 1057,Т 1058,У 1059,Ф 1060,Х 1061,Ц 1062,
Ч 1063,Щ 1065,Ъ 1066,Ы 1067,Ь 1068,Э 1069,Ю 1070,Я 1071,
а 1072,б 1073,в 1074,г 1075,д 1076,е 1077,ё 1105,ж 1078,
з 1079,и 1080,й 1081,к 1082,л 1083,м 1084,н 1085,о 1086,
п 1087,р 1088,с 1089,т 1090,у 1091,ф 1092,х 1093,ц 1094,
ч 1095,щ 1097,ъ 1098,ы 1099,ь 1100,э 1101,ю 1102,я 1103,

Caché ObjectScript utiliza un operador binario especial ]] — «ordenar después». Devuelve el número 1, si el subíndice con el primer operador se ubica después del segundo operador, en caso contrario devuelve el número 0:

USER>write ##class(%Library.Collate).SetLocalName("IRIS standard"),!
1
USER>write "А" ]] "Ё"
1
USER>write ##class(%Library.Collate).SetLocalName("Cyrillic3"),!
1
USER>write "А" ]] "Ё"
0

Globals y compilaciones

Globals diferentes en la misma base de datos pueden tener una compilación diferente. Cada base de datos tiene una opción de configuración - compilación predeterminada para los nuevos globals. Justo después de que se realiza la instalación, todas las bases de datos, excepto USER, utilizan la compilación predeterminada de IRIS standard. La compilación predeterminada para la base de datos USER se determina por la configuración local. Para rusw es Cyrillic3.

Para crear un global con una compilación que no sea la predeterminada para su base de datos, utiliza ##class(%GlobalEdit)##class(%GlobalEdit).Create method:

USER>kill ^a
USER>write ##class(%GlobalEdit).Create(,"a",##class(%Collate).DisplayToLogical("IRIS standard"))

Hay una columna de compilación para cada global en la lista de globals en el Management Portal (System Explorer > Globals).

No es posible cambiar la compilación de los globals actuales. Deberías crear un global con una nueva compilación y copiar los datos con el comando Merge. Para realizar la conversión masiva de globals utiliza ##class(SYS.Database).Copy()

Cyrillic4, Cyrillic3 y umlauts

Parece ser que convertir el subíndice de una cadena a un formato interno lleva, evidentemente, más tiempo con la compilación Cyrillic3 que con la compilación IRIS estándar. Por lo tanto, insertar y buscar la matriz global (o local) con la compilación Cyrillic3 es más lento. Caché 2014.1 incluye una nueva compilación - Cyrillic4, que tiene el mismo orden correcto de letras que Cyrillic3, y un mejor rendimiento.

for collation="IRIS standard","Cyrillic3","Cyrillic4" {
     write ##class(%Library.Collate).SetLocalName(collation),!
     write ##class(%Library.Collate).GetLocalName(),!
     do test(100000)
 }
 quit
test(C)
 set letters = "абвгдеёжзийклмнопрстуфхцчщщьыъэюя"
 set letters = letters _ $zconvert(letters,"U")

 kill test
 write "test insert: "
 //fill local array “test” with data
 set z1=$zh
 for c=1:1:C {
     for i=1:1:$Length(letters) {
         set test($Extract(letters,i)_"плюс длинное русское слово" _ $Extract(letters,i)) = ""
     }
 }
 write $zh-z1,!

 //looping through test subscripts
 write "test $Order: "
 set z1=$zh
 for c=1:1:C {
     set l = ""
     for  {
         set l = $Order(test(l))
         quit:l=""
     }
 }
 write $zh-z1,!

USER>do ^testcol
1
IRIS standard
test insert: 1.520673
test $Order: 2.062228
1
Cyrillic3
test insert: 3.541697
test $Order: 5.938042
1
Cyrillic4
test insert: 1.925205
test $Order: 2.834399

Cyrillic4 aún no es la compilación predeterminada para la configuración local rusw, pero puedes definir tu propia configuración local basada en rusw y especificar Cyrillic4 como compilación predeterminada para las matrices locales. O puedes configurar Cyrillic4 como la nueva compilación predeterminada para los globals en la configuración de la base de datos.

Cyrillic3 es más lento que IRIS estándar y Cyrillic4, porque se basa en un algoritmo más general que clasificar dos cadenas basándose en códigos de caracteres individuales.

En alemán, la letra ß debería compilarse como ss durante el proceso de clasificación. InterSystems IRIS respeta esa regla:

USER>write ##class(%Collate).GetLocalName()
German3
USER>set test("Straßer")=1
USER>set test("Strasser")=1
USER>set test("Straster")=1
USER>zwrite test
test("Strasser")=1
test("Straßer")=1
test("Straster")=1

Ten en cuenta que la clasificación ordena las cadenas en subíndices. Específicamente, las primeras cuatro letras de la primera cadena son “Stras”, después “Straß”, y otra vez “Stras”. Es imposible clasificar las cadenas de esa manera, si la compilación solo es una clasificación basada en los códigos de caracteres separados.

Otro ejemplo es el finlandés, donde “v” y “w” deben compilarse como la misma letra. Las reglas para compilar el idioma ruso son más simples: a cada letra se le asigna un código específico y la clasificación mediante estos códigos es suficiente. Eso permitió mejorar el rendimiento de la compilación Cyrillic4 sobre Cyrillic3.

Compilación y SQL

No hay que confundir la compilación de una matriz con la compilación de SQL. Esta última es la conversión que se implementa en la cadena antes de que realice una comparación, o que se utilice como subíndice en el índice global. SQLUPPER es la compilación predeterminada de SQL en InterSystems IRIS. En esta compilación todos los caracteres se convierten en mayúsculas, se eliminan los caracteres de espacio y se añade un espacio al inicio de la cadena. Otras compilaciones SQL (EXACT, SQLSTRING, TRUNCATE) se describen en la documentación.

Es fácil complicar las cosas cuando diferentes globals en la misma base de datos tienen diferente compilación, y las matrices locales tienen otra compilación. SQL utiliza la base de datos IRISTEMP para los datos temporales. La compilación predeterminada para los globals en IRISTEMP puede ser diferente de la compilación para la configuración local de InterSystems IRIS.

Hay una regla principal - para que las consultas ORDER BY en SQL devuelvan las filas en el orden esperado, la compilación de los globals donde se almacenan los datos y los índices de las tablas relevantes deben ser la misma que la compilación predeterminada de la base de datos IRISTEMP y la compilación de las matrices locales. Para obtener más información, consulta el párrafo en la documentación “Compilaciones de SQL y NLS”.

Vamos a crear la clase de prueba:

Class Collation.test Extends %Persistent
{

Property Name As %String;

Property Surname As %String;

Index SurInd On Surname;

ClassMethod populate()
{
    do ..%KillExtent()

    set t = ..%New()
    set t.Name = "Павел", t.Surname = "Ёлкин"
    write t.%Save()

    set t = ..%New()
    set t.Name = "Пётр", t.Surname = "Иванов"
    write t.%Save()

    set t = ..%New()
    set t.Name = "Прохор", t.Surname = "Александров"
    write t.%Save()
}

}

Añade datos a la clase (más tarde puedes intentar utilizar las palabras del ejemplo anterior con el alemán):

USER>do ##class(Collation.test).populate()

Realiza la consulta:

![](https://community.intersystems.com/sites/default/files/inline/images/0-order-by-name-wrong.png)

Ese es el resultado inesperado. La pregunta principal es: ¿por qué los nombres no se ordenan alfabéticamente? (Павел, Пётр, Прохор)? Veamos el plan de consultas:

![](https://community.intersystems.com/sites/default/files/inline/images/1-order-by-name-plan.png)

Las palabras clave de este plan son “populates temp-file”. El motor SQL decidió utilizar una estructura temporal para realizar esta consulta. Aunque se llama "file" ("archivo"), en realidad se trata de un global process-private y en algunos casos es una matriz local. Con los valores de los subíndices de este global se ordenarán, en este caso particular, nombres de personas. Los globals process-private se almacenan en la base de datos IRISTEMP y la clasificación predeterminada para los nuevas globals en IRISTEMP es IRIS estándar.

Otra pregunta razonable es por qué “ё” se devuelve a la parte superior y no a la inferior (recuerda, en IRIS estándar “ё” se clasifica después de todas las letras rusas; y “Ё”, antes). Los subíndices del global temporal no son el valor exacto del campo Name, sino los valores en mayúsculas de Name (SQLUPPER es la compilación de SQL predeterminada para las cadenas), y, por tanto, devuelve “Ё” antes que otros caracteres.

Al modificar la compilación predeterminada mediante la función %Exact, todavía la recibiríamos de forma incorrecta, pero al menos “ё” se clasifica después de otras letras, como un resultado esperado.

![](https://community.intersystems.com/sites/default/files/inline/images/2-order-by-exact-name.png)

Por el momento, no vamos a cambiar la compilación predeterminada de IRISTEMP - vamos a verificar las consultas con la columna Surname. El índice de esta columna se almacena en el global ^Collation.testI. La compilación de ese global es Cyrillic3, así que deberíamos ver el orden correcto de las filas:

![](https://community.intersystems.com/sites/default/files/inline/images/3-order-by-surname-wrong.png)

Equivocado de nuevo — “Ё” debería ir entre “А” y “И”. Echa un vistazo al plan de consulta:

![](https://community.intersystems.com//sites/default/files/inline/images/4-order-by-surname-plan.png)

Los datos del índice no son suficientes para obtener los valores originales del campo Surname porque SQLUPPER se aplica a los valores del índice SurInd. El motor SQL decidió utilizar los valores de la propia tabla y ordenar los valores en el archivo temporal, tal como hizo antes con la columna Name.

En la consulta podemos indicar que estamos de acuerdo con que los apellidos se escriban en mayúsculas. El orden será el correcto porque las filas se tomarán directamente del índice global ^Collation.testI:

![](https://community.intersystems.com//sites/default/files/inline/images/5-order-by-surname-sqlupper.png)

El plan de consulta es como se esperaba:

![](https://community.intersystems.com//sites/default/files/inline/images/6-order-by-surname-sqlupper-plan.png)

Ahora hagamos lo que deberíamos haber hecho hace mucho tiempo: cambiar la compilación predeterminada de la base de datos IRISTEMP a Cyrillic3 (o Cyrillic4).

Las consultas que utilizan archivos temporales darán como resultado filas en el orden correcto:

![](https://community.intersystems.com//sites/default/files/inline/images/7-order-by-name-ok.png)
![](https://community.intersystems.com//sites/default/files/inline/images/8-order-by-surname-ok.png)

Resumen

  • Si no te interesan los matices de los alfabetos locales, utiliza la compilación IRIS estándar.
  • Algunas compilaciones (Cyrillic4) tienen un mejor rendimiento que otras (Cyrillic3).
  • Comprueba que IRISTEMP tiene la misma compilación que tu base de datos principal y matrices locales. Nota de traducción: para ver una lista con las collations disponibles y las cargadas en la instancia, abre una ventana de Terminal, cambia al namespace % SYS% e ingresa el comando DO ^ COLLATE.
0
0 152
Artículo Alberto Fuentes · abr 7, 2021 6m read

Hola a todos! Os traigo hoy un ejemplo de código que compartía Robert Cemper para mostrar por SQL los registros de error almacenados en ^ERRORS.

Este es un ejemplo de código que funciona en Caché 2018.1.3 e IRIS 2020.2 
No se mantendrá sincronizado con las nuevas versiones. 
Es un ejemplo de código y como tal no está soportado por el Soporte de InterSystems

Los errores en IRIS/Caché/Ensemble se registran entre otros en la global ^ERRORS. Como este mecanismo se remonta a muchas versiones atrás (décadas del milenio anterior!) su estructura está lejos de las estructuras de almacenamiento de SQL típicas.

El global se escribe mediante la rutina ^%ETN.int y el contenido se hace visible desde la línea de comandos del terminal mediante la rutina ^%ERN o en el Portal de Administración como Log de Errores de la Aplicación.

Por defecto no está disponible a través de SQL ya que no hay ninguna clase que lo presente como tabla. Por varias razones:

  • Cuando se diseñó, era una buena práctica tener estructuras similares a índices en los mismos globals que los datos. Si digo "similares", significa que no sirve para SQL.
  • El contenido de los objetos va a niveles más profundos que el resto. En consecuencia, la profundidad de los subíndices (normalmente IdKey) varía de 3 a 11.

^ERRORS es independiente en cada namespace. Está estructurado por Day, SequenceByDay, Type, ItemName (Variable, OREF),Value.

zrcc.ERRORStack muestra esta información como tabla SQL.
El contenido más profundo de los objetos se hace visible por la consulta personalizada incluida.
El procedimiento SQL zrcc.ERRORStack_Dump(Day,Sequence) devuelve todo el contenido disponible y presenta subíndices y valores como se ve en la lista de globals.

A continuación veremos cómo sacar partido de estas utilidades:

Primero: localiza el día que te interese y el número de secuencia con la ayuda de SQL

Por ejemplo: SELECT * FROM zrcc.ERRORStack where item='$ZE'

        Day  Seq    Stk Type    Item    Value
    2020-07-02  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1
    2020-07-07  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1
    2020-07-15  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1
    2020-07-20  1    0     V      $ZE   &lt;LOG ENTRY>
    2020-07-26  1    0     V      $ZE   &lt;WRITE>zSend+204^%Net.HttpRequest.1

A continuación, llama al procedimiento en SQL:   CALL zrcc.ERRORStack_Dump('2020-07-26',1)

Row count: 541 Performance: 0.026 seconds  6557 global references
Ref                                 Value
2020-07-26,1,"*STACK",0,"V","Routine")  zSend+204^%Net.HttpRequest.1
2020-07-26,1,"*STACK",1,"I")    1^S^^^0^
2020-07-26,1,"*STACK",1,"L")    1 SIGN ON
2020-07-26,1,"*STACK",1,"S")    
2020-07-26,1,"*STACK",1,"T")    SIGN ON
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""Analyzer""")   6
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""Architect""")  7
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""DashboardViewer""")    8
2020-07-26,1,"*STACK",1,"V","%dsTrackingKeys","N","""ResultSet""")  9
2020-07-26,1,"*STACK",1,"V","%objcn")   2
2020-07-26,1,"*STACK",3,"V","Task") &lt;OBJECT REFERENCE>[1@%SYS.Task]
2020-07-26,1,"*STACK",3,"V","Task","OREF",1)    142
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,0)  3671
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,1)  +----------------- general information ---------------
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,2)  | oref value: 1
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,3)  | class name: %SYS.Task
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,4)  | %%OID: $lb("13","%SYS.Task")
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,5)  | reference count: 5
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,6)  +----------------- attribute values ------------------
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,7)  | %Concurrency =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,8)  4 &lt;Set>
- - - 
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,53) | EmailOutput =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,54) 0
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,55) | EndDate =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,56) ""
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,57) | Error =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,58) "&lt;WRITE>zSend+204^%Net.HttpRequest.1"
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,59) | Expires =
- - -
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,111)    | Status =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,112)    "0 "_$lb($lb(5002,"POST to Server Failed",,,,,,,,$lb(,"%SYS",$lb("$^zSend+204^%Net.HttpRequest.1 +1","$^zPost+1^%Net.HttpRequest.1 +1","$^zSendData+20^FT.Collector.1 +1","$^zTransfer+12^FT.Collector.1 +1","$^zOnTask+3^%SYS.Task.FeatureTracker.1 +1","D^zRunTask+74^%SYS.TaskSuper.1 +1","$^zRunTask+54^%SYS.TaskSuper.1 +1","D^zRun+26^%SYS.TaskSuper.1 +1"))),$lb(6085,"ISC.FeatureTracker.SSL.Config","SSL/TLS error in SSL_connect(), SSL_ERROR_SSL: protocol error, error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed",,,,,,,$lb(,"%SYS",$lb("e^zSend+303^%Net.HttpRequest.1^1","e^zPost+1^%Net.HttpRequest.1^1","e^zSendData+20^FT.Collector.1^1","e^zTransfer+12^FT.Collector.1^1","e^zOnTask+3^%SYS.Task.FeatureTracker.1^1","e^zRunTask+74^%SYS.TaskSuper.1^1","d^zRunTask+54^%SYS.TaskSuper.1^1","e^zRun+26^%SYS.TaskSuper.1^1","d^^^0"))))/* ERROR #5002: Cache error: POST to Server Failed- ERROR #6085: Unable to write to socket with SSL/TLS configuration 'ISC.FeatureTracker.SSL.Config', error reported 'SSL/TLS error in SSL_connect(), SSL_ERROR_SSL: protocol error, error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed' */
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,113)    | SuspendOnError =
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,114)    0
2020-07-26,1,"*STACK",3,"V","Task","OREF",1,115)    | Suspended =
- - -
2020-07-26,1,"*STACK",6,"V","Status1")  1
2020-07-26,1,"*STACK",6,"V","Task") &lt;OBJECT REFERENCE>[1@%SYS.Task]
2020-07-26,1,"*STACK",6,"V","Task","OREF",1)    142
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,0)  3671
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,1)  +----------------- general information ---------------
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,2)  | oref value: 1
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,3)  | class name: %SYS.Task
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,4)  | %%OID: $lb("13","%SYS.Task")
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,5)  | reference count: 5
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,6)  +----------------- attribute values ------------------
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,7)  | %Concurrency =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,8)  4 &lt;Set>
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,9)  | DailyEndTime =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,10) 0
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,11) | DailyFrequency =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,12) 0
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,13) | DailyFrequencyTime =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,14) ""
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,15) | DailyIncrement =
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,16) ""
2020-07-26,1,"*STACK",6,"V","Task","OREF",1,17) | DailyStartTime =
- - - 
2020-07-26,1,"*STACK",12,"V","%00000","N","""JournalState""")   12
2020-07-26,1,"*STACK",13,"I")   13^Z^ETNERRB^%ETN^0
2020-07-26,1,"*STACK",13,"L")   13 ERROR TRAP S $ZTRAP="ETNERRB^%ETN"
2020-07-26,1,"*STACK",13,"S")   S $ZTRAP="ETNERRB^%ETN"
2020-07-26,1,"*STACK",13,"T")   ERROR TRAP

541 row(s) affected
0
0 200
Artículo Jose-Tomas Salvador · feb 10, 2021 4m read

Hay tres aspectos muy importantes en cualquier conversación sobre el rendimiento de SQL: los Índices, el TuneTable, y el Plan de ejecución. En los PDFs adjuntos a este artículo se incluyen presentaciones antiguas sobre estos temas. En los enlaces a nuestra documentación debajo, se ofrece más información sobre estos y otros asuntos relacionados con el rendimiento de SQL. La formación online también refuerza varios de estos temas. Además, hay varios artículos de la Comunidad de Desarrolladores que están relacionados con el rendimiento de SQL y que mostramos a continuación.

Hay bastantes repeticiones en la información que se muestra a continuación.  Los aspectos más importantes a considerar sobre el rendimiento de SQL son:

  • Los tipos de índices que están disponibles
  • Por qué utilizar un tipo de índice en lugar de otro
  • La información que TuneTable recaba para crear una tabla y lo que esto significa para Optimizer
  • Cómo leer un Plan de ejecución para comprender mejor si una consulta es buena o mala
1
1 113
Pregunta Mathew Lambert · ene 13, 2021

¿Alguien sabe si hay una manera fácil de saber si la ejecución del comando $ System.SQL.PurgeForTable ha ido bien / mal?

La documentación describe que se devuelve un string, pero de hecho hay un bonito  Quit ""  en el código.

¿Quizás dentro de PurgeForTable ^% apiSQL hay alguna variable de proceso establecida cuando va bien / mal?

¡Muchas gracias!

3
0 157
Pregunta Ba Moser · ago 25, 2020

Yo uso estas clases de ejemplo:
Class Sample.Address Extends (%SerialObject, %Populate)
{Property Street As %String;
Property City As %String;
Property State As %String(POPSPEC = "USState()");
Property Zip As %String;}
Class Sample.Person1 Extends (%Persistent%Populate)
{  Property Name As %String;
Property Home As Sample.Address;
Property AR As array Of Sample.Address; }

En SQL es Table Sample.Person1

No hay problema para definir INDEX on Home_State

But Table Sample.Person1_AR

Cómo definir un INDEX on AR_State ?
Index st On AR.State;

¡No compila!

1
0 148
Artículo Nancy Martínez · jul 22, 2020 8m read

Ejemplos de Mapeos

Obviamente, si tienes un cuatro artículo en la trilogía, debes apostar por las ganancias económicas y escribir el quinto, ¡así que aquí está!

Nota: Hace muchos años, Dan Shusman me dijo que el mapeo de globals es una forma de arte. No existe una manera correcta o incorrecta de hacerlo. El modo en que interpretes los datos te llevará al tipo de mapeo que realizas. Como siempre, existe más de una forma de llegar a la respuesta final. Según vayas revisando mis ejemplos, verás que hay algunos en los que se mapean el mismo tipo de datos, pero de distintas maneras.

0
0 190
Artículo Bernardo Linarez · ago 29, 2019 3m read

¡Hola a tod@s!

El Portal de Administración del Sistema Caché incluye una potente herramienta de consultas en SQL basada en la web, aunque para algunas aplicaciones lo más conveniente es utilizar un cliente dedicado SQL que esté instalado en la PC del usuario.

SQuirreL SQL es un conocido cliente SQL de código abierto construido en Java, que utiliza JDBC para conectarse a un DBMS. Como tal, podemos configurar SQuirreL para que se conecte a Caché usando el controlador JDBC en Caché.

Encontrar el controlador JDBC de Caché en archivos JAR

2
0 1972
Anuncio Esther Sanchez · jun 26, 2020

¡Hola Comunidad!

Os traemos el cuarto episodio de Data Points, el podcast de InterSystems en inglés. En esta ocasión, charlamos con @Benjamin De Boe, que nos explica algunas de las cosas que podéis hacer para optimizar vuestras consultas SQL en InterSystems IRIS.

Todos hemos oído — tanto de nosotros mismos como de otros — la queja "esto va demasiado lento". Creo que Benjamin ha hecho un gran trabajo revisando todas las cosas en las que os podeis fijar en vuestras consultas en IRIS para descubrir lo que se puede mejorar.

0
0 114
Artículo Ricardo Paiva · mar 26, 2020 14m read

Este es el primero de dos artículos sobre los índices SQL.

Parte 1 - Conoce tus índices

¿Qué es un índice?

Recuerda la última vez que fuiste a una biblioteca. Normalmente, los libros están ordenados por temática (y luego autor y título) y cada repisa tiene un cartel en el extremo con un código que describe la temática de los libros. Si necesitaras libros de un cierto tema, en lugar de caminar por cada pasillo y leer la descripción en la parte interior de cada libro, podrías dirigirte directamente al estante cuyo cartel describa la temática que buscas y elegir tus libros de allí. Sin esos carteles, el proceso de encontrar los libros que quieres, habría sido muy lento.

Un índice SQL tiene la misma función general: mejorar el rendimiento, al ofrecer una referencia rápida del valor de los campos para cada fila de una tabla.

Configurar índices es uno de los pasos más importantes a la hora de preparar tus clases para un rendimiento óptimo de SQL.

1
1 328
Artículo Ricardo Paiva · mayo 15, 2020 9m read

¡Hola desarrollador!

Si has leído la parte 1 de este artículo, ya tienes una buena idea del tipo de índices que necesitas para tus clases y cómo definirlos. Lo siguiente es saber cómo gestionarlos.

Plan de consultas

(RECUERDA: Al igual que cualquier modificación en una clase, añadir índices en un sistema en producción conlleva riesgos: si los usuarios están actualizando o accediendo a datos mientras se rellena un índice, podrían obtener resultados vacíos o incorrectos a sus consultas, o incluso dañar los índices que se están formando. Ten en cuenta que hay pasos adicionales para definir y usar índices en un sistema en producción. Estos pasos se analizarán en esta sección, y se detallan en nuestra documentación).

1
0 279