Categoría: Seguridad de la base de datos
Dependencia de Usuarios en SQL: Guía Completa
Dependencia de Usuarios en SQL, en el mundo de la gestión de bases de datos, uno de los aspectos más críticos es el control de los permisos y dependencias de los usuarios. En este artículo, exploraremos cómo manejar las dependencias de usuarios en SQL, proporcionaremos ejemplos prácticos y discutiremos las mejores prácticas para asegurar una gestión eficiente y segura.
¿Qué es la Dependencia de Usuarios en SQL?
La dependencia de usuarios en SQL se refiere a la relación y permisos que un usuario tiene dentro de una base de datos. Estas dependencias son cruciales para garantizar que los usuarios tengan los permisos necesarios para realizar sus tareas sin comprometer la seguridad y la integridad de la base de datos.
Ejemplo de Dependencia de Usuarios
Imaginemos un escenario donde necesitamos identificar todos los objetos de la base de datos a los que un usuario específico tiene acceso. Esto es especialmente útil en auditorías de seguridad o cuando se realizan cambios en los permisos de los usuarios.
Consultas SQL para Gestionar Dependencias de Usuarios
Vamos a profundizar en cómo podemos usar SQL para identificar y gestionar estas dependencias. A continuación, presentamos una consulta que permite listar los objetos de la base de datos a los que un usuario específico tiene acceso.
Consulta de Ejemplo
SELECT DISTINCT
o.name AS ObjectName,
o.type_desc AS ObjectType,
s.name AS SchemaName,
u.name
FROM sys.database_principals u
INNER JOIN sys.database_permissions p ON u.principal_id = p.grantee_principal_id
INNER JOIN sys.objects o ON p.major_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE u.name = 'DOMINIO\\usuario'
ORDER BY SchemaName;
Explicación de la Consulta
- sys.database_principals: Esta vista del sistema contiene información sobre los usuarios y roles de la base de datos.
- sys.database_permissions: Esta vista muestra los permisos asignados a los usuarios y roles.
- sys.objects: Contiene información sobre los objetos dentro de la base de datos, como tablas, vistas, procedimientos almacenados, etc.
- sys.schemas: Proporciona información sobre los esquemas en la base de datos.
La consulta se compone de varias partes que trabajan en conjunto para revelar las dependencias de usuarios:
- FROM: Esta cláusula especifica las tablas de las que se extraerá la información:
sys.database_principals
,sys.database_permissions
,sys.objects
ysys.schemas
. - INNER JOIN: Se utilizan tres combinaciones internas para relacionar las tablas entre sí:
sys.database_principals
consys.database_permissions
a través deprincipal_id
.sys.database_permissions
consys.objects
a través demajor_id
.sys.objects
consys.schemas
a través deschema_id
.
- SELECT DISTINCT: Esta cláusula garantiza que solo se muestren filas únicas, evitando duplicados.
- SELECT Columnas: La consulta selecciona las siguientes columnas:
o.name
comoObjectName
: El nombre del objeto de la base de datos.o.type_desc
comoObjectType
: El tipo de objeto de la base de datos (por ejemplo, tabla, vista, procedimiento almacenado).s.name
comoSchemaName
: El nombre del esquema al que pertenece el objeto.u.name
: El nombre del usuario que posee el permiso.
- WHERE: Esta cláusula filtra los resultados para mostrar solo las dependencias del usuario específico
'DOMINIO\usuario'
. - ORDER BY: La consulta ordena los resultados por
SchemaName
para una mejor organización.
Ejemplo de Ejecución:
Al ejecutar la consulta, se obtiene una tabla que muestra en detalle las dependencias del usuario especificado. Cada fila representa un permiso otorgado al usuario sobre un objeto específico, indicando el nombre del objeto, su tipo, el esquema al que pertenece y el nombre del usuario.
¿Por qué son Importantes las Dependencia de Usuarios en SQL?
Las dependencias de usuarios juegan un papel fundamental en la administración de bases de datos por diversas razones:
- Seguridad: Las dependencias permiten establecer controles de acceso granulares, restringiendo el acceso a información sensible solo a los usuarios autorizados.
- Integridad de Datos: Al limitar el acceso a objetos específicos, se minimiza el riesgo de errores o modificaciones no deseadas que puedan afectar la integridad de los datos.
- Auditoría y Resolución de Problemas: Identificar las dependencias de usuarios facilita la trazabilidad de acciones y la resolución de problemas relacionados con el acceso a la base de datos.
Mejores Prácticas para la Gestión de Permisos en SQL
A continuación, presentamos algunas mejores prácticas para la gestión de permisos en SQL:
1. Principio de Menor Privilegio
Otorgar a los usuarios solo los permisos que necesitan para realizar sus tareas. Esto minimiza el riesgo de accesos no autorizados y posibles daños a la base de datos.
2. Uso de Roles
En lugar de asignar permisos directamente a los usuarios, es recomendable utilizar roles. Los roles permiten agrupar permisos y asignarlos a usuarios, lo que facilita la gestión y auditoría de permisos.
3. Auditorías Regulares
Realizar auditorías regulares de los permisos de los usuarios para asegurarse de que solo los usuarios autorizados tienen acceso a los recursos necesarios. Esto también ayuda a identificar y corregir posibles problemas de seguridad.
4. Registro de Actividades
Implementar el registro de actividades de los usuarios para monitorear y auditar las acciones realizadas en la base de datos. Esto es crucial para detectar y responder a actividades sospechosas o no autorizadas.
Ejemplo Práctico: Gestión de Permisos en una Empresa
Supongamos que trabajamos en una empresa donde necesitamos gestionar los permisos de varios usuarios que pertenecen a diferentes departamentos. Queremos asegurarnos de que cada usuario solo tenga acceso a los objetos que necesita para su trabajo.
Paso 1: Creación de Roles
Primero, creamos roles para cada departamento.
CREATE ROLE ventas;
CREATE ROLE marketing;
CREATE ROLE it;
Paso 2: Asignación de Permisos a Roles
Asignamos permisos a cada rol según las necesidades del departamento.
GRANT SELECT ON esquema_ventas.tabla_clientes TO ventas;
GRANT SELECT, INSERT ON esquema_marketing.campañas TO marketing;
GRANT EXECUTE ON esquema_it.proc_backup TO it;
Paso 3: Asignación de Roles a Usuarios
Asignamos los roles creados a los usuarios correspondientes.
EXEC sp_addrolemember 'ventas', 'usuario1';
EXEC sp_addrolemember 'marketing', 'usuario2';
EXEC sp_addrolemember 'it', 'usuario3';
Auditoría de Permisos
Para auditar los permisos de un usuario específico, utilizamos la consulta presentada anteriormente. Esto nos permitirá revisar qué objetos están accesibles para cada usuario y ajustar los permisos según sea necesario.
Conclusión
La gestión de las dependencias de usuarios en SQL es un aspecto fundamental para mantener la seguridad y eficiencia en una base de datos. Utilizando las mejores prácticas y herramientas disponibles, podemos asegurarnos de que los usuarios tengan los permisos adecuados y que la base de datos esté protegida contra accesos no autorizados.
La consulta presentada es una poderosa herramienta para auditar y gestionar estos permisos, y su implementación adecuada puede marcar una gran diferencia en la administración de bases de datos.
Archivos MDF y NDF en SQL Server: Guía Completa
Entendiendo Kerberos en SQL Server: Seguridad y Autenticación
SSPI handshake failed with error code 0x8009030c SQL Server
Entendiendo Kerberos en SQL Server: Seguridad y Autenticación
SSPI handshake failed with error code 0x8009030c SQL Server
Detectando y Mitigando Posibles Ataques en SQL Server: Un Caso de Estudio
Recientemente, nos encontramos con un error intrigante en nuestro entorno de SQL Server 2019 que levantó algunas alarmas de seguridad. El mensaje de error decía:
SSPI handshake failed with error code 0x8009030c, state 14 while establishing a connection with integrated security; the connection has been closed. Reason: AcceptSecurityContext failed. The operating system error code indicates the cause of failure. The logon attempt failed [CLIENT: xxx.xxx.xxx.xxx]
La seguridad de los datos es más importante que nunca. Los servidores SQL Server almacenan información confidencial que puede ser un objetivo atractivo para los ciberdelincuentes. En este blog, compartiremos un caso de estudio real en el que un mensaje de error «SSPI handshake failed» en SQL Server 2019 alertó sobre un posible intento de ataque
Aunque inicialmente sospechamos de un problema de configuración de alguna aplicación, pronto descubrimos que este incidente podría ser indicativo de un posible ataque. A continuación, comparto cómo abordamos esta situación y los pasos para proteger nuestros servidores SQL de ataques similares. Luego nos dimos cuenta que eran los chicos de seguridad con juguete nuevo.
1. Revisar los Registros de Eventos

Lo primero que hicimos fue verificar los registros de eventos en el servidor para identificar cualquier patrón sospechoso de intentos de conexión fallidos:
- En el Visor de Eventos de Windows, revisamos las secciones de
Security
yApplication
para buscar eventos relacionados con fallos de autenticación y errores de conexión. Esto nos ayudó a identificar si los intentos provenían de una sola IP o de varias, lo cual podría indicar un intento de fuerza bruta.
2. Auditar Intentos de Inicio de Sesión
Para tener un mejor control sobre quién intenta acceder a nuestro servidor, habilitamos la auditoría de inicio de sesión en SQL Server:
EXEC xp_readerrorlog 0, 1, N'Login failed';
Además, en SQL Server Management Studio (SSMS), configuramos la auditoría completa de inicio de sesión para rastrear tanto los intentos exitosos como los fallidos:
- Navegamos a
Security
>Logins
> Propiedades de un inicio de sesión específico >Securables
>Permissions
.
3. Revisar las Políticas de Seguridad

Verificamos nuestras políticas de seguridad del dominio y del servidor para asegurarnos de que estaban correctamente configuradas y así prevenir accesos no autorizados:
- Implementamos políticas de contraseña fuertes y requisitos de bloqueo de cuenta.
- Configuramos listas blancas y negras de direcciones IP para restringir el acceso.
4. Monitoreo de la Red
Utilizamos herramientas de monitoreo de red para detectar tráfico sospechoso y actividades inusuales:
- Herramientas como Wireshark y NetFlow nos ayudaron a identificar patrones que podrían sugerir un ataque.
- Implementamos soluciones de detección de intrusos (IDS/IPS) para alertarnos sobre posibles amenazas en tiempo real.
5. Implementar Seguridad Adicional
Para fortalecer aún más nuestra defensa, adoptamos varias medidas adicionales de seguridad:
- Firewall: Configuramos reglas de firewall para permitir solo el acceso de IPs autorizadas a SQL Server.
- Seguridad a nivel de red: Implementamos VPNs para proteger el tráfico entre los clientes y el servidor.
- Seguridad a nivel de aplicación: Configuramos autenticación multifactor (MFA) para acceder a SQL Server, añadiendo una capa extra de protección.
6. Consultar con el Equipo de Seguridad
Dada la sospecha de un ataque, contactamos a nuestro equipo de seguridad de TI. Después de uns risas nos comentaron que hacian una prueba de vulnerabilidad en la red, ellos realizaron una revisión exhaustiva y tomaron medidas adicionales para asegurar nuestro entorno. Su experiencia fue crucial para implementar soluciones de seguridad avanzadas y mitigar cualquier riesgo potencial.
7. Revisar las Cuentas de Usuario
Asegurarnos de que todas las cuentas de usuario en SQL Server estaban debidamente administradas fue otro paso esencial:
- Desactivamos o eliminamos cuentas innecesarias.
- Verificamos que las cuentas de servicio tenían los permisos mínimos necesarios para operar.
8. Actualizaciones y Parches
Mantuvimos nuestro servidor SQL Server y el sistema operativo actualizados con los últimos parches de seguridad para protegernos contra vulnerabilidades conocidas.
Prevención de ataques SSPI Handshake:
La mejor manera de protegerse contra ataques SSPI Handshake es implementar medidas de seguridad proactivas que dificulten a los atacantes acceder a su servidor SQL Server. Algunas de las mejores prácticas de seguridad que puede seguir incluyen:
- Utilizar contraseñas seguras y complejas: Evite utilizar contraseñas fáciles de adivinar, como nombres, fechas de nacimiento o palabras comunes. En su lugar, utilice contraseñas largas y complejas que combinen letras mayúsculas, minúsculas, números y símbolos.
- Implementar el principio de mínimo privilegio: Otorgue a los usuarios y aplicaciones solo los permisos que necesitan para realizar su trabajo. Evite otorgar privilegios administrativos innecesarios.
- Mantener el software actualizado: Aplique los parches de seguridad más recientes para su sistema operativo y software SQL Server tan pronto como estén disponibles. Estos parches a menudo corrigen vulnerabilidades que podrían ser explotadas por los atacantes.
- Realizar auditorías de seguridad periódicas: Realice auditorías de seguridad regulares de su entorno SQL Server para identificar y corregir posibles vulnerabilidades.
- Capacitar a los usuarios sobre las prácticas de seguridad adecuadas: Eduque a sus usuarios sobre las amenazas cibernéticas y las mejores prácticas para proteger su información.
Conclusión
El error «SSPI handshake failed» puede ser un indicativo de problemas de configuración, pero también puede señalar posibles intentos de ataque. Al tomar medidas proactivas y revisar minuciosamente nuestro entorno, no solo identificamos la causa del problema, sino que también fortalecimos nuestra postura de seguridad. Si bien en nuestro caso se trataba de una herramienta de prueba de seguridad, el proceso nos preparó mejor para enfrentar verdaderas amenazas en el futuro.
Script Creación de Roles en SQL Server
UPDATE JOIN en SQL para Actualizar Tablas Relacionadas
¿Es Necesario Hacer un Refresco de una Vista en SQL Server?
Eliminar usuarios huérfanos SQL server
Auditoría descubriendo las Conexiones en SQL Server
En el mundo del desarrollo y administración de bases de datos, monitorear las conexiones activas es crucial para asegurar la seguridad y el rendimiento del sistema. SQL Server proporciona varias vistas de administración dinámica (DMVs) que ayudan a los administradores de bases de datos (DBAs) a obtener información detallada sobre las conexiones activas y las sesiones del servidor. Dos de estas DMVs son sys.dm_exec_connections
y sys.sysprocesses
.
Entendiendo las Vistas de Administración Dinámica (DMVs)
¿Qué son las DMVs?
Las DMVs son vistas y funciones que exponen el estado interno del servidor SQL y proveen información sobre la salud y rendimiento del servidor. Estas vistas son esenciales para la gestión y optimización de las bases de datos, permitiendo a los administradores diagnosticar problemas y tomar decisiones informadas sobre el mantenimiento y la configuración del sistema.
Introducción a sys.dm_exec_connections
La vista sys.dm_exec_connections
devuelve información sobre las conexiones de cliente a SQL Server. Cada fila en esta vista representa una conexión de cliente única al servidor. Algunas de las columnas clave en esta vista incluyen:
session_id
: Identificador de la sesión en SQL Server.client_net_address
: Dirección IP del cliente.auth_scheme
: Esquema de autenticación utilizado.
Introducción a sys.sysprocesses
La vista sys.sysprocesses
proporciona información sobre los procesos activos en SQL Server. Aunque es una vista más antigua y ha sido reemplazada en gran medida por las vistas de administración dinámica modernas, todavía se utiliza comúnmente debido a su familiaridad y la amplia documentación disponible. Algunas columnas importantes son:
spid
: Identificador del proceso en SQL Server.hostname
: Nombre del host desde donde se originó la conexión.program_name
: Nombre del programa que inició la conexión.
Consultas Prácticas con sys.dm_exec_connections
y sys.sysprocesses
Consulta de Conexiones Específicas por Dirección IP
Para ilustrar el uso de estas vistas, consideremos un escenario donde necesitamos obtener información sobre las conexiones activas desde una dirección IP específica, por ejemplo, 10.28.0.153
. La siguiente consulta logra esto uniendo sys.dm_exec_connections
y sys.sysprocesses
:
SELECT b.spid, b.hostname, b.program_name, a.auth_scheme
FROM sys.dm_exec_connections a
INNER JOIN sys.sysprocesses b
ON a.session_id = b.spid
WHERE a.client_net_address = '10.28.0.153';
Desglose de la Consulta:
- SELECT b.spid, b.hostname, b.program_name, a.auth_scheme: Esta cláusula selecciona las columnas que nos interesan de ambas vistas.
- FROM sys.dm_exec_connections a: Especifica la vista principal de donde estamos obteniendo las conexiones.
- INNER JOIN sys.sysprocesses b: Realiza una unión interna con la vista
sys.sysprocesses
usandosession_id
yspid
como claves de unión. - WHERE a.client_net_address = ‘10.28.0.153’: Filtra los resultados para mostrar solo las conexiones desde la dirección IP
10.28.0.153
.
Esta consulta nos proporciona información útil, como el esquema de autenticación utilizado (auth_scheme
), que puede ser Kerberos, NTLM, SQL, entre otros.
Consulta de Todas las Conexiones Ordenadas por Dirección IP
Para obtener una visión completa de todas las conexiones activas y ordenarlas por la dirección IP del cliente, podemos utilizar la siguiente consulta:
SELECT a.*
FROM sys.dm_exec_connections a
INNER JOIN sys.sysprocesses b
ON a.session_id = b.spid
ORDER BY a.client_net_address;
Desglose de la Consulta:
- SELECT a.*: Selecciona todas las columnas de
sys.dm_exec_connections
para una visión detallada. - INNER JOIN sys.sysprocesses b: Similar a la consulta anterior, realiza una unión con
sys.sysprocesses
. - ORDER BY a.client_net_address: Ordena los resultados según la dirección IP del cliente.

Ejemplos Prácticos
Ejemplo 1: Monitoreo de Conexiones desde un Servidor Específico
Imaginemos que estamos administrando una red de servidores y necesitamos monitorear las conexiones provenientes de un servidor específico con la IP 10.28.0.153
. Ejecutando la primera consulta, podemos identificar rápidamente todas las conexiones activas desde este servidor, junto con detalles como el nombre del programa que inició la conexión y el esquema de autenticación utilizado. Esto es particularmente útil para identificar conexiones no autorizadas o inesperadas.
Ejemplo de Resultado:
spid | hostname | program_name | auth_scheme
-----|---------------|-----------------------|------------
52 | SERVER1 | Microsoft SQL Server | KERBEROS
53 | SERVER1 | SQLCMD | NTLM
54 | SERVER1 | .NET SqlClient Data | SQL
Ejemplo 2: Auditoría de Conexiones para Seguridad
Supongamos que estamos realizando una auditoría de seguridad y necesitamos revisar todas las conexiones activas a nuestro servidor SQL. La segunda consulta nos proporciona una lista completa de conexiones, ordenadas por dirección IP. Esto nos permite identificar patrones inusuales, como múltiples conexiones desde una misma dirección IP, lo cual podría indicar un ataque o una mala configuración del cliente.
Ejemplo de Resultado:
ession_id | client_net_address | auth_scheme
-----------|--------------------|------------
52 | 10.28.0.153 | KERBEROS
53 | 10.28.0.154 | NTLM
54 | 10.28.0.155 | SQL
Buenas Prácticas para el Monitoreo de Conexiones
Automatización de Consultas
Para mantener un monitoreo continuo, es recomendable automatizar la ejecución de estas consultas y almacenar los resultados en una tabla de auditoría. Esto se puede lograr mediante trabajos de SQL Server Agent que ejecuten las consultas a intervalos regulares.
Alertas y Notificaciones
Configurar alertas y notificaciones basadas en ciertos criterios, como un número inusual de conexiones desde una misma dirección IP o conexiones que utilizan esquemas de autenticación inseguros, puede ayudar a detectar y responder rápidamente a posibles problemas.
Análisis Periódico
Realizar análisis periódicos de los datos recopilados permite identificar tendencias y patrones a lo largo del tiempo. Esto es crucial para la planificación de capacidad y la identificación de posibles problemas antes de que afecten al rendimiento del sistema.
Conclusión
Las vistas sys.dm_exec_connections
y sys.sysprocesses
son herramientas poderosas para cualquier DBA que necesite monitorear y gestionar conexiones en SQL Server. Al entender cómo utilizar estas vistas y aplicar consultas específicas, podemos obtener una visión clara y detallada del estado de las conexiones en nuestro servidor, lo que nos permite tomar decisiones informadas para mejorar la seguridad y el rendimiento del sistema.
Monitoreo y Mantenimiento SQL: Mantén Tu Base de Datos Saludable
Descarga de SQL Server Management Studio (SSMS)
Eliminar usuarios huérfanos SQL server
Script para saber el histórico de queries ejecutados SQL
En el mundo del desarrollo de bases de datos, la gestión y optimización de consultas SQL es una tarea fundamental para garantizar el rendimiento y la integridad de los datos. Una práctica recomendada es mantener un script histórico de las queries ejecutadas en SQL. En este artículo, exploraremos las razones por las cuales es necesario conservar este historial y cómo puede beneficiar a tu organización.
1. Auditoría y Cumplimiento
Uno de los motivos más importantes para mantener un historial de consultas SQL es la auditoría. En muchas industrias, existen regulaciones estrictas que requieren un seguimiento detallado de quién accede a la base de datos y qué acciones realizan. Un script histórico proporciona una pista de auditoría completa que puede ser invaluable durante auditorías internas y externas.
2. Resolución de Problemas
Cuando se presenta un problema en la base de datos, ya sea un error o un rendimiento lento, tener un historial de consultas ejecutadas puede ayudar a identificar rápidamente la causa. Los administradores de bases de datos pueden revisar las consultas previas para ver si hubo algún cambio significativo o una consulta ineficiente que esté afectando el rendimiento.
3. Optimización del Rendimiento
El análisis de las consultas históricas permite a los administradores identificar patrones y tendencias en el uso de la base de datos. Con esta información, pueden optimizar las consultas y mejorar el rendimiento general del sistema. Por ejemplo, si una consulta específica se ejecuta frecuentemente y tarda mucho tiempo, se pueden tomar medidas para optimizarla o ajustar los índices de la base de datos.
4. Recuperación de Datos
En situaciones donde se ha producido una pérdida de datos accidental, el historial de consultas puede ser crucial para la recuperación. Al revisar las consultas ejecutadas, es posible identificar qué datos se vieron afectados y restaurarlos a su estado original.
5. Capacitación y Mejora Continua
Para equipos de desarrollo y administración de bases de datos, el historial de consultas es una herramienta de aprendizaje. Los nuevos miembros del equipo pueden estudiar las consultas previas para entender las mejores prácticas y los estándares de la organización. Además, permite una revisión continua y mejoras en las prácticas de escritura de consultas SQL.
6. Documentación
Mantener un historial de consultas ejecutadas también sirve como documentación viva del uso de la base de datos. Esto puede ser útil no solo para los administradores, sino también para otros stakeholders que necesiten entender cómo se está utilizando la base de datos.
Script para ver el histórico de queries lanzados en sql (Insert)
select top(100)
creation_time,
last_execution_time,
execution_count,
total_worker_time/1000 as CPU,
convert(money, (total_worker_time))/(execution_count*1000)as [AvgCPUTime],
qs.total_elapsed_time/1000 as TotDuration,
convert(money, (qs.total_elapsed_time))/(execution_count*1000)as [AvgDur],
total_logical_reads as [Reads],
total_logical_writes as [Writes],
total_logical_reads+total_logical_writes as [AggIO],
convert(money, (total_logical_reads+total_logical_writes)/(execution_count + 0.0)) as [AvgIO],
[sql_handle],
plan_handle,
statement_start_offset,
statement_end_offset,
plan_generation_num,
total_physical_reads,
convert(money, total_physical_reads/(execution_count + 0.0)) as [AvgIOPhysicalReads],
convert(money, total_logical_reads/(execution_count + 0.0)) as [AvgIOLogicalReads],
convert(money, total_logical_writes/(execution_count + 0.0)) as [AvgIOLogicalWrites],
query_hash,
query_plan_hash,
total_rows,
convert(money, total_rows/(execution_count + 0.0)) as [AvgRows],
total_dop,
convert(money, total_dop/(execution_count + 0.0)) as [AvgDop],
total_grant_kb,
convert(money, total_grant_kb/(execution_count + 0.0)) as [AvgGrantKb],
total_used_grant_kb,
convert(money, total_used_grant_kb/(execution_count + 0.0)) as [AvgUsedGrantKb],
total_ideal_grant_kb,
convert(money, total_ideal_grant_kb/(execution_count + 0.0)) as [AvgIdealGrantKb],
total_reserved_threads,
convert(money, total_reserved_threads/(execution_count + 0.0)) as [AvgReservedThreads],
total_used_threads,
convert(money, total_used_threads/(execution_count + 0.0)) as [AvgUsedThreads],
case
when sql_handle IS NULL then ' '
else(substring(st.text,(qs.statement_start_offset+2)/2,(
case
when qs.statement_end_offset =-1 then len(convert(nvarchar(MAX),st.text))*2
else qs.statement_end_offset
end - qs.statement_start_offset)/2 ))
end as query_text,
db_name(st.dbid) as database_name,
object_schema_name(st.objectid, st.dbid)+'.'+object_name(st.objectid, st.dbid) as [object_name],
sp.[query_plan]
from sys.dm_exec_query_stats as qs with(readuncommitted)
cross apply sys.dm_exec_sql_text(qs.[sql_handle]) as st
cross apply sys.dm_exec_query_plan(qs.[plan_handle]) as sp
WHERE st.[text] LIKE '%insert%'
order by creation_time desc
Explicación de la Consulta anterior que muestra el histórico de queries en SQL
Consulta SQL que sirve para monitorizar y obtener estadísticas detalladas sobre consultas que contienen la palabra «INSERT«. Este tipo de análisis es fundamental para identificar y optimizar el rendimiento de las operaciones de inserción en una base de datos.

Desglose de la Consulta
Selección de los Primeros 100 Registros
TOP(100)
La consulta selecciona los primeros 100 registros de los datos que cumple con las condiciones especificadas.
Campos y Cálculos
A continuación, se seleccionan varios campos y se realizan ciertos cálculos para proporcionar métricas detalladas sobre el rendimiento de las consultas:
creation_time,
last_execution_time,
execution_count,
total_worker_time / 1000 AS CPU,
CONVERT(money, (total_worker_time)) / (execution_count * 1000) AS [AvgCPUTime],
qs.total_elapsed_time / 1000 AS TotDuration,
CONVERT(money, (qs.total_elapsed_time)) / (execution_count * 1000) AS [AvgDur],
total_logical_reads AS [Reads],
total_logical_writes AS [Writes],
total_logical_reads + total_logical_writes AS [AggIO],
CONVERT(money, (total_logical_reads + total_logical_writes) / (execution_count + 0.0)) AS [AvgIO],
[sql_handle],
plan_handle,
statement_start_offset,
statement_end_offset,
plan_generation_num,
total_physical_reads,
CONVERT(money, total_physical_reads / (execution_count + 0.0)) AS [AvgIOPhysicalReads],
CONVERT(money, total_logical_reads / (execution_count + 0.0)) AS [AvgIOLogicalReads],
CONVERT(money, total_logical_writes / (execution_count + 0.0)) AS [AvgIOLogicalWrites],
query_hash,
query_plan_hash,
total_rows,
CONVERT(money, total_rows / (execution_count + 0.0)) AS [AvgRows],
total_dop,
CONVERT(money, total_dop / (execution_count + 0.0)) AS [AvgDop],
total_grant_kb,
CONVERT(money, total_grant_kb / (execution_count + 0.0)) AS [AvgGrantKb],
total_used_grant_kb,
CONVERT(money, total_used_grant_kb / (execution_count + 0.0)) AS [AvgUsedGrantKb],
total_ideal_grant_kb,
CONVERT(money, total_ideal_grant_kb / (execution_count + 0.0)) AS [AvgIdealGrantKb],
total_reserved_threads,
CONVERT(money, total_reserved_threads / (execution_count + 0.0)) AS [AvgReservedThreads],
total_used_threads,
CONVERT(money, total_used_threads / (execution_count + 0.0)) AS [AvgUsedThreads],
Explicación de Campos Seleccionados
- creation_time: Tiempo de creación de la consulta.
- last_execution_time: Última vez que se ejecutó la consulta.
- execution_count: Número de veces que se ha ejecutado la consulta.
- total_worker_time / 1000 AS CPU: Tiempo total de CPU utilizado, convertido a segundos.
- AvgCPUTime: Tiempo promedio de CPU por ejecución.
- TotDuration: Duración total de la consulta en milisegundos.
- AvgDur: Duración promedio por ejecución.
- Reads: Lecturas lógicas totales.
- Writes: Escrituras lógicas totales.
- AggIO: I/O agregado (lecturas + escrituras).
- AvgIO: I/O promedio por ejecución.
- sql_handle, plan_handle: Identificadores de la consulta y del plan de ejecución.
- statement_start_offset, statement_end_offset: Posiciones de inicio y fin de la consulta dentro del batch.
- plan_generation_num: Número de veces que se ha generado el plan de ejecución.
- total_physical_reads: Lecturas físicas totales.
- AvgIOPhysicalReads: Lecturas físicas promedio por ejecución.
- AvgIOLogicalReads: Lecturas lógicas promedio por ejecución.
- AvgIOLogicalWrites: Escrituras lógicas promedio por ejecución.
- query_hash, query_plan_hash: Hash de la consulta y del plan de ejecución.
- total_rows: Número total de filas afectadas.
- AvgRows: Número promedio de filas por ejecución.
- total_dop: Grado total de paralelismo.
- AvgDop: Grado promedio de paralelismo.
- total_grant_kb, total_used_grant_kb, total_ideal_grant_kb: Memoria total concedida, usada e ideal en KB.
- AvgGrantKb, AvgUsedGrantKb, AvgIdealGrantKb: Promedio de memoria concedida, usada e ideal en KB por ejecución.
- total_reserved_threads, total_used_threads: Hilos totales reservados y usados.
- AvgReservedThreads, AvgUsedThreads: Hilos promedio reservados y usados por ejecución.
Texto de la Consulta y Plan de Ejecución
CASE
WHEN sql_handle IS NULL THEN ' '
ELSE SUBSTRING(st.text, (qs.statement_start_offset + 2) / 2,
(CASE
WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(nvarchar(MAX), st.text)) * 2
ELSE qs.statement_end_offset
END - qs.statement_start_offset) / 2)
END AS query_text,
DB_NAME(st.dbid) AS database_name,
OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid) AS [object_name],
sp.[query_plan]
- query_text: Extrae el texto de la consulta SQL.
- database_name: Nombre de la base de datos donde se ejecutó la consulta.
- object_name: Nombre del objeto (tabla, vista, etc.) relacionado con la consulta.
- query_plan: Plan de ejecución de la consulta.
Tablas y Funciones del Sistema
CASE
WHEN sql_handle IS NULL THEN ' '
ELSE SUBSTRING(st.text, (qs.statement_start_offset + 2) / 2,
(CASE
WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(nvarchar(MAX), st.text)) * 2
ELSE qs.statement_end_offset
END - qs.statement_start_offset) / 2)
END AS query_text,
DB_NAME(st.dbid) AS database_name,
OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid) AS [object_name],
sp.[query_plan]
- sys.dm_exec_query_stats: Vista de estadísticas de ejecución de consultas.
- sys.dm_exec_sql_text: Función que devuelve el texto completo de la consulta SQL.
- sys.dm_exec_query_plan: Función que devuelve el plan de ejecución de la consulta.
Filtrado y Orden
WHERE st.[text] LIKE '%insert%'
ORDER BY creation_time DESC;
- Filtro: Se filtran las consultas cuyo texto contiene la palabra «insert».
- Orden: Los resultados se ordenan por el tiempo de creación en orden descendente.
Esta consulta es una herramienta útil para analizar el rendimiento y el uso de recursos de las consultas SQL que contienen la palabra «insert» en su texto. Proporciona una visión detallada de cómo se comportan estas consultas en términos de CPU, duración, lecturas/escrituras y otros recursos, ayudando a los administradores de bases de datos a optimizar y solucionar problemas de rendimiento.
Script Creación de Roles en SQL Server
Eliminar usuarios huérfanos SQL server
Eliminar usuarios huérfanos en SQL Server, puedes seguir estos pasos detallados y hacer uso de un script SQL que te ayudará a identificar y eliminar dichos usuarios de una manera ordenada. Aquí te dejo una guía detallada, que también podría ser útil como entrada de blog:
¿Por qué borrar usuarios huérfanos en SQL después de una migración?
Las migraciones de bases de datos son procesos complejos que, a menudo, pueden generar datos residuales no deseados, como usuarios huérfanos. Estos usuarios son cuentas que ya no están asociadas a ningún inicio de sesión válido y pueden suponer diversos riesgos para la seguridad y el rendimiento de la base de datos.
En este artículo, exploraremos las razones principales por las que es crucial eliminar los usuarios huérfanos en SQL después de una migración:
1. Mejorar la seguridad:
Los usuarios huérfanos representan una brecha de seguridad potencial, ya que podrían ser utilizados por actores maliciosos para acceder a la base de datos sin autorización. Al eliminarlos, se elimina este punto de entrada vulnerable y se protege la integridad de los datos.
2. Optimizar el rendimiento:
Las bases de datos con un gran número de usuarios huérfanos pueden experimentar un rendimiento más lento, especialmente durante las consultas que involucran permisos y roles. Eliminar estos usuarios innecesarios libera recursos del sistema y mejora la eficiencia general de la base de datos.
3. Simplificar la administración:
La presencia de usuarios huérfanos dificulta la administración de la base de datos, ya que aumenta la complejidad de tareas como la concesión de permisos y la auditoría de acceso. Eliminar estos usuarios simplifica el entorno y facilita la gestión de la base de datos.
4. Mejorar la calidad de los datos:
Los usuarios huérfanos pueden generar entradas de registro y datos de auditoría incorrectos, lo que dificulta la identificación de patrones y la comprensión del uso real de la base de datos. Eliminar estos usuarios garantiza que los datos de la base de datos sean precisos y confiables.
5. Cumplimiento normativo:
En algunos sectores, las regulaciones de cumplimiento de datos, como GDPR y HIPAA, exigen la eliminación de datos personales no utilizados. Eliminar usuarios huérfanos ayuda a garantizar el cumplimiento de estas regulaciones y protege la privacidad de la información sensible.
Script para borrar usuarios huérfanos y sus esquemas
---------------------------------------------------------------------------------------
-- ELIMINAR usuarios huérfanos y sus eschemas
---------------------------------------------------------------------------------------
-- www.sql-ninja.com
set nocount on
declare @cadena varchar(4000)
declare @usuario sysname
declare @nombre_usuario sysname
declare @principal_id int
declare @usuario2 sysname
---- coge los usuarios huérfanos (que no tiene un login con mismo nombre ni mismo codigo (SID)
select name, principal_id
into #usuarios --- tabla temporal con los usuarios
from sys.database_principals
where type in ('S','U','G')
and (sid is not null and sid <> 0x0)
and name not in (select name from sys.server_principals) -- no existe con mismo nombre
and sid not in (select sid from sys.server_principals) -- no existe con mismo sid
and principal_id > 1
and db_id() > 4
order by name
declare cur_usuarios cursor
for select name,principal_id from #usuarios
order by name
Open cur_usuarios
FETCH NEXT FROM cur_usuarios
INTO @nombre_usuario, @principal_id
WHILE @@FETCH_STATUS = 0
BEGIN
select @usuario= @nombre_usuario
select @usuario2='[' + @nombre_usuario +']'
declare @schema_name sysname , @cant_schemas int
set @schema_name = null
set @cant_schemas = 0
--- verifica la cantidad de schemas que tiene
select @cant_schemas = count(*) from sys.schemas where principal_id = @principal_id
print '********* USUARIO ---> ' + @nombre_usuario
if @cant_schemas > 0
begin
While @cant_schemas > 0
begin
select top(@cant_schemas) @schema_name = '[' + name +']' from sys.schemas where principal_id = @principal_id
print ' --- Se procedera a borrar el SCHEMA: ' + @schema_name
set @cadena=' drop schema ' + @schema_name + ''
print @cadena
exec ( @cadena ) ----- ELIMINA schema
set @cant_schemas = @cant_schemas - 1
end
end
---- select schema_name(s.schema_id),user_name(s.principal_id),*
print ' --- Se procedera a borrar el USUARIO: ' + @usuario
set @cadena=' drop user ' + @usuario2 + ''
print @cadena
exec ( @cadena ) ----- ELIMINA usuario
FETCH NEXT FROM cur_usuarios
INTO @nombre_usuario,@principal_id
END
CLOSE cur_usuarios
DEALLOCATE cur_usuarios
set nocount off
drop table #usuarios
go
Explicación del código para borrar usuarios huerfános en SQL
Este script de SQL está diseñado para eliminar usuarios huérfanos y sus esquemas asociados en una base de datos. Los usuarios huérfanos son aquellos que no tienen un login correspondiente con el mismo nombre o el mismo SID (Security Identifier). Aquí está el desglose del script:
Parte Superior: Comentarios y Configuración Inicial
sqlCopiar código---------------------------------------------------------------------------------------
-- ELIMINAR usuarios huérfanos y sus esquemas --- Usuario que NO EXISTE LOGIN CON MISMO NOMBRE NI CON MISMO SID
---------------------------------------------------------------------------------------
-- www.sql-ninja.com
set nocount on
- Comentarios: Explica el propósito del script.
set nocount on
: Previene que SQL Server devuelva mensajes de cuenta de filas afectadas, lo que hace que el script sea más limpio en términos de salida.
Declaración de Variables
declare @cadena varchar(4000)
declare @usuario sysname
declare @nombre_usuario sysname
declare @principal_id int
declare @usuario2 sysname
- Declaración de variables: Estas variables se utilizarán para almacenar información temporal durante la ejecución del script.
Selección de Usuarios Huérfanos
select name, principal_id
into #usuarios --- tabla temporal con los usuarios
from sys.database_principals
where type in ('S','U','G')
and (sid is not null and sid <> 0x0)
and name not in (select name from sys.server_principals) -- no existe con mismo nombre
and sid not in (select sid from sys.server_principals) -- no existe con mismo sid
and principal_id > 1
and db_id() > 4
order by name
select
: Selecciona los usuarios que no tienen un login correspondiente con el mismo nombre o SID y los almacena en una tabla temporal#usuarios
.
Cursor para Iterar sobre los Usuarios Huérfanos
declare cur_usuarios cursor
for select name,principal_id from #usuarios
order by name
Open cur_usuarios
FETCH NEXT FROM cur_usuarios
INTO @nombre_usuario, @principal_id
- Cursor: Define un cursor
cur_usuarios
para iterar sobre los usuarios huérfanos seleccionados anteriormente.
Bucle para Procesar Cada Usuario Huérfano
WHILE @@FETCH_STATUS = 0
BEGIN
select @usuario= @nombre_usuario
select @usuario2='[' + @nombre_usuario +']'
declare @schema_name sysname , @cant_schemas int
set @schema_name = null
set @cant_schemas = 0
--- verifica la cantidad de schemas que tiene
select @cant_schemas = count(*) from sys.schemas where principal_id = @principal_id
print '********* USUARIO ---> ' + @nombre_usuario
if @cant_schemas > 0
begin
While @cant_schemas > 0
begin
select top(@cant_schemas) @schema_name = '[' + name +']' from sys.schemas where principal_id = @principal_id
print ' --- Se procedera a borrar el SCHEMA: ' + @schema_name
set @cadena=' drop schema ' + @schema_name + ''
print @cadena
exec ( @cadena ) ----- ELIMINA schema
set @cant_schemas = @cant_schemas - 1
end
end
---- select schema_name(s.schema_id),user_name(s.principal_id),*
print ' --- Se procedera a borrar el USUARIO: ' + @usuario
set @cadena=' drop user ' + @usuario2 + ''
print @cadena
exec ( @cadena ) ----- ELIMINA usuario
FETCH NEXT FROM cur_usuarios
INTO @nombre_usuario,@principal_id
END
- Bucle
WHILE
: Itera sobre cada usuario huérfano.- Variables y Preparación: Asigna el nombre del usuario a las variables
@usuario
y@usuario2
(con corchetes para manejar nombres con espacios o caracteres especiales). - Verificación de Esquemas: Cuenta la cantidad de esquemas asociados con el usuario.
- Eliminación de Esquemas: Si hay esquemas asociados, los elimina uno por uno.
- Eliminación de Usuario: Después de eliminar los esquemas, elimina el usuario.
- Variables y Preparación: Asigna el nombre del usuario a las variables
Cierre y Liberación de Recursos
CLOSE cur_usuarios
DEALLOCATE cur_usuarios
set nocount off
drop table #usuarios
go
- Cierre del Cursor: Cierra y libera el cursor.
- Restauración de
nocount
: Vuelve a permitir que SQL Server devuelva mensajes de cuenta de filas. - Eliminación de Tabla Temporal: Elimina la tabla temporal
#usuarios
.
Este script es útil para mantener la base de datos limpia al eliminar usuarios huérfanos y sus esquemas asociados, evitando así posibles problemas de seguridad y administración.
La importancia eliminar usuarios huérfanos en SQL después de una migración.
Más allá de las razones generales mencionadas en la entrada anterior, eliminar usuarios huérfanos en SQL después de una migración reviste especial importancia por las siguientes razones:
1. Complejidad de la migración:
Las migraciones de bases de datos, por su naturaleza compleja, pueden generar un mayor número de usuarios huérfanos debido a diversos factores, como:
- Eliminación incompleta de usuarios: Si la migración no elimina correctamente las cuentas de usuario asociadas a objetos de la base de datos origen, pueden quedar usuarios huérfanos en el destino.
- Cambios en la estructura de la base de datos: Si la estructura de la base de datos destino difiere de la origen, es posible que algunos usuarios ya no tengan permisos para acceder a los objetos relevantes, quedando huérfanos.
- Migración de datos incompleta: Si la migración no transfiere completamente los datos de permisos y roles, puede haber usuarios huérfanos en el destino que no estén asociados a ningún objeto o rol.
2. Mayor impacto en el rendimiento:
En el contexto de una migración, el impacto en el rendimiento causado por usuarios huérfanos puede ser más significativo, ya que:
- La base de datos destino es un nuevo entorno: Es posible que la base de datos destino no esté optimizada para manejar un gran número de usuarios huérfanos, lo que puede amplificar la degradación del rendimiento.
- Los recursos del sistema se encuentran en fase de adaptación: Tras la migración, la base de datos destino se encuentra en un proceso de adaptación a la nueva carga de trabajo. La presencia de usuarios huérfanos puede sobrecargar aún más el sistema durante esta fase crucial.
3. Riesgos de seguridad amplificados:
En el contexto posterior a una migración, los riesgos de seguridad asociados a usuarios huérfanos se intensifican:
- Entorno menos familiar: Los administradores del sistema pueden estar menos familiarizados con la nueva base de datos destino, lo que aumenta la probabilidad de pasar por alto usuarios huérfanos durante las revisiones de seguridad.
- Mayor superficie de ataque: Una migración puede ampliar la superficie de ataque de la base de datos, ya que los actores maliciosos pueden explorar los nuevos usuarios huérfanos como puntos de entrada vulnerables.
4. Mayor dificultad para la resolución de problemas:
La presencia de usuarios huérfanos puede dificultar la resolución de problemas después de una migración:
- Diagnóstico confuso: Los errores o fallos de funcionamiento pueden tener su origen en usuarios huérfanos, lo que dificulta la identificación precisa de la causa raíz del problema.
- Soluciones más complejas: La resolución de problemas relacionados con usuarios huérfanos puede requerir soluciones más complejas y que consumen más tiempo, desviando recursos de otras tareas importantes.
Cambiar el collation en un servidor sql server 2019
Creación de Roles en SQL Server