2011-01-17 13 views
24

Eche un vistazo al siguiente ejemplo. Muestra que la búsqueda dentro de una cadena Unicode (nvarchar) es casi ocho veces peor que buscar dentro de una cadena varchar. Y a la par con las conversiones implícitas. Buscando una explicación para esto. O una forma de buscar dentro de cadenas nvarchar de manera más eficiente.SQL Server usa una CPU alta cuando busca dentro de las cadenas nvarchar

use tempdb 
create table test 
(
    testid int identity primary key, 
    v varchar(36), 
    nv nvarchar(36), 
    filler char(500) 
) 
go 

set nocount on 
set statistics time off 
insert test (v, nv) 
select CAST (newid() as varchar(36)), 
    CAST (newid() as nvarchar(36)) 
go 1000000 

set statistics time on 
-- search utf8 string 
select COUNT(1) from test where v like '%abcd%' option (maxdop 1) 
-- CPU time = 906 ms, elapsed time = 911 ms. 

-- search utf8 string using unicode (uses convert_implicit) 
select COUNT(1) from test where v like N'%abcd%' option (maxdop 1) 
-- CPU time = 6969 ms, elapsed time = 6970 ms. 

-- search unicode string 
select COUNT(1) from test where nv like N'%abcd%' option (maxdop 1) 
-- CPU time = 6844 ms, elapsed time = 6911 ms. 
+2

FYI, resulta que la CPU más alta en el ejemplo conversión implícita (query 2) * no * es debido a la conversión en sí, sino a la lógica de comparación Unicode, al igual que la otra consulta Unicode (query 3) . –

+0

Esta es una pregunta excelente y he agregado un enlace a mi respuesta aquí [varchar-vs-nvarchar-performance] (http://stackoverflow.com/questions/35366) – gbn

+0

@gbn, en esa publicación se ha vinculado a http: //msdn.microsoft.com/en-us/library/ms189617.aspx, que es la explicación que más me gusta. ¡Gracias! –

Respuesta

20

Buscando una explicación para esto.

NVarchar es 16 bits y reglas de comparación Unicode son mucho más complicados que ASCII - caracteres especiales para los distintos idiomas que son compatibles a la vez requieren más procesamiento cotización alguna.

+0

Hmmm. interesante. En teoría, usar una intercalación binaria puede ser un poco más rápido ... estad atentos. –

+5

¡Dios mío, eso es todo! Cuando utilizo "nv COLLATE Latin1_General_Bin like N '% ABCD%'" obtengo: - Tiempo de CPU = 890 ms, tiempo transcurrido = 881 ms. –

+5

Déjeme adivinar, usted es hablante de inglés;) Hable con algunas personas de Alemania y Francia y empiece a darse cuenta de las reglas parcialmente IMPAR en acentos y caracteres especiales. Esto simplemente toma tiempo para resolverlo;) Bien, logramos eso;) – TomTom

1

He visto problemas similares en SQL Server. Hubo un caso en el que estaba usando consultas parametrizadas, y mi parámetro fue UTF-8 (predeterminado en .net) y el campo varchar (por lo que no es utf-8). Terminó con convertir cada valor de índice a utf-8 solo para hacer una simple búsqueda de índice. Esto podría estar relacionado con el hecho de que toda la cadena podría ser traducida a otro conjunto de caracteres para hacer la comparación. También para nvarchar, "a" sería lo mismo que "& aacute;" lo que significa que hay mucho más trabajo allí para averiguar si 2 cadenas son iguales en Unicode. Además, es posible que desee utilizar la indexación de texto completo, aunque no estoy seguro si eso resuelve su problema.

+0

Gracias Kibbee. La intercalación que se utilizó ya era sensible al acento, por lo que no fue una causa en particular.Además, la indexación de texto completo no funciona en mi caso porque las cadenas que estoy buscando no están dentro de los límites de las palabras. Pero gracias por ayudarme –

+0

-1 Realmente no quiero ser negativo, pero todo lo que se dice en esta respuesta es incorrecto. .NET/Windows/SQL Server usa UTF-16 Little Endian ("Unicode" en Microsoft-land). No hay UTF-8 a menos que tenga un 'byte []' de esos bytes; una cadena es UTF-16 LE, igual que 'NVARCHAR' (y' XML') en SQL Server. Su problema fueron los datos 'VARCHAR' que utilizan una intercalación de SQL Server (uno que comienza con' SQL_') en el índice y que lo comparan con una cadena 'NVARCHAR'. Esa combinación requiere una conversión implícita debido a 2 algoritmos de clasificación diferentes. Los datos 'VARCHAR' con una intercalación de Windows no harían eso. (cont) –

+0

Además, ''a'' y' 'á'' no son lo mismo en 'NVARCHAR'. Si se equiparan o no se determina por la opción de sensibilidad de acento (es decir, '_AI' frente a' _AS' en el nombre) de cada colación particular. Y se pueden considerar como iguales o diferentes para ambos 'VARCHAR' y' NVARCHAR'. Intente lo siguiente para ver que son iguales a los datos 'VARCHAR' utilizando una clasificación de SQL Server en desuso:' SELECT 1 WHERE 'a' = 'á' COLLATE SQL_Latin1_General_CP1_CI_AI; '. Y para aclarar: podría haber usado un parámetro 'VARCHAR' en su consulta para solucionarlo; se convirtió a 'NVARCHAR' debido a la precedencia del tipo de datos. –

2

Supongo que LIKE se implementa utilizando un algoritmo O (n^2) en oposición a un algoritmo O (n); probablemente tendría que ser para que funcione el % líder. Dado que la cadena Unicode es dos veces más larga, parece consistente con sus números.

+0

Tiene razón, esa explicación es consistente con los números, hasta que realicé otro experimento (vea el comentario bajo la respuesta de TomTom). Gracias por pasar por Larry –

+0

@Michael: tengo curiosidad acerca de si se ve el mismo resultado con la columna varchar. –

+0

Con colación varchar + latin obtengo "cpu time = 891", que es un poco mejor que sin la intercalación, pero no puedo decir si es significativamente mejor sin tener una buena comprensión de las estadísticas. :-) –

2

A LIKE %% search se implementa como> y <. Ahora más el número de filas, más el tiempo de procesamiento, ya que SQL realmente no puede hacer un uso efectivo de las estadísticas para %% como las búsquedas.

Además, la búsqueda Unicode requiere almacenamiento adicional y, junto con las complicaciones de intercalación, normalmente no sería tan eficiente como la búsqueda simple varchar de vanilla. La búsqueda de colación más rápida que ha observado es la búsqueda de colación binaria.

Este tipo de búsquedas son las más adecuadas para la búsqueda de texto completo o implementadas usando FuzzyLookup con una tabla hash en memoria en caso de que tenga mucha RAM y una tabla bastante estática.

HTH

Cuestiones relacionadas