Actualizaciones en Bases de Datos

 Así  como las plataformas de desarrollo van evolucionando, los paradigmas en que éstas están basadas van recreándose, adecuándose a las nuevas exigencias, otro tanto ocurre con las bases de datos

Sin embargo, en este último caso la evolución es más silenciosa y no pocas veces termina pasando desapercibida. Quizás esto sea atribuíble a que las tecnologías de bases de datos, por estar ligadas a unos pocos aspectos concretos del software (persistencia, inteligencia de negocios, etc) no suelen despertar en los desarrolladores el mismo nivel de interés que el que logran las plataformas de desarrollo. Plataformas como Java EE o .NET, pero también el stack conocido como LAMP (por Linux, Apache, MySQL y un enjambre de lenguajes hasta hace un tiempo compuesto por PHP, Python y Perl, pero ahora Ruby se sumó a la partida) también contemplan acceso a datos en una forma más general la que, además, sirve para el resto de las otras cosas. Así es como las bases de datos, finalmente, no generan la misma atracción

Como consecuencia, tenemos el riesgo de caer en "pecados" como el que me referí alguna vez: Repudio de la Infraestructura (Infrastructure Repudiation) y creer que todo es absolutamente soluble desde la plataforma programable y el resto es algo circunstancial que, de poderse evitar, debería hacerse. Al respecto quiero decir que si bien en Java o en C# podemos programar clases y métodos de manipulación intensiva de datos de una misma fuente, como alternativa a poner esa lógica en la base de datos misma, el bandwith involucrado así como también la posibilidad de que nuestro entorno general de programación no alcance los mismos niveles de optimización para la manipulación intensiva de datos puede hacer que ambos lados de la aparente ecuación no sean realmente tan iguales. Nada más, al respecto. Sólo algo a tener en cuenta. Hay que medir y confirmarlo o refutarlo

Por consiguiente a veces caemos sin mala fe en vicios innecesarios como los de creer que las limitaciones que alguna vez tuvieron las bases de datos nunca fueron resueltas ni se espera que lo vayan a ser alguna vez. Eso es falso ya que en la medida que el segmento de las bases de datos, comercialmente hablando, sigue teniendo una demanda competitiva, tanto los principales vendors así como los jugadores de segunda línea siguen investigando, perfeccionando y evolucionando sus ofertas de manera de hacer la diferencia frente a los demandantes que, finalmente, los decida a optar por ellos

En este post quiero comentar algunas viejas deficiencias que las bases de datos presentaron alguna vez, hoy superadas pero que conversando por ahí sé de más de un caso que no se dieron por enterado (señoras y señores, estoy hablando también de mí: caigo en ese vicio reiteradamente y espero con este post expiar mis culpas)

 

"ALTER TABLE No Hay Que Hacer Porque Es Caro"

El primer hecho que luego quedó en mito es la creencia de que el comando ALTER TABLE se ejecuta pesadamente porque debe recrear los datos de la tabla alterada, la que queda lockeada durante esa reconstrucción. En efecto, hace 10 años atrás la información de los registros de la mayoría de las bases de datos se guardaba en forma contigua. Por consiguiente si teníamos que modificar la estructura de una tabla (tipicamente el comando ALTER TABLE de SQL), esto iba a implicar una reescritura de todos los registros de dicha tabla, basándonse en el nuevo esquema -si la tabla tenía muchos registros esto era, me acuerdo, desalentador-

Hoy eso es parte de un pasado que seguramente aquellos que se adentraron en el maravilloso mundo de las bases de datos terminando el siglo pasado (digamos, 1999, año 2000 o después) ni lo llegaron a conocer

Lo cierto es que allá por el 2001 con Alejo, amigo y arquitecto también, nos perdimos los dos un proyecto porque el cliente nos pedía especialmente resolver un problema de rendimiento que tenía su aplicación, ya que habilitaba a los usuarios a definir "columnas virtuales" en los esquemas de las tablas-entidades de negocio

Su workaround para evitar la reescritura de registros era meter esas columnas virtuales como filas en la siguiente forma: suponete que la tabla a customizar era la tabla CLIENTES. Supongamos también que el usuario había generado como columnas virtuales COLOR_CABELLO y CANTIDAD_HIJOS. Este buen amigo, entonces, llevaba en una tabla extra algo como la que te muestro a continuación:

 

 Foreign-key a la tabla CLIENTES

Identificador de columna virtual

Valor de columna virtual 

56

COLOR_CABELLO

"Pelirrojo"

56

CANTIDAD_HIJOS

"6" (gran cañón del colorado)

94

COLOR_CABELLO

"Castaño"

Figura 1 – Columnas adicionales de la tabla CLIENTES, almacenadas de a filas

 

Como notarás: la última columna ("Valor") era de tipo VARCHAR para poder alojar practicamente cualquier tipo posible de valor. Había, claro, otra tabla más (o meta-tabla en realidad) para alojar el esquema de las columnas virtuales (siguiendo el ejemplo, era la meta-tabla donde se indicaba que la tabla CLIENTES tenía una columna virtual llamada "COLOR_CABELLO" de tipo VARCHAR, otra llamada "CANTIDAD_HIJOS" de tipo INT, y así

La consigna era, a nivel de aplicación, no complicar la lógica de acceso a un registro como el de CLIENTES -incluyendo sus columnas extendidas- con toda la plomería de acceder a estar columnas que en realidad se guardaban en filas. Cuestión que esta gente había hecho toda una biblioteca de acceso donde parseaban cada columna virtual según su metadato, y sacaban hacia afuera registros de primera clase, lineales… aunque con una performance de cuarta

Este cliente que nos llamó estaba desesperado por eso, porque esta aplicación él la vendía, y sus -a su turno- clientes estaban que se lo querían comer crudo. Alejo entonces le propuso migrar hacia un contexto donde cuando el usuario confirme un nuevo esquema de columnas, estas ya no serían virtuales sino que la aplicación reaccionaría emitiendo un ALTER TABLE en la tabla elegida para extender su esquema directamente en el motor de la base de datos. Nuestro cliente inmediatamente nos destacó que mientras el usuario que modifica esquemas está haciendo lo suyo, el resto de los usuarios accede en forma concurrente a la tabla, de modo que la complejidad de ejecución de un ALTER TABLE iba a llevar las cosas a una crisis inmensamente peor porque en ese caso se lockearía la tabla entera por un período (minutos? tal vez horas?) inaceptable. Además, normalmente el usuario que modificaba el esquema alteraba una columna, salvaba, alteraba otra, salvaba, y así se podía pasar un par de horas modificando esquemas. Vale la pena aclarar que el cliente se quedó bastante asombrado de la propuesta insólita, onda "yo creía que estos eran dos expertos que me iban a enseñar a resolver este bardo y resulta que les tengo que enseñar el abecé de las bases de datos"

Lógico, Alejo -con la tranquilidad que lo caracterizó siempre- le explicó que el comando ALTER TABLE no iba a producir ese resultado que el cliente temía, y que de hecho en cualquier base de datos de las de más conocidas, los valores de las columnas de un mismo registro no necesariamente se almacenan consecutivamente y que, a decir verdad, el único que sabía cómo almacenar y dónde había dejado cada cosa es el motor de la base de datos, de manera que la base de datos ya hacía lo que nuestro cliente hacía a manopla -a diferencia de que, y esto lo digo yo, en el caso de la base de datos, esa lógica fue escrita por gente que investigó científicamente el tema, le hizo tuning a los resultados, elaboró mecanismos para atenuar el peor caso estadístico, promover el caso favorable (al que optimizó), etc-

El cliente nos despidió con un "ok, nos vemos" y no nos volvió a devolver llamados. Sencillamente no nos creyó y por esa incredulidad se perdió la oportunidad -y nos la negó a nosotros- de optimizar su instalación

 

"Las Claves Principales Se Generan Por Programa"

No es éste el único caso de evoluciones truncas debido a la incredulidad (que es una forma de ignorancia). Otro ejemplo similar es el de la generación de valores únicos a ser usados como claves principales (Principal Key o PK las que, inherentemente, no admiten duplicados). En tiempos precámbricos, las bases de datos si bien permitían designar columnas como clave principal, no ofrecían mecanismo alguno en el que delegar la tarea de generar valores unívocos

A consecuencia de eso, normalmente estas claves se solían elegir de tipo numérico entero de manera de ir generando claves únicas mediante el mantenimiento de un contador en alguna tabla aparte (normalmente una tabla de parámetros de configuración). De esta manera, añadir un nuevo registro a la base de datos implicaba por lo menos tres operaciones con registros:

  • Uno para leer –lockeándolo– el contador
  • Otro para grabarlo -liberándolo- luego de sumarle 1 (uno)
  • Un acceso final para añadir el nuevo registro usando como clave principal el resultado de la suma

Si esta lógica era controlada desde la capa de acceso a datos, externa a la base de datos, estábamos entonces hablando de tres accesos a la base. Un poco mucho si cada inserción requería tres accesos, por lo que los más intrépidos se animaban a adentrarse en el fascinante mundo de los procedimientos almacenados (stored procedures o SPs) que presentaban una doble ventaja respecto de la lógica de manipulación de datos ejecutada offshore:

  • Los SP quedan compilados y por consiguiente se ejecutan más rápido que comandos SQL individuales que deben ser interpretados cada vez (frente a esto plataformas como Java han ofrecido la alternativa del java.sql.PreparedStatement, un comando SQL individual que se compila al crearse y a partir de ahí puede reutilizarse; pero no es comparable al SP: está limitado a un sólo comando SQL y además esa compilación expira con la conexión a la base, por lo que una cualquier otra conexión deberá compilar el propio, con el consiguiente consumo de recursos, en definitiva, compartidos)
  • Las extensiones a SQL para soportar SP estaban fuertemente enfocadas en el dominio de manipulación de datos, y optimizadas para tal fin. Por este motivo, siempre que se usen para manipulación intensiva de datos, la aplicación podía alcanzar mejores niveles de escalabilidad que si una lógica equivalente era escrita en la capa de acceso a datos de la aplicación. Desafortunadamente una lectura rápida e imprecisa de esto último lleva a varios a creer que en realidad la idea de los SP era poner la lógica, atención, de negocio lo más al fondo posible (esto es, en la base de datos) porque así se iban a alcanzar niveles de reusabilidad sorprendentes. Una salida un tanto cara, en la medida en que SQL extendido para soportar SP no llega a alcanzar ni la versatilidad ni la riqueza de un lenguaje de programación de propósito general (por caso, hay pocos ejemplos de SP orientado a objetos -y en forma limitada, por ejemplo herencia: bien, gracias-, o basados en paradigmas superadores del paradigma estructurado). Por otro lado, tirar demasiada carga de ejecución de lógica de cómputo en la base de datos tampoco era una idea muy inteligente por el hecho de que escalabilidad y alta disponibilidad, hablando de motores de bases de datos, se alcanzan por caminos diferentes que en los middleware o servidores de aplicación tradicionales. Acá hablamos de mirroring y/o clustering, ambas estrategias para datos altamente disponibles. No para capacidad de cómputo altamente disponible

Como contrapartida, los SP suelen no ser portables entre diversos motores de bases de datos, y esto desalentó particularmente a los devotos de la plataforma Java -más que nada imbuídos del leit motiv de Write Once, Run Anywhere ("Escribilo Una Sola Vez y Correlo en Todas Partes")- porque les resultaba inaceptable que, habiendo logrado una aplicación que pueda correr sin modificaciones en ambientes Linux como Windows (mentira: eso sólo si Sun le otorgó a tu aplicación la distinción "100% Pure Java"), cómo era posible que la portabilidad quede resignada por culpa de la base de datos? Esto a más de uno -me incluyo- los motivó a escribir la lógica de manipulación de datos enteramente en la capa de acceso a datos cayendo -una vez más- en el antipatrón de Repudio de la Infraestructura

Pero volvamos a la generación de valores unívocos para claves principales. Venía contando que al principio las bases de datos te dejaban a la buena. Años más tarde algunas bases de datos incorporaron la característica conocida como test-and-set (una traducción literal quedaría incoherente: preferentemente la voy a llamar "leer actualizando"). La función test-and-set resumía los dos primeros pasos mencionados antes (de leer un valor, grabandolo incrementado en uno), devolviendo al llamador el nuevo valor del contador. De esta forma podíamos insertar, como valor para la clave principal, el resultado devuelto por la función test-and-set

 

Tipos Secuenciados

Posteriormente las bases empezaron a ofrecer la posibilidad de definir directamente la clave principal de las tablas como de un tipo que se autogeneraba en la medida en la que los registros eran insertados. En Oracle este tipo de columnas podía lograrse mediante el comando CREATE SEQUENCE. En SQL Server, como en el resto de las bases de datos principales, este tipo de columnas estaba soportado pero la sintaxis era completamente particular (no estándar). En SQL Server 2005 la clave principal se definiría, por ejemplo, así

Id INTEGER NOT NULL IDENTITY (1, 1)

En este ejemplo, Id es el nombre de la columna, INTEGER es el tipo, y en el caso mío -SQL Server 2005- acepta un valor máximo equivalente a 2^31-1 (dos a la treinta y uno, menos 1; o sea 2.147.483.647). Pero lo que especialmente da la pauta es el modificador del final: IDENTITY (1, 1). Lo que indica es que la columna Id va a recibir valores comenzando de un valor inicial equivalente a 1 (conocido como semilla o seed), y posteriormente el motor de base de datos continuará generando identidades incrementando en 1 el última valor calculado

Claro, si el que manipula ese valor es el motor de la base… cómo nos enteramos qué valor le quedó finalmente a la clave principal? En SQL Server, en particular, la variable de sistema @@IDENTITY va a estar guardando el último identificador generado en tu sesión (eso quiere decir que si en una sesión concurrente se generase otro registro, ambos @@IDENTITY estarán retornando -adecuadamente- valores diferentes)

Este mecanismo de generación de claves principales por la técnica de la semilla y el valor de incremento es adecuadamente bueno y altamente recomendable en aquellos casos que tengas total control sobre tu base de datos y/o el/los servidor/es donde resida (me refiero a que se trate de servidores donde tengas autorización para hacer BACKUP y especialmente RESTORE de tu base en una forma más o menos sencilla -obviamente en un momento planificado y comunicado a los usuarios, pero me refiero a que no tenés que conseguir cinco niveles de firma para poder ejecutar estos comandos de alcance masivo a toda la base. Si ése es tu caso, esta estrategia de generación de claves principales te va a andar bien y es muy recomendable, por cuanto los valores que genera son relativamente memorizables (probablemente no te acuerdes las claves de todos los clientes, eso está claro, pero si justo estás haciendo algo con "Juan Pérez" y de casualidad tenés que ingresar su código a manopla, te podés acordar del número por unos instantes)

En cambio, si no tenés facilitado el acceso a resguardo y restauración de tu base de datos, y de alguna forma tenés que replicar o exportar los registros de un servidor a otro, lamento decirte que este mecanismo no te va a ayudar demasiado en la medida que no se pueden importar masivamente estas columnas secuenciadas con los valores ya fijados: el motor de la base de datos te va a importar el resto de las columnas, en tanto que a la clave principal la va a seguir generando usando el valor actual de la semilla y el incremento. Como consecuencia, no tenés ninguna garantía de que las PKs resultantes van a coincidir con las originales. Si esta clave principal era referenciada como clave foránea (foreign key o FK) desde otra tabla, estas referencias van a quedar apuntandote para cualquier lado (probalo si querés, pero te aseguro que ya me pasó smile_regular)

Habrá alguna forma de generar claves únivocas pero que no necesariamente estén relacionadas entre sí y se puedan mover de un lado al otro?

 

Identificadores Globalmente Únicos

Tu salvación para este caso existe, aunque no te va a resultar tan sencillo acordarte valores de memoria, y yo te diría que no vas a zafar de apelar al copy/paste. Porque el otro mecanismo de generación de valores unívocos que hoy la mayoría de las bases de datos, aunque nuevamente cada una a su modo, implementan algo conocido como Identificador Universalmente Único (Universally Unique Identifier o UUID). Si bien como tipo de dato es un estándar sancionado por la Organización de Estándares Internacional (ISO) y hasta hay sugerencias del algoritmo a aplicar para generar claves universalmente únicas como su nombre lo explicita, la probabilidad de repetir valores no es 0 (cero) absoluto. Pero es muy baja de todas formas. Este tipo de datos consiste en 16 bytes, lo que es decir que tenemos 2 a la 128… alrededor de 3,4 por 10 a la 38 claves distintas. La especificación de ISO sugiere, en su apéndice A, un mecanismo de cómputo basado en el reloj del sistema como semilla. Microsoft particularmente, que viene usando UUID desde mediados de los 90 (te habrá llamado la atención, ya por Windows 98, esas tiras raras de números hexa que aparecían en medio de las claves de la Registry -ver figura 2-) usa la "MAC address" de la tarjetas de red junto a una combinación con la hora del sistema

 


Figura 2 – Un día "común" en la Registry de Windows

 

Este mecanismo le ha valido a la compañía de Redmond varios reproches, en la medida en que sería posible rastrear desde que equipo en Internet se generó determinado GUID (por Globally Unique Identifier o Identificador Globalmente Único, tal como Microsoft llama al UUID de ISO) y de hecho así se pudo atrapar al que liberó al gusano Melissa (que la sacó barata pero no zafó de la cárcel, ver pormenores del caso en figura 3)

 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

ME

LIS

SA

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

Figura 3 – Tocado, Tocado, Hundido
David L. Smith, creador del virus "Melissa"

En SQL Server 2005 para que tu clave principal sea de este tipo de datos la tenés que definir como uniqueidentifier en lugar de INTEGER y, contrariamente a los secuenciadores, acá sí tenés que insertar el valor de la columna mediante la llamada a la función NEWID(). Te conviene llamar primero a la función, asignándole el valor a un parámetro de salida de tu SP, y entonces insertar ese valor a la clave principal

Como te contaba hace un rato, estos valores no están secuencialmente relacionados sino que se generan independientemente. Esto entonces no impone restricciones al tipo de clave principal y -tengas o no posibilidades de hacer   o al menos importar o exportar registros y esquemas-, vas a poder copiarlos entre bases de datos equivalentes en distintos servidores sin alteraciones al valor de la clave principal

La contra de este tipo de datos, como también te comentaba recién, es que es muy compleja (digamos "imposible" y no exageramos) de memorizar por lo que si tenés que chequear listados, cotejando el valor de esta columna, o mismo si la tenés que ingresar a mano o dictarsela a alguien -cada tanto te va a pasar, esperemos que poco- la cosa se ve no tan atractiva

 

Epílogo

Te voy a pasar más data sobre estos temas a medida que me vaya (y me vayan) apiolando de mas novedades

Esta entrada fue publicada en Software Architecture. Guarda el enlace permanente.

8 respuestas a Actualizaciones en Bases de Datos

  1. Matias Woloski dijo:

    Muy interesante lo de ALTER TABLE. Es uno de los temas a tener en cuenta al hacer apps multi-tenant (SaaS).
    Escribi un post al resepcto agregando un poco de data: http://staff.southworks.net/blogs/matiaswoloski/archive/2007/04/30/Performance-of-ALTER-TABLE.aspx
    abrazo

  2. Esteban J. dijo:

    mmm, No estoy muy de acuerdo con el tema de la clave Primaria. No creo que la mejor opcion sea usar GUID (si la mas facil).En primer lugar porque tendrias un indice muchisimo mas grande, por otra parte, por lo menos SQLServer ofrece opciones para trabajar con IDENTITYS sin tener los problemas que nombras.1) En caso de que la tabla de replique, se puede usar Identity Not For Replication, que el nombre mismo dice lo que hace.2) Si queremos hacer una actualizacion masiva de tablas, podes deshabilitar la escritura automatica de este campo usando SET IDENTITY_INSERT NombreTabla OFF y escribir el valor de "identity" de forma explicita.3) Si es necesario, podes modificar la sequencia de los identity de una tabla con un comando DBCC.

  3. Jaime dijo:

    Diego,
     
    Interesante post por lo que te dejo mis comentarios, concuerdo completamente con Esteban sobre los identitys, sobre todo en replicación y mantención de data.
     
    Pondría especial cuidado con el comando @@IDENTITY que expones, ya que no te asegura el “scope” del ultimo valor “identity” devuelto, es decir podría ser el valor de cualquier tabla de tu sesión, en especial cuando tienes insert masivos, triggers disparados después de los insert, select into, etc por tanto seria mas adecuado la utilización de SCOPE_IDENTITY() que te asegura el ultimo valor insertado en la tabla de tu sesión y además de tu “scope”, otro comando interesante es IDENT_CURRENT que no se limita ni a la sesión ni al scope o alcance.
     
     
    Saludos
     

  4. Gustavo dijo:

    Hola Diego, cómo estás. Quisiera agregar mis comentarios personales, tomalos como que vienen de una persona del mundo de las bases de datos (aunque soy de los que confraternizan con los programadores de aplicaciones :-))
     
    Respecto a tus comentarios sobre el uso de ALTER TABLE. En una base de datos consideramos al esquema o "intension" como una estructura que tiende a ser inmutable en el tiempo, versus la extensión o datos que sí cambian con suma frecuencia. Desde el punto de vista de un DBA, la necesidad de una aplicación en cambiar el esquema de la base de datos suele ser síntoma de: a) Una aplicación patológicamente diseñada; b) Una aplicación de características especiales o extraordinarias (como la que mencionás en tu post). Como en la Medicina, una aplicación tan extraordinaria finalmente es un caso de patología de alguna clase 🙂
     
    Entiendo de tu post de que estás considerando un escenario donde el ALTER TABLE se aplica directamente sobre datos de producción. Esto difícilmente ocurra en la práctica: Los cambios al esquema de la base de datos se deberán aplicar en ambiente de desarrollo, homologarse en un ambiente de pre-producción y finalmente aplicarse a la base de datos de producción. Las bases de datos tienen su ciclo de vida como cualquier otra pieza de software. Eso implica el uso de herramientas adecuadas que permitan el versionado de esquemas, comparación, generación de scripts de cambio, pruebas unitarias y finalmente deploy del nuevo esquema (seguido de traspaso de datos al nuevo esquema). Es decir, ALTER TABLE es apenas un peón en el tablero del DBA.
     
    No quiero ser extenso de más: Simplemente menciono que ALTER TABLE es apenas uno de decenas de refactoreos estructurales posibles que pueden hacerse a una base de datos. Los artículos y libros de Mr. Scott W. Ambler acerca del tema merecen una leída, aunque sea por el trabajo de catalogar todos los refactoreos que consiguió cazar. Ver:
     
    http://www.agiledata.org/essays/databaseRefactoringCatalog.html
     
    Respecto a los otros temas que mencionas en tu post, trataré de aportar algún comentario en otro momento. Estoy viendo como Boca le gana a Velez por la Copa Libertadores 🙂
     
    Un abrazo
    ~gux
    http://blogs.solidq.com/ES/glarriera
     
     
     

  5. Diego dijo:

    Estimadísimos,
       muchísimas gracias a todos por los comments, que sin duda han hecho de este post algo mucho más "nutritivo" de lo que era originalmente (empezó siendo un fascículo de "Érase una vez… el Hombre" y terminó siendo todo un libro gordo de Petete!!)
       He aprendido cosas que no sabía y agradezco por ello, algunas, sin duda las pude haber aplicado en tanto que otras no dado que, en mi contexto, yo tuve que exportarle mi BD a un tercero. A un hoster remoto que no me daba full control sobre la misma para tirar cualquier comando sino que, por contrato, yo tenía habilitados sólo un puñado de ellos. Si quería más, poniendo estaba la ganza como decía el amigo Olmedo
       Aprovecho y les pregunto a Uds que son los que la llevan: Esteban menciona un punto interesante, comparando las GUID con enteros comunes, ya que ciertamente una GUID son 16 bytes (un entero no recuerdo hoy si siguen siendo 4 o ya va por los 8). Ahora, la posta, más allá de que es al menos el doble de espacio -en nuestro caso despreciable ya que las tablas más grossas tienen registros de tamaño arriba del K-, existe un impacto real, considerable, en rendimiento? Hay benchmarks como para mirar? Nosotros tomamos benchmarks pero end-to-end, es decir ejecutábamos el caso de uso en forma automática para 1000 registros maestros de a cuatro threads de 250 cada uno (cada registro maestro a su turno tenía unos cinco registros secundarios en tablas asociadas)
       Repito, era una prueba end-to-end, desde la primera inserción hasta la última. Si la diferencia era considerable, entonces íbamos a hacer drill down para ver dónde estaba el agujero negro. Ejecutamos esta prueba 10 veces y los tiempos a nosotros nos han dado similares. Un empate técnico
       Medimos mal? Existen benchmarks para compartir?
     
       Estimados, nuevamente gracias por leer y compartir vuestras opiniones (me encantó tu blog, Esteban!!! Sos el Tangalanga de la Ingeniería de Software!!!)   😀

  6. Esteban J. dijo:

    Que tal? Debe haber algun bencharmark dando vuelta por ahi. Pero la prueba que hiciste de 1000 registros por ahi es chica.Por ejemplo, un campo GUID pesa 16 bytes, un campo Int, 4. Si tenes una tabla de 10 millones de registros, estamos hablando de una diferencia de 8 Megas entre una tabla con campo GUID y otra con Identity. El problema no estaria en el espacio en disco, sino en el aumento del costo de I/O del SQLServer. Peor aun, el Cluster Index tambien seria mas grande, con lo cual tendrias otros 8 Megas mas de diferencia en el indice, o sea, mas costo de I/O. A esto hay que sumarle que tenes que propagar este campo GUID en todas las tablas relacionadas, o sea, que las demas FK tambien tendria un costo adicional de 8 megas y como en general, lo recomendable es que los FK esten indexadas, hay que sumarle otros 8 megas mas del indice (suponiendo que la otra tabla tambien tenga 10 millones de registros).Ademas hay un factor MUY importante, si una PK es cluster Index, significa la tabla tiene que estar internamente ordenada por este campo. Como un campo indentity es autoincremental, siempre va a estar ordenado. En cambio, si es un campo GUID, el costo del INSERT es mucho mayor, porque el SQL tiene que insertar en forma ordenada. Aunque el SQL2005 incorpora la funcion NEWSEQUENTIALID que genera GUID sequenciales, lo que te evita este problema. Pero es importante aclararlo. Conclusion, si tenemos una tabla con un campo GUID como PK y este campo tiene foreign key con otras 20 tablas por ejemplo (algo muy habitual en bases grandes) con sus respectivos indices, tenemos un excedente bastante considerable, cuyo mayor impacto lo verias en el I/O, que es la operacion mas lenta de todas. Ni hablar, que al ser los campos de una tabla mas grandes, tendrias menos registros cacheados en memoria.

  7. Gustavo dijo:

    Acerca de benchmarks en el uso de GUID como claves primarias y cómo afectan el renidmiento, ver este ilustrativo artículo de Zach Nichter, publicado en el siempre excelente sitio SQL-Server-Performance. Hay mediciones interesantes:
     
    http://www.sql-server-performance.com/zn_guid_performance.asp
     
    Que lo disfruten..
    ~gux
     
    PD: Finalmente Boca le ganó bien a Vélez y mi querido Defensor Sporting le metió 3-0, con bailongo incluido, al Flamengo.

  8. Diego dijo:

    Estimadísimos: GRACIAS infinitas por toda esta información!!!!
     
    (PD: y aguante Boquita, caraxx. Vamo a quemá el Fortín)

Deja un comentario