Cómo devolver registros aleatoriamente en SQL Server

Cómo devolver registros aleatoriamente en SQL Server

En este post te voy a mostrar dos opciones que tenemos en SQL para hacer una búsqueda aleatoria de registros en una tabla y compararlas.

Opción ORDER BY con NEWID()

Esta es una opción de las mas encontradas en internet como ejemplo de búsqueda y consta simplemente en hacer tu consulta y luego agregar un Order BY NEWID() como es el siguiente ejemplo:

USE ADVENTUREWORKS2019 
GO

SELECT TOP (100) * 
FROM
SALES.SALESORDERDETAIL 
ORDER BY NEWID()

Opción con TABLESAMPLE

Esta otra opción utiliza la función TABLESAMPLE la cual es nativa y pensada para hacer esto, la misma funciona con paginas de registros y también se le puede poner cantidades pero no suelen ser exactas y lo que debemos hacer si por ejemplo queremos traer un random de 100 registros es poner números mas altos como el caso del ejemplo siguiente

SELECT TOP (100) * 
FROM
SALES.SALESORDERDETAIL TABLESAMPLE (1000 ROWS)

Performance

Ambos casos que he mostrado darán los mismos resultados funcionales, ¿ pero que pasara con la performance? bueno para eso mostrare ambos planes de ejecución y algunos detalles

Usando NEWID()
Usando TableSample

Al observar ambos planes vemos una diferencia sustancial, ahora para la misma operación voy a ver el costo de cada uno de ellos

MétodoCosto Plan ejecución
NEWID()3.34
TABLESAMPLE0.0041

Sin ninguna duda que la diferencia que se observo en los planes de ejecución se ve muy marcada en los costos en donde usar el TABLESAMPLE es mucho mas eficiente que el otro método

Cómo devolver registros aleatoriamente en SQL Server

Mejorando los tiempos de Rollback usando ADR de SQL 2019

Mejorando los tiempos de Rollback usando ADR de SQL 2019

¿No te ha pasado que cuando haces una transacción y luego al hacer el rollback este ultimo tarda casi el mismo tiempo que tu transacción?

Bueno en SQL 2019 tenemos una nueva funcionalidad llamada accelerated database recovery la cual te va a permitir mejorar estos tiempos.

En el siguiente vídeo de mi canal de Youtube te muestro cómo funciona ADR

Acá te copio el código de ejemplo que he utilizado

CREATE DATABASE DEMOADR;
GO

USE DEMOADR
GO

SET STATISTICS TIME ON

DROP TABLE IF EXISTS t1;

SELECT TOP 5000000 t1.* 
INTO t1 
FROM sys.all_objects AS t1
CROSS JOIN sys.all_objects AS t2
CROSS JOIN sys.all_objects AS t3

ROLLBACK TRAN

-- activar adr

ALTER DATABASE DEMOADR
SET ACCELERATED_DATABASE_RECOVERY = ON;
GO

-- probamos de nuevo

BEGIN TRANSACTION
DROP TABLE IF EXISTS t1;

SELECT TOP 5000000 t1.* 
INTO t1 
FROM sys.all_objects AS t1
CROSS JOIN sys.all_objects AS t2
CROSS JOIN sys.all_objects AS t3

ROLLBACK TRAN
Cómo devolver registros aleatoriamente en SQL Server

Cómo depurar registros de una tabla y moverlos a otra

En varias oportunidades podemos tener la necesidad de depurar alguna tabla grande, esta operación puede ser compleja y hasta impactar la performance de tu base de datos.

En el siguiente tutorial te muestro paso a paso cómo podes hacer un proceso para mover registros viejos a una tabla de historia afectando lo menos posible la performance de tu SQL.

Comparto también el código utilizado en dicho video tutorial

USE master
GO

DROP DATABASE DATOS 
DROP DATABASE DATOS_HISTORY 

CREATE DATABASE DATOS
CREATE DATABASE DATOS_HISTORY

USE DATOS
GO
-- CREAMOS UNA TABLA Y LA LLENAMOS CON 4M DE REGISTROS
SELECT TOP 4000000  
H.AccountNumber,
h.BillToAddressID,
h.CustomerID,
h.OrderDate,
h.SalesOrderNumber,
h.TotalDue       
INTO DBO.VENTAS FROM AdventureWorks2019.Sales.SalesOrderHeader  H
CROSS JOIN AdventureWorks2019.sys.columns C

-- CREAMOS A LA BASE HISTORY LA TABLA VACIA
USE DATOS_HISTORY 
GO

SELECT TOP 0 * INTO DBO.VENTAS FROM DATOS.DBO.VENTAS   

USE DATOS 
GO

-- CALCULAMOS LAS ORDENES MENORES A 2007
SELECT COUNT(1)
FROM DBO.VENTAS 
WHERE OrderDate >= '20130101' and OrderDate < '20140101'

SELECT COUNT(1)
FROM DBO.VENTAS 

use DATOS 

DBCC TRACEON (1224) -- NO ESCALAN LOS LOKEOS PARA ESTA SESION

WHILE 1 = 1
BEGIN
  DELETE TOP (50000) FROM DBO.VENTAS 
    OUTPUT
	  Deleted.AccountNumber,
      Deleted.BillToAddressID,  
      Deleted.CustomerID,
      Deleted.OrderDate,
      Deleted.SalesOrderNumber,
      Deleted.TotalDue    
	
      INTO DATOS_HISTORY.dbo.VENTAS 
      WHERE OrderDate >= '20130101' 
	  and OrderDate < '20140101'

  IF @@ROWCOUNT = 0 BREAK;
END;
SELECT COUNT(1) FROM DBO.VENTAS 
SELECT COUNT(1) FROM DATOS_HISTORY.DBO.VENTAS
Cómo devolver registros aleatoriamente en SQL Server

¿Porque no usa SQL Server mis índices?

En algunas oportunidades observamos que SQL no utiliza nuestros índices creados.

En el siguiente tutorial te explico cuales son las principales causas.

También te comparto los ejemplos utilizados:

USE AdventureWorks2019 
GO

SP_HELPINDEX 'Sales.SalesOrderDetail'

SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID = 897;
 

SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID +1  = 898;

SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID = 897;


SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE upper(ProductID) = '897';


SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID = 897;
 
SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WHERE ProductID = 870;

SELECT SalesOrderDetailID, OrderQty
FROM Sales.SalesOrderDetail
WITH (INDEX=ix_salesorderdetail_productid)
WHERE ProductID = 870;