Pregunta

En una discusión bastante animada en mi equipo, me hicieron pensar lo que a la mayoría de las personas les gusta como claves principales. Tuvimos los siguientes grupos-

  1. Int / BigInt cuyos autoincrementos son claves primarias suficientemente buenas.
  2. Debe haber al menos 3 columnas que conforman la clave principal.
  3. La identificación, el GUID y los identificadores de fila legibles por humanos deben tratarse de manera diferente.

¿Cuál es el mejor enfoque para las PK? Sería genial si pudieras justificar tu opinión. ¿Hay un mejor enfoque que el anterior?

EDITAR: ¿Alguien tiene una muestra / algoritmo simple para generar identificadores legibles por humanos para filas que se escalan bien?

¿Fue útil?

Solución

Si va a realizar una sincronización entre las bases de datos con aplicaciones conectadas ocasionalmente, entonces debería usar GUID para sus claves principales. Es un tipo de molestia para la depuración, por lo que, aparte de ese caso, tiendo a atenerme a los ints que el autoincremento.

Las entradas de autoincremento deben ser su valor predeterminado, y no su uso debe estar justificado.

Otros consejos

No veo una respuesta que indique (lo que considero) el punto realmente fundamental, es decir, que una clave principal es lo que garantiza que no obtendrá dos entradas en la tabla para el mismo mundo real. Entidad (según modelo en la base de datos). Esta observación ayuda a establecer qué son buenas y cuáles son malas elecciones para la clave principal.

Por ejemplo, en una tabla de nombres y códigos de estado (EE. UU.), el nombre o el código podrían ser la clave principal: constituyen dos claves candidatas diferentes, y una de ellas (normalmente la más corta, el código) es elegido como la clave principal. En la teoría de las dependencias funcionales (y las dependencias de unión, de 1NF a 5NF, son las claves candidatas las que son cruciales en lugar de una clave principal.

Para un ejemplo contrario, los nombres humanos generalmente hacen una mala elección para la clave principal. Hay muchas personas que llevan el nombre "John Smith" o algunos otros nombres similares; incluso teniendo en cuenta los nombres medios (recuerde: no todos tienen uno, por ejemplo, yo no), hay muchas posibilidades de duplicación. En consecuencia, las personas no usan nombres como claves primarias. Inventan claves artificiales como el Número de Seguro Social (SSN) o Número de empleado y las usan para designar a la persona.

Una clave principal ideal es corta, única, memorable y natural. De estas características, la singularidad es obligatoria; el resto tiene que flexionarse dadas las limitaciones de los datos del mundo real.

Cuando se trata de determinar la clave primaria de una tabla dada, por lo tanto, debe mirar lo que representa esa tabla. ¿Qué conjunto o conjuntos de valores de columna en la tabla identifican de forma única cada fila en la tabla? Esas son las claves candidatas. Ahora, si cada clave candidata consta de 4 o 5 columnas, entonces podría decidir que son demasiado torpes para hacer una buena clave principal (principalmente por motivos de falta). En esas circunstancias, puede introducir una clave sustituta, un número generado artificialmente. Muy a menudo (pero no siempre) un simple entero de 32 bits es suficiente para la clave sustituta. A continuación, designa esta clave sustituta como la clave principal.

Sin embargo, debe todavía debe asegurarse de que las otras claves candidatas (para la clave sustituta también es una clave candidata, así como la clave primaria elegida) se mantengan como identificador único, normalmente colocando una restricción única en esos conjuntos de columnas.

A veces, a las personas les resulta difícil identificar qué hace que una fila sea única, pero debería haber algo para hacer eso, porque simplemente repetir una parte de la información no hace que sea más cierto. Y si no es cuidadoso y obtiene dos (o más) filas que pretenden almacenar la misma información, y luego necesita actualizar la información, existe el peligro (especialmente si usa cursores) de que solo actualice una fila. en lugar de cada fila, por lo que las filas están fuera de sincronía y nadie sabe qué fila contiene la información correcta.

Esta es una vista de línea bastante dura, en algunos aspectos.

No tengo ningún problema particular con el uso de un GUID cuando se necesitan, pero tienden a ser grandes (como en 16-64 bytes), y se usan con demasiada frecuencia. Muy a menudo bastaría un valor de 4 bytes perfectamente bueno. El uso de un GUID donde bastaría un valor de 4 bytes desperdicia espacio en el disco y ralentiza el acceso indexado a los datos ya que hay menos valores por página de índice, por lo que el índice será más profundo y habrá que leer más páginas para llegar al información.

Este es solo un tema religioso porque las personas buscan una respuesta universal correcta. El hecho de que tanto su equipo como esta secuencia de SO muestren tanto desacuerdo debería ser una pista de que hay buenas razones para usar todas las soluciones que describe, en diferentes circunstancias.

  • Las claves sustitutas son útiles cuando ningún otro atributo o conjunto de atributos en la tabla es adecuado para identificar las filas de forma única.
  • Se prefieren las teclas naturales, cuando sea posible, para hacer que la tabla sea más legible para los humanos. Las claves naturales también permiten que la clave externa en una tabla dependiente contenga un valor real en lugar de una identificación sustituta. P.ej. cuando necesite almacenar estado (CA, TX, NY), también puede utilizar una clave natural char (2) en lugar de una int.
  • Use claves primarias compuestas donde sea apropiado. No añada un " id " clave sustituta innecesaria cuando existe una clave compuesta perfectamente buena (esto es especialmente cierto en tablas de muchos a muchos). Un mandato para una clave de tres columnas en cada tabla es un completo disparate.
  • Los GUID son una solución cuando necesitas preservar la singularidad en varios sitios. También son útiles si necesita que los valores de la clave principal sean únicos, pero no ordenados ni consecutivos.
  • INT vs. BIGINT: no es común que una tabla requiera un rango de 64 bits para las claves principales, pero con la creciente disponibilidad de hardware de 64 bits no debería ser una carga, y da más seguridad de que no se desbordará. INT es, por supuesto, más pequeño, por lo que si el espacio es escaso, puede dar una pequeña ventaja.

Me gusta El blog del programador de bases de datos como fuente de este tipo de información.

3 columnas para una clave primaria? Yo diría que las columnas deberían tener restricciones únicas apropiadas según lo exijan las reglas de negocios, pero todavía tendría una clave sustituta por separado. Las claves compuestas significan que la lógica de negocios entra en la clave. Si la lógica cambia, todo el esquema se atornilla.

Me gusta el mío único.

Siempre voy con la clave sustituta. Una clave sustituta (generalmente una columna de identidad, autoincremento o GUID) es aquella en la que la clave no está presente en los datos en sí. Una clave natural, por otro lado, es aquella que, por sí sola, identifica de forma única la fila. Tan cerca como puedo ver en la vida, casi no hay ninguna clave natural real . Ni siquiera cosas como el SSN en los Estados Unidos es una clave natural. Las claves primarias compuestas son un desastre a la espera de suceder. No puede editar ninguno de esos datos (que es el mayor inconveniente de cualquier clave natural, compuesta o no), pero peor es que con una clave compuesta, ahora tiene que perpetuar esos datos clave en cada tabla relacionada. Qué gigante desperdicio.

Ahora, para la selección de la clave sustituta, me quedo con las columnas de identidad (trabajo principalmente en MS SQL Server). Los GUID son demasiado grandes y Microsoft recomienda contra usarlos como PK. Si tiene varios servidores, todo lo que debe hacer es hacer el incremento 10 o 20 o lo que sea que crea que será el número máximo de servidores que necesitará para sincronizar / expandir, y solo incluir la semilla para cada tabla en cada servidor subsiguiente. y nunca tendrás una colisión de datos.

Por supuesto, debido al incremento, hago que la columna de identidad sea BigInt (también conocida como larga [64 bits]).

Haciendo un poco de matemáticas, incluso si haces el incremento de 100, aún puedes tener 92,233,720,368,547,758 (> 92 cuatrillones) filas en tu tabla.

Creo que el uso de la palabra " Primary " ;, en la frase " Primary " La clave es en un sentido real, engañosa.

Primero, usa la definición que una " clave " es un atributo o conjunto de atributos que deben ser únicos dentro de la tabla,

Entonces, tener cualquier clave sirve para varios propósitos a menudo mutuamente inconsistentes.

  1. Para usar como condiciones de unión a uno o varios registros en tablas secundarias que tienen una relación con esta tabla primaria. (Definición explícita o implícita de una clave externa en esas tablas secundarias)
  2. (relacionado) Asegurar que los registros secundarios deben tener un registro principal en la pestaña principal; e (La tabla secundaria FK debe existir como Clave en la tabla principal)
  3. Para aumentar el rendimiento de las consultas que necesitan localizar rápidamente un registro / fila específico en la tabla.

  4. Para garantizar la consistencia de los datos evitando que se inserten filas duplicadas que representan la misma entidad lógica en la tabla. (Esto suele denominarse clave "natural" y debe consistir en atributos de la tabla (entidad) que son relativamente invariantes).

Claramente, cualquier clave no significativa, no natural (como un GUID o un entero generado automáticamente es totalmente incapaz de satisfacer el # 4.

Pero a menudo, con muchas (la mayoría) de las tablas, una clave totalmente natural que puede proporcionar el # 4 a menudo consistirá en múltiples atributos y será excesivamente ancha, o tan ancha que su uso para los propósitos # 1, # 2 o # 3 causará consecuencias inaceptables de rendimiento.

La respuesta es simple. Usa ambos. Use una clave integral de auto-generación simple para todas las combinaciones y FK en otras tablas secundarias, pero asegúrese de que cada tabla que requiera consistencia de datos (muy pocas tablas no) tenga una clave única natural alternativa que evitará inserciones de filas de datos inconsistentes. .. Además, si siempre tiene ambos, entonces todas las objeciones contra el uso de una clave natural (¿qué pasa si cambia? Tengo que cambiar cada lugar al que se hace referencia como FK) se vuelven discutibles, ya que no lo está utilizando para eso. .. Solo lo está utilizando en la única tabla en la que es un PK, para evitar datos duplicados inconsistentes ...

En cuanto a los GUID, tenga mucho cuidado al usarlos, ya que usar guías en un índice puede provocar la fragmentación del índice. Los algoritmos más comunes utilizados para crearlos ponen " aleatorio " parte del guid en las posiciones de bit más significativas ... Esto aumenta el requisito de desfragmentación de índice / reindexación a medida que se agregan nuevas filas.

Un poco fuera de tema, pero me siento obligado a participar con ...

Si su clave principal es un GUID, no lo convierte en un índice agrupado . Como los GUID no son secuenciales, los datos se reorganizarán en el disco durante casi todas las inserciones. (Yuck.) Si utiliza GUID como claves primarias, deben ser índices no agrupados.

Una cosa que nunca debes hacer es usar una llave inteligente. Esa es una clave en la que la información sobre el registro está codificada en la propia clave y eventualmente lo morderá.

Trabajé en un lugar, donde la clave principal era el ID de cuenta, que era una combinación de letras y números. No recuerdo ninguna información específica, pero, por ejemplo, aquellas cuentas que eran de cierto tipo, estarían en el rango de 600, y de otro tipo, comenzaron con 400. Eso fue genial, hasta que el cliente decidió solicitar ambas. tipos de trabajo O cambió el tipo de trabajo que hicieron.

Otro lugar, usó la ubicación en el árbol como la clave principal para los registros. Así que habría registros como los siguientes.

Cat1.subcatA.record1
Cat1.subcatA.record2
Cat1.subcatB.record1
Cat2.subcatA.record1

Por supuesto, lo primero que querían los clientes era una forma de mover los elementos en el árbol. Todo el conjunto de software murió antes de que eso sucediera.

Por favor, por favor, por favor, si está escribiendo un código que debo mantener, ¡no use una llave inteligente!

Soy un fanático del incremento automático como clave principal. Sé en el fondo de mi corazón que se trata de una copia, pero hace que sea muy fácil ordenar los datos cuando se agregaron (ORDENAR POR ID DESC, por ejemplo).

3 columnas suenan terriblemente duras de analizar humanamente.

Y esa es la compensación: cuánta capacidad relacional necesita, en lugar de hacer que ESTA TABLA AQUÍ sea entendible para que un humano la interrogue (en comparación con el procedimiento almacenado o la interfaz programática).

auto-incremento es para nosotros los humanos. :-(

En general, depende.

Personalmente, me gustan las entradas de autoincremento.

Pero, una cosa que puedo decirles es que nunca confíe en los datos de otras fuentes como su clave. Lo juro, cada vez que lo hago vuelve a morderme. Bueno, nunca más!

  

Debe haber al menos 3 columnas que conforman la clave principal.

No entiendo esto.

¿Estás hablando de una " clave natural " ;, p. ej. " nombre y fecha de nacimiento " ;? Una clave natural podría ser ideal si existe, pero la mayoría de los candidatos para una clave natural no son únicos (varias personas con el mismo nombre) o no son constantes (alguien puede cambiar su nombre).

  

Int / BigInt cuyos autoincrementos son claves primarias suficientes.

Prefiero Guid. Un problema potencial con el aumento automático es que el valor (por ejemplo, '' id de pedido '') es asignado por la instancia de la base de datos (por ejemplo, por la '' base de datos de ventas '') ... que no funcionará por completo (en cambio, comenzará a necesitar claves compuestas ) si alguna vez necesita fusionar datos creados por más de una instancia de base de datos (por ejemplo, de varias oficinas de ventas, cada una con su propia base de datos).

RE GUID

Tenga cuidado si se trata de una gran base de datos realmente REALMENTE REALMENTE REALMENTE , mucha carga y acceso rápido.

En mi último trabajo, donde teníamos bases de datos de 100 a 500 millones de registros, nuestros muchachos de bases de datos discutían enérgicamente contra los GUID y por un número decimal de tamaño apropiado. Sintieron que (bajo Oracle) la diferencia de tamaño en el almacenamiento interno para un Guid de cadena - vs- un valor decimal haría una diferencia muy notable en las búsquedas. (Teclas más grandes = árboles más profundos para atravesar)

La naturaleza aleatoria de los GUID también reduce significativamente el factor de relleno para las páginas de índice; esto aumenta drásticamente el desgarro y la E / S del disco.

Columnas de incremento automático. Soy capaz de hacer que mi código funcione sin problemas con SQL Server u Oracle, uno usando identidad y el otro usando secuencias a través de mi DAL, y no podría estar más feliz. Estoy de acuerdo, los GUIDs a veces son necesarios si está haciendo una replicación o enviando datos para recibirlos más tarde en un procesamiento posterior.

Siempre he usado una clave sustituta: un entero de autoincremento llamado 'id'. Puedo ver muchas razones para hacer esto incluso cuando hay otra opción obvia:

  • consistencia
  • Datos independientes (únicos, no destruidos por cambios en el formato)
  • legible por humanos

... y no hay una razón sensata para no:

  • ¿La ambigüedad en las uniones? - Aliasing tables es una mejor práctica, IMHO
  • tablas optimas? - Eliminar un byte por entrada es una optimización prematura, IMHO
  • decisión por mesa? - Ya no es consistente
  • ¿Problemas de escalado? Eh ¿Por qué?
  • estructura de datos jerárquica? - Eso es desnormalizar, otro tema de la religión. Basta con decir que soy un fan en algunas circunstancias en teoría, pero nunca en la práctica :)

razones sensatas en contra de las cuales no he pensado o no he encontrado todavía son bienvenidas ...

Este es un clásico " depende " ;. No hay una respuesta correcta para cada proyecto. Me gustan las cosas diferentes para diferentes situaciones. Depende de si estoy usando un ORM y de qué soporta. Depende de la arquitectura global (distribuida o no, etc). Simplemente elija uno que crea que funcionará y continúe discutiendo sobre tabulaciones y espacios.

Tiendo a usar la opción # 1 o # 3 dependiendo del tamaño, la cantidad de personas conectadas y si se trata de una situación de servidor de base de datos múltiple o no.

La opción # 2 no tiene mucho sentido para mí. Si cualquiera de los tres no es suficiente para identificar un registro único, entonces es posible (sin pasar por maquinaciones adicionales) que dos registros aparezcan con los mismos valores en las tres columnas. Si desea imponer unicidad en cualquier combinación de los tres, simplemente agregue un índice para ellos.

Solo uso un incremento automático o un GUID. El 99% de las veces he usado auto-increment int. Es justo lo que me enseñaron a usar cuando aprendí por primera vez sobre bases de datos y nunca encontré una razón para no usarlas (aunque conozco algunas razones por las que un GUID sería mejor).

Me gustan los incrementos automáticos porque ayuda con la legibilidad. Por ejemplo, puedo decir " echar un vistazo al registro 129383 " y es bastante fácil para alguien entrar y encontrarlo. Con un GUID que es casi imposible de hacer.

Más allá de una respuesta de definición básica, lo que constituye una clave principal buena se deja en gran parte a los argumentos de la religión y la sala de descanso. Si tiene algo que es, y siempre, se asignará de forma única a una fila individual, entonces funcionará bien como clave principal. Más allá de ese punto, hay otras consideraciones:

  • ¿La definición de la clave principal no es demasiado compleja? ¿Evita la introducción de una complejidad innecesaria para seguir las "mejores prácticas"?
  • ¿Existe una mejor clave principal posible que requiera menos sobrecarga para que la base de datos la maneje (es decir, INTEGER vs. VARCHAR, etc.)?
  • ¿Estoy ABSOLUTAMENTE seguro de que la singularidad y la invariante definición de mi clave principal no cambiarán?

Es probable que este último sea el que atraiga a la mayoría de las personas a usar elementos como los GUID o las columnas de enteros autoincrementables, ya que confiar en cosas como direcciones, números de teléfono, nombres y apellidos, etc. simplemente no lo corta. El único invariante de las personas en las que puedo pensar es en los números de seguro social, pero entonces ni siquiera estoy 100% seguro de que permanezcan únicos para siempre.

Esperemos que esto ayude a agregar algo de claridad ...

La forma en que me acerco a las claves primarias (y creo que es la mejor) es evitar tener un " predeterminado " enfoque. Esto significa que, en lugar de solo abofetear a un entero auto-incremental y llamarlo un día, observo el problema y digo "¿hay una columna o grupo de columnas que siempre serán únicas y no cambiarán?" Si la respuesta es sí, entonces adopto ese enfoque.

Casi siempre enteros.

Tienen otras buenas razones además de ser más pequeños / más rápidos de procesar. ¿Qué preferirías escribir - " 404040 " o " 3463b5a2-a02b-4fd4-aa0f-1d3c0450026c " ;?

Solo un poco relevante, pero una cosa que comencé a hacer recientemente cuando tengo tablas de clasificación pequeñas (esencialmente aquellas que representarían ENUMs en código) es que haré que la clave principal sea char (3) o char (4). ). Luego hago esas claves primarias representativas del valor de búsqueda.

Por ejemplo, tengo un sistema de cotización para nuestros agentes de ventas internos. Tenemos " Categorías de costos " que cada línea de presupuesto tiene asignada una de ... Así que tengo una tabla de búsqueda de tipo llamada 'tCostCategories', donde la clave principal es 'MTL', 'SVC', 'TRV', 'TAX', 'ODC'. Otras columnas en la tabla de búsqueda almacenan más detalles, como los significados normales en inglés de los códigos, "Material", "Servicio", "Viajes", "Impuestos", "Otros costos directos", etc. .

Esto es realmente bueno porque no usa más espacio que un int, y cuando está mirando los datos de origen, no tiene que vincular la tabla de búsqueda para saber qué diablos es el valor. Por ejemplo, una fila de comillas podría tener el siguiente aspecto:

1 PartNumber $ 40 MTL
2 OtherPartNumber $ 29.99 SVC
3 PartNumber2 $ 150 TRV

Es mucho más fácil usar un int para representar las categorías y luego unir 1, 2, 3 en todas las líneas: tienes los datos justo delante de ti y el rendimiento no parece afectado en absoluto (no que realmente he probado.)

En cuanto a la pregunta real ... Me gustan los identificadores únicos de RowGUID. No estoy 100% en esto, pero ¿no todas las filas tienen RowGuid interno de todos modos? Si es así, usar RowGuid tomaría menos espacio que ints (o cualquier otra cosa). Lo único que sé es que si es lo suficientemente bueno para usar M $ en GreatPlains, entonces es lo suficientemente bueno para mí. (¿Debo agacharme?)

Oh, una razón más por la que uso GUIDs: uso una estructura de datos jerárquica. Es decir, tengo una tabla 'Compañía' y una tabla 'Proveedor' para las cuales coinciden las Claves principales. Pero también tengo una tabla 'Fabricante' que también 'hereda' de la Compañía. Los campos que son comunes a los proveedores y fabricantes no aparecen en esas tablas, aparecen en la Compañía. En esta configuración, usar int's es mucho más doloroso que Guids. Como mínimo, no puede utilizar claves primarias de identidad.

Me gustan las llaves naturales, siempre que puedo confiar en ellas. Estoy dispuesto a pagar un precio de precio reducido para usar claves que tengan sentido para los expertos en la materia.

Para las tablas que describen entidades, debe haber una clave natural simple que identifique las instancias individuales de la misma forma en que lo hacen las personas. Si el tema no tiene identificadores confiables para una de las entidades, entonces recurriré a una clave sustituta.

Para las tablas que describen relaciones, uso una clave compuesta, donde cada componente hace referencia a una entidad que participa en la relación y, por lo tanto, una fila en una tabla de entidades. Nuevamente, el impacto de rendimiento para usar una clave compuesta es generalmente mínimo.

Como han señalado otros, el término " clave principal " Es un poco engañoso. En el modelo de datos relacionales, el término que se usa es " claves candidatas " ;. Podría haber varias claves candidatas para una sola tabla. Lógicamente, cada uno es tan bueno como el otro. Elegir uno de ellos como " primario " y hacer todas las referencias a través de esa clave es simplemente una elección que el diseñador puede hacer.

Guids.period.

En el caso de que necesite escalar o de asignar la clave principal por medios alternativos, será su amigo. Puedes agregar índices para todo lo demás.


actualizar para aclarar mi declaración.

He trabajado en muchos tipos diferentes de sitios. Desde pequeñas ofertas de servidores individuales hasta grandes respaldadas con múltiples bases de datos y servidores web. Ciertamente, ha habido aplicaciones que habrían estado bien con el incremento automático de entradas como claves principales. Sin embargo, esos no se ajustan al modelo de cómo hago las cosas.

Al usar un GUID puede generar la ID en cualquier lugar. Puede ser generado por un servidor remoto, su aplicación web, dentro de la propia base de datos o incluso dentro de múltiples bases de datos en una situación de varios maestros.

Por otro lado, un INT incrementado automáticamente solo se puede generar de forma segura dentro de la base de datos principal. Una vez más, este podría estar bien si tiene una aplicación que estará íntimamente ligada a ese servidor de base de datos de respaldo y no es algo que le preocupe.

Claro, el uso de GUID significa que debes tener procesos de reindexación cada noche. Sin embargo, si está utilizando algo que no sea un INT con incremento automático, debe hacerlo de todos modos. Diablos, incluso con una INT como principal, es probable que tenga otros índices que necesitan regenerarse para hacer frente a la fragmentación. Por lo tanto, el uso de GUID no agrega otro problema exactamente porque esas tareas deben realizarse independientemente.

Si echa un vistazo a las aplicaciones más grandes, notará algo importante: todas utilizan GUID codificados en Base64 como claves. La razón de esto es simple, el uso de GUID le permite escalar hacia fuera fácilmente, mientras que puede haber una gran cantidad de obstáculos para saltar cuando se intenta escalar INTs.

Nuestra última aplicación atraviesa un período de inserciones pesadas que dura aproximadamente un mes. Después de eso, más del 90% de las consultas son todas seleccionadas para informes. Para aumentar la capacidad, puedo abrir servidores de base de datos adicionales durante este gran período de inserción; y más tarde, fusionarlos fácilmente en un solo DB para informes. Intentar hacer eso con los INT sería una pesadilla absoluta.

Francamente, cada vez que agrupe una base de datos o la replicación de la configuración, el servidor de la base de datos exigirá que tenga GUID en la tabla de todos modos. Entonces, si crees que tu sistema podría necesitar crecer, elige el que sea bueno.

Este es un tema complejo, ya sea que te hayas dado cuenta o no. Podría caer en la sección de estas Preguntas frecuentes de StackOverflow.

¿Qué tipo de preguntas no debería hacer aquí?

Evite hacer preguntas que sean subjetivas, argumentativas o que requieran una discusión extensa. Este es un lugar para preguntas que pueden ser respondidas!

Esto ha sido debatido durante años y continuará siendo debatido durante años. Los únicos indicios de consenso que he visto es que las respuestas son algo predecibles dependiendo de si le estás preguntando a un chico OO (¡los GUID son la única manera de ir!), Un modelador de datos (¡las claves naturales son la única manera de ir!), o un DBA orientado al rendimiento (¡las INT son la única manera de ir!).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top