Si bien esta publicación no será una respuesta completa debido a la falta de información, debería ser capaz de orientarlo en la dirección adecuada o, de lo contrario, obtener información que luego podrá compartir con la comunidad.
Desafortunadamente, esta definición da como resultado una degradación del rendimiento con respecto a la situación anterior con una tabla basada en disco. El orden de magnitud es más o menos un 10% más alto (que en algunos casos alcanza el 100%, entonces el doble de tiempo).
Sobre todo, esperaba obtener una superventaja en escenarios de alta concurrencia, dada la arquitectura sin bloqueo anunciada por Microsoft. En cambio, las peores actuaciones son exactamente cuando hay varios usuarios concurrentes que ejecutan varias consultas en la tabla.
Esto es preocupante ya que definitivamente no debería ser el caso. Ciertas cargas de trabajo no son para tablas de memoria (SQL 2014) y algunas cargas de trabajo se prestan a ello. En la mayoría de las situaciones, puede haber un aumento mínimo en el rendimiento simplemente migrando y eligiendo los índices adecuados.
Originalmente estaba pensando muy estrechamente sobre sus preguntas con respecto a esto:
Preguntas:
- ¿Cuál es el BUCKET_COUNT correcto para establecer?
- ¿Qué tipo de índice debo usar?
- ¿Por qué el rendimiento es peor que con la tabla basada en disco?
Inicialmente creía que había un problema con la tabla de memoria real y los índices no eran óptimos. Si bien hay algunos problemas con la definición del índice de hash optimizado para la memoria, creo que el problema real es con las consultas utilizadas.
-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
SELECT @fixedValue, id2, col1, col2 FROM AnotherTable
Este inserto debería ser extremadamente rápido si solo involucrara la tabla en memoria. Sin embargo, también involucra una tabla basada en disco y está sujeta a todos los bloqueos y bloqueos asociados con eso. Por lo tanto, la pérdida de tiempo real aquí está en la tabla basada en disco.
Cuando hice una prueba rápida contra la inserción de 100,000 filas de la tabla basada en el disco después de cargar los datos en la memoria, fueron tiempos de respuesta de menos de un segundo. Sin embargo, la mayoría de sus datos solo se conservan durante un período de tiempo muy corto, menos de 20 segundos. Esto no le da mucho tiempo para vivir realmente en caché. Además, no estoy seguro de qué tan grandeAnotherTable
es realmente y no sé si los valores se leen del disco o no. Tenemos que confiar en usted para estas respuestas.
Con la consulta Seleccionar:
SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1
Nuevamente, estamos a merced del rendimiento de la tabla basada en interoperabilidad + disco. Además, los tipos no son baratos en los índices HASH y se debe usar un índice no agrupado. Esto se menciona en la guía de índice que vinculé en los comentarios.
Para dar algunos datos reales basados en la investigación, cargué la SearchItems
tabla en memoria con 10 millones de filas y AnotherTable
con 100,000 ya que no sabía el tamaño real o las estadísticas de la misma. Luego usé la consulta de selección anterior para ejecutar. Además, creé una sesión de eventos extendidos en wait_completed y la puse en un búfer de anillo. Se limpió después de cada ejecución. También corrí DBCC DROPCLEANBUFFERS
para simular un entorno donde todos los datos pueden no residir en la memoria.
Los resultados no fueron nada espectaculares al mirarlos en el vacío. Dado que la computadora portátil en la que estoy probando esto está usando un SSD de mayor grado, reduje artificialmente el rendimiento basado en disco para la VM que estoy usando.
Los resultados llegaron sin información de espera después de 5 ejecuciones de la consulta solo en la tabla basada en memoria (eliminando la unión y sin subconsultas). Esto es más o menos como se esperaba.
Sin embargo, cuando utilicé la consulta original, tuve que esperar. En este caso, fue PAGEIOLATCH_SH lo que tiene sentido ya que los datos se leen del disco. Ya que soy el unico usuario en este sistema y no dediqué tiempo a crear un entorno de prueba masivo para inserciones, actualizaciones y eliminaciones en la tabla unida, no esperaba que entrara en vigencia ningún bloqueo o bloqueo.
En este caso, una vez más, la porción significativa de tiempo se gastó en la tabla basada en disco.
Finalmente la consulta de eliminación. Encontrar las filas basadas solo en ID1 no es extremadamente eficiente con un índice has. Si bien es cierto que los predicados de igualdad son para lo que son adecuados los índices hash, el depósito en el que se encuentran los datos se basa en las columnas hash completas. Por lo tanto, id1, id2 donde id1 = 1, id2 = 2 e id1 = 1, id2 = 3 se dividirán en diferentes segmentos, ya que el hash estará en (1,2) y (1,3). Este no será un simple escaneo de rango B-Tree ya que los índices hash no están estructurados de la misma manera. Entonces esperaría que este no sea el índice ideal para esta operación, sin embargo, no esperaría que tome órdenes de magnitud más tiempo de lo experimentado. Me interesaría ver wait_info sobre esto.
Sobre todo, esperaba obtener una superventaja en escenarios de alta concurrencia, dada la arquitectura sin bloqueo anunciada por Microsoft. En cambio, las peores actuaciones son exactamente cuando hay varios usuarios concurrentes que ejecutan varias consultas en la tabla.
Si bien es cierto que los bloqueos se usan para lograr coherencia lógica, las operaciones aún deben ser atómicas. Esto se realiza a través de un operador especial de comparación basado en CPU (razón por la cual In-Memory solo funciona con ciertos procesadores [aunque casi todos los cpus fabricados en los últimos 4 años]). Por lo tanto, no obtenemos todo gratis, aún habrá tiempo para completar estas operaciones.
Otro punto a destacar es el hecho de que en casi todas las consultas, la interfaz utilizada es T-SQL (y no SPROC compilados de forma nativa) que tocan al menos una tabla basada en disco. Es por eso que creo que, al final, en realidad no estamos teniendo un mayor rendimiento, ya que todavía estamos limitados al rendimiento de las tablas basadas en disco.
Seguimiento:
Cree una sesión de evento extendida para wait_completed y especifique un SPID conocido por usted. Ejecute la consulta y bríndenos el resultado o consúmalo internamente.
Danos una actualización de la salida del # 1.
No hay un número mágico para determinar el recuento de depósitos para los índices hash. Básicamente, siempre y cuando los cubos no se llenen por completo y las cadenas de fila permanezcan por debajo de 3 o 4, el rendimiento debe ser aceptable. Esto es como preguntar: "¿En qué debo configurar mi archivo de registro?" - va a depender por proceso, por base de datos, por tipo de uso.
OPTION(OPTIMIZE FOR UNKNOWN)
(ver Sugerencias de tabla )?