probé 2 juegos basados en métodos de aleatorización contra RAND() mediante la generación de 100.000.000 filas con cada uno. Para nivelar el campo, la salida es un flotante entre 0-1 para imitar a RAND(). La mayor parte del código está poniendo a prueba la infraestructura por lo resumo los algoritmos aquí:
-- Try #1 used
(CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)%500000000000000000+500000000000000000.0)/1000000000000000000 AS Val
-- Try #2 used
RAND(Checksum(NewId()))
-- and to have a baseline to compare output with I used
RAND() -- this required executing 100000000 separate insert statements
Usando CRYPT_GEN_RANDOM fue claramente la más aleatoria ya que sólo hay una oportunidad de ver 0,000000001% hasta 1 duplicado cuando el desplume 10^8 números de una conjunto de 10^18 números. IOW no deberíamos haber visto ningún duplicado y este no tenía ninguno! Este conjunto tardó 44 segundos en generarse en mi computadora portátil.
Cnt Pct
----- ----
1 100.000000 --No duplicates
de ejecución de SQL Server tiempos: tiempo de CPU = 134795 ms, tiempo transcurrido = 39274 ms.
IF OBJECT_ID('tempdb..#T0') IS NOT NULL DROP TABLE #T0;
GO
WITH L0 AS (SELECT c FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c)) -- 2^4
,L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B) -- 2^8
,L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B) -- 2^16
,L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B) -- 2^32
SELECT TOP 100000000 (CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)%500000000000000000+500000000000000000.0)/1000000000000000000 AS Val
INTO #T0
FROM L3;
WITH x AS (
SELECT Val,COUNT(*) Cnt
FROM #T0
GROUP BY Val
)
SELECT x.Cnt,COUNT(*)/(SELECT COUNT(*)/100 FROM #T0) Pct
FROM X
GROUP BY x.Cnt;
En casi 15 órdenes de magnitud menos aleatorio que este método no era el doble de rápido, teniendo sólo 23 segundos para generar números 100M.
Cnt Pct
---- ----
1 95.450254 -- only 95% unique is absolutely horrible
2 02.222167 -- If this line were the only problem I'd say DON'T USE THIS!
3 00.034582
4 00.000409 -- 409 numbers appeared 4 times
5 00.000006 -- 6 numbers actually appeared 5 times
de ejecución de SQL Server tiempos: tiempo de CPU = 77156 ms, tiempo transcurrido = 24613 ms.
IF OBJECT_ID('tempdb..#T1') IS NOT NULL DROP TABLE #T1;
GO
WITH L0 AS (SELECT c FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c)) -- 2^4
,L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B) -- 2^8
,L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B) -- 2^16
,L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B) -- 2^32
SELECT TOP 100000000 RAND(Checksum(NewId())) AS Val
INTO #T1
FROM L3;
WITH x AS (
SELECT Val,COUNT(*) Cnt
FROM #T1
GROUP BY Val
)
SELECT x.Cnt,COUNT(*)*1.0/(SELECT COUNT(*)/100 FROM #T1) Pct
FROM X
GROUP BY x.Cnt;
RAND() por sí solo es inútil para la generación basada en conjunto de modo que genera la línea de base para la comparación de aleatoriedad tomó más de 6 horas y tuvo que ser renovadas varias veces para obtener finalmente el número correcto de filas de salida. También parece que la aleatoriedad deja mucho que desear aunque es mejor que usar suma de comprobación (newid()) para resembrar cada fila.
Cnt Pct
---- ----
1 99.768020
2 00.115840
3 00.000100 -- at least there were comparitively few values returned 3 times
Debido a los reinicios, no se pudo capturar el tiempo de ejecución.
IF OBJECT_ID('tempdb..#T2') IS NOT NULL DROP TABLE #T2;
GO
CREATE TABLE #T2 (Val FLOAT);
GO
SET NOCOUNT ON;
GO
INSERT INTO #T2(Val) VALUES(RAND());
GO 100000000
WITH x AS (
SELECT Val,COUNT(*) Cnt
FROM #T2
GROUP BY Val
)
SELECT x.Cnt,COUNT(*)*1.0/(SELECT COUNT(*)/100 FROM #T2) Pct
FROM X
GROUP BY x.Cnt;
esta pregunta/respuesta puede ser útil: http://stackoverflow.com/a/9039661/47226 –