2012-05-23 19 views
9

Acabo de descubrir la cláusula TABLESAMPLE pero, sorprendentemente, no devuelve el número de filas que he especificado.TABLESAMPLE devuelve el número de filas incorrecto?

La tabla que he usado tiene ~ 14M filas y quería una muestra arbitraria de 10000 filas.

select * from tabData TABLESAMPLE(10000 ROWS) 

No obtengo 10000 sino un número diferente cada vez que lo ejecuto (entre 8000 y 14000).

¿Qué está pasando aquí, he entendido mal el propósito previsto de TABLESAMPLE?

Editar:

David's link lo explica bastante bien.

Esto devuelve siempre 10000 filas más o menos al azar de una manera eficiente:

select TOP 10000 * from tabData TABLESAMPLE(20000 ROWS); 

y la opción REPEATABLE ayuda a obtener siempre el mismo (a menos que los datos han cambiado)

select TOP 10000 * from tabData TABLESAMPLE(10000 ROWS) REPEATABLE(100); 

ya que quería saber si es más costoso usar TABLESAMPLE con una gran cantidad de filas para asegurar (?) que obtengo el número de fila correcto, lo he medido;

1.loop (20 veces):

select TOP 10000 * from tabData TABLESAMPLE(10000 ROWS); 

(9938 row(s) affected) 
(10000 row(s) affected) 
(9383 row(s) affected) 
(9526 row(s) affected) 
(10000 row(s) affected) 
(9545 row(s) affected) 
(9560 row(s) affected) 
(9673 row(s) affected) 
(9608 row(s) affected) 
(9476 row(s) affected) 
(9766 row(s) affected) 
(10000 row(s) affected) 
(9500 row(s) affected) 
(9941 row(s) affected) 
(9769 row(s) affected) 
(9547 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(9478 row(s) affected) 
First batch(only 10000 rows) completed in: 14 seconds! 

2.loop (20 veces):

select TOP 10000 * from tabData TABLESAMPLE(10000000 ROWS); 

(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
(10000 row(s) affected) 
Second batch(max rows) completed in: 13 seconds! 

3.loop: counterscheck con 100% filas aleatorios usando ORDER BY NEWID() :

select TOP 10000 * from tabData ORDER BY NEWID(); 

(10000 row(s) affected) 

cancelado después de una ejecución que duró 23 minutos

Conclusión:

Así sorprendentemente el enfoque con una cláusula de TOP exacta y un gran número de TABLESAMPLE es no más lento. Por lo tanto, es una alternativa muy eficiente a ORDER BY NEWID() si no importa que las filas no sean aleatorias por fila sino por nivel de página (cada página de 8K para la tabla tiene un valor aleatorio).

Respuesta

4

Ver el article here. Necesita agregar una cláusula superior y/o usar la opción repetible para obtener el número de filas que desea.

+0

La opción repetible no ayuda a obtener las 10000 filas. Garantizará que obtengo el mismo número cada vez que se ejecuta la consulta (los datos de la unidad no han cambiado). De todos modos, el artículo lo explica muy bien. Puedo combinarlo con una cláusula 'TOP' (por ejemplo, 10000) para obtener casi 10000 filas. Gracias. –

+1

Tampoco TOP si el resultado es * menos * que el número TABLESAMPLE. –

+0

@David: De hecho, puede obtener el número exacto con TABLESAMPLE: 'seleccione TOP 10000 * de tabData TABLESAMPLE (20000 ROWS);'. Edité mi respuesta en consecuencia. –

1

Este comportamiento se ha documentado anteriormente. Hay una buena reseña en él here.

Creo que puede solucionarlo pasando REPEATABLE con la misma semilla cada vez. Aquí está una snippit de la valoración crítica:

... se dará cuenta que diferentes número de filas se devuelven cada vez. Sin ningún cambio de datos, volver a ejecutar la consulta idéntica sigue dando resultados diferentes. Esto es factor no determinante de la cláusula TABLESAMEPLE.Si la tabla es estática y no se cambian las filas, podría ser el motivo para devolver diferentes números de las filas a devolver en cada ejecución. El factor es 10 PERCENT no son los porcentajes de las filas de la tabla o registros de tablas, es los porcentajes de las páginas de datos de la tabla. Una vez que se seleccionan las páginas de muestra de datos , se devuelven todas las filas de las páginas seleccionadas, no limitará el número de filas muestreadas desde esa página. El factor de relleno de todas las páginas varía según los datos de la tabla. Esto hace que la secuencia de comandos devuelva un recuento de fila diferente en el conjunto de resultados cada vez que se ejecuta . La opción REPETIBLE hace que una muestra seleccionada sea devuelta nuevamente. Cuando REPEATABLE se especifica con el mismo valor repeat_seed , SQL Server devuelve el mismo subconjunto de filas, siempre que no se hayan realizado cambios en la tabla. Cuando se especifica REPEATABLE con un valor diferente de repeat_seed, SQL Server generalmente devolverá una muestra diferente de las filas en la tabla . .

+1

Gracias, pero el artículo relacionado de David lo explica mejor. La opción repetible no ayuda a obtener las 10000 filas, se asegurará de obtener lo mismo cada vez hasta que no se cambien los datos. –

1

He observado lo mismo.

La explicación de la página definitivamente tiene sentido y hace sonar la campana: Debería ver recuentos de filas mucho más predecibles cuando se arregla el tamaño de fila. Pruébalo en una mesa sin columnas con nulos o de longitud variable.

De hecho, acabo de usarlo para probar una teoría sobre su uso para actualizar (probablemente fuiste estimulado por la misma pregunta que yo), y elegir TABLESAMPLE (50000 ROWS) en realidad afectó a 49,849 filas.

+0

Entonces, ¿no podemos confiar en 'TABLESAMPLE' si el número de filas juega un papel importante? –

+0

@TimSchmelter No puedo ver cómo, no. Si importa el número de filas, use TOP o una subconsulta con ROW_NUMBER() o en SQL Server 2012 OFFSET/FETCH. La parte costosa será del tipo si el género necesita ser aleatorio. –

+0

Hmm, saltó esa parte: el enlace de David sugiere combinar el 'TOP' exacto con un número de fila alto en' TABLESAMPLE'. ¡Funciona (ver mi edición)! ¿Crees que un gran número hace que TABLESAMPLE sea más caro entonces? –

2

De la documentación.

El número real de filas que se devuelven puede variar significativamente. Si especifica un número pequeño, como 5, es posible que no reciba los resultados en la muestra.

http://msdn.microsoft.com/en-us/library/ms189108(v=sql.90).aspx

+0

Gracias, pero [Davids Link] (http://www.mssqltips.com/sqlservertip/1308/retrieving-random-data-from-sql-server-with-tablesample/) lo explica mejor que MSDN. –

Cuestiones relacionadas