2011-11-03 8 views
8

Tengo una tabla que tiene una clave de cadena grande (varchar (1024)) que pensaba indexar en el servidor SQL (quiero poder buscar rápidamente pero también son importantes). En sql 2008 no recibo una advertencia, pero en SQL server 2005 me dice que supera los 900 bytes y que las inserciones/actualizaciones con la columna de este tamaño se descartarán (o algo así)Servidor SQL: ¿vale la pena indexar grandes claves de cadena?

¿Cuáles son mis alternativas si quisiera indexar en esta gran columna? No sé si valdría la pena si pudiera de todos modos.

+1

Su pregunta no es particularmente útil sin contexto. ¿Por qué crees que necesitas un índice? Cómo lo usarías? – Anon246

+0

ver comentario abajo Remus Rusanu – Ghita

+0

Alguien sabe si sería útil usar https://msdn.microsoft.com/en-us/library/ms174415.aspx si debe usar cadenas largas para este tipo de cosas. – HumbleWebDev

Respuesta

13

un índice con todas las llaves cerca de 900 bytes haría ser muy grande y muy profundo (muy pocas teclas por página resultan en B-Trees muy altos).

Depende de cómo va a consultar los valores. Un índice es útil en varios casos:

  • cuando se prueba un valor. Este es el uso más típico, es cuando se busca un valor exacto en la tabla. Los ejemplos típicos son WHERE column='ABC' o una condición de unión ON a.column = B.someothercolumn.
  • cuando se escanea un rango. Esto también es bastante típico cuando se busca en la tabla rango de valores. Además del ejemplo obvio de WHERE column BETWEEN 'ABC' AND 'DEF', hay otros ejemplos menos obvios, como una coincidencia parcial: WHERE column LIKE 'ABC%'.
  • un requisito de pedido. Este uso es menos conocido, pero los índices pueden ayudar a una consulta que tiene un requisito explícito de ORDER BY column para evitar una orden stop-and-go, y también puede ayudar a ciertos requisitos de clasificación ocultos, como un ROW_NUMBER() OVER (ORDER BY column).

Entonces, ¿por qué necesita el índice? ¿Qué tipo de consultas usaría?

Para los escaneos de rango y para los requisitos de pedido, no hay otra solución más que tener el índice, y tendrá que ponderar el costo del índice frente a los beneficios.

Para las sondas, puede, potencialmente, usar hash para evitar indexar una columna muy grande. Cree una columna calculada persistente como column_checksum = CHECKSUM(column) y luego indexe en esa columna. Las consultas deben reescribirse para usar WHERE column_checksum = CHECKSUM('ABC') AND column='ABC'. Se debe considerar cuidadosamente la posibilidad de ponderar la ventaja de un índice estrecho (suma de comprobación de 32 bits) frente a las desventajas de la doble verificación de colisión y la falta de escaneo de rango y capacidades de orden.

después del comentario

Una vez tuve un problema similar y utilicé una columna de hash. El valor era demasiado grande para indexar (> 1K) y también necesitaba convertir el valor en una ID para almacenar (básicamente, un diccionario). Algo a lo largo de las líneas:

create table values_dictionary (
    id int not null identity(1,1), 
    value varchar(8000) not null, 
    value_hash = checksum(value) persisted, 
    constraint pk_values_dictionary_id 
    primary key nonclustered (id)); 
create unique clustered index cdx_values_dictionary_checksum on (value_hash, id); 
go 

create procedure usp_get_or_create_value_id (
    @value varchar(8000), 
    @id int output) 
begin 
    declare @hash = CHECKSUM(@value); 
    set @id = NULL; 
    select @id = id 
     from table 
     where value_hash = @hash 
     and value = @value; 
    if @id is null 
    begin 
     insert into values_dictionary (value) 
     values (@value); 
     set @id = scope_identity(); 
    end 
end 

En este caso, la tabla de diccionario se organiza como un índice agrupado en la columna de la values_hash que agrupa a todos los valores de hash que chocan juntos. La columna id se agrega para hacer que el índice agrupado sea único, evitando la necesidad de un hidden uniqueifier column. Esta estructura hace que la búsqueda de @value sea lo más eficiente posible, sin un índice enormemente ineficiente en value y eludiendo la limitación de 900 caracteres. La clave principal en id no está agrupada, lo que significa que al buscar value y id se incurre en la sobrecarga de una sonda adicional en el índice agrupado.

No estoy seguro si esto responde su problema, obviamente sabe más sobre sus escenarios reales que yo. Además, el código no maneja las condiciones de error y puede insertar entradas @value duplicadas, que pueden ser correctas o no.

+0

Gracias por señalar eso a Remus. Eso en realidad tiene sentido. Creo que estoy utilizando principalmente esta columna en las inserciones para ubicar si ya está allí (y está asociada a la identificación única de la fila) para poder hacer referencia a la identificación de esa columna como clave externa en otra tabla. Eso tiene sentido :-) ? Así que principalmente para el caso descrito: WHERE column = 'ABC' – Ghita

+0

+1, pensé en agregar un índice en una columna hash, pero me pregunté qué hacer con las colisiones, nunca pensé en tener un índice tanto en la columna hash como en la columna id. –

1

General Index Design Guidelines

Cuando se diseña un índice en cuenta las siguientes directrices de columna:

  • mantener la longitud de la clave de índice abreviatura de índices agrupados. Además, los índices agrupados se benefician al crearse en columnas únicas o no nulas. Para obtener más información, vea Pautas de diseño de índice agrupado .

  • columnas que son de la ntext, texto, imagen, varchar (max), nvarchar (max), y tipos varbinary (max) no se pueden especificar como columnas de clave de índice . Sin embargo, los tipos de datos varchar (max), nvarchar (max), varbinary (max) y xml pueden participar en un índice no agrupado como columnas de índice no clave. Para obtener más información, vea Índice con Columnas incluidas.

  • Examine la distribución de datos en la columna. Con frecuencia, una consulta de larga duración es causada por la indexación de una columna con pocos valores únicos o por realizando una combinación en dicha columna. Este es un problema fundamental con los datos y la consulta, y generalmente no se puede resolver sin identificando esta situación. Por ejemplo, un directorio físico teléfono ordenadas alfabéticamente en apellido no acelerará localizar a una persona si todas las personas en la ciudad se nombran Smith o Jones

+0

Entonces, básicamente, en mi caso en el que tengo esta gran columna varchar, ¿debería simplemente no utilizar ningún índice? También un ejemplo en el enlace proporcionado: CREATE INDEX IX_Address_PostalCode ON Person.Address (PostalCode) INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID); En el ejemplo proporcionado, parece que solo PostalCode cuenta con el tamaño del índice. ¿Esto ayuda en absoluto al rendimiento cuando consulta sobre la columna AddressLine1 (por ejemplo, "WHERE AddressLine1 = @ Addr1")? – Ghita