Way*_*rad 3 sql-server sql-server-2017
我们有一个邪恶的查询,它从表中读取每一行,但不应该。为了帮助开发人员找到该查询的来源,当针对该表的任何选择没有 where 子句时,我想使 SQL Server 出错。
一个应用程序正在做一个无处可去的邪恶选择。选择读取大约有 6,500 行的表的每一行。选择在 SSMS 中很快(< 1 秒),但是当由应用程序运行时它很慢(大约 1/2 小时)。我们认为这是因为应用程序正在慢慢地迭代结果集。它是一个用于更新和插入的活动表,因此在进行此读取时可能会阻止其他查询。
开发人员没有理由认为任何应用程序都应该读取该表的每一行。他们怀疑是过去开发人员的疏忽。
到目前为止,邪恶的 query-with-no-where 是我的领跑者,因为它在 Query Store 中的总持续时间最长。
通过使用 SQL Profiler 识别应用程序名称、主机名和数据库用户名,我知道哪个应用程序正在发出恶意查询。该应用程序的开发人员无法找到恶意查询的来源。我想帮忙。
该应用程序使用 C# 并使用 LINQ。邪恶的查询每次都完全相同,具有相同顺序的相同列。可以使用简单的相等来确定发出的查询是否是邪恶的查询。查询以自己的批次发出,没有任何其他查询。
我想让任何针对没有 WHERE 子句(即选择每一行)的表的选择立即失败。我们希望应用程序会记录错误,或者触发 Activity 的最终用户可能会向我们报告 500 错误,这将为我们提供另一个线索来找到发出邪恶查询的代码.
我们针对该表的其他选择具有特定的 where 子句,并且只返回表行的子集。必须允许这些选择继续。
SELECT
[a].[Id],
[a].[AccountingIntegrationActionTypeId],
[a].[CreateDate],
[a].[CreatedBy],
[a].[FranchiseId],
[a].[Message],
[a].[ModelObject],
[a].[ProcessId],
[a].[RequestedBy],
[a].[RequestedFor],
[a].[Resolved],
[a].[UpdateBy],
[a].[UpdateDate]
FROM
[AccountingIntegrationQueue] AS [a]
Run Code Online (Sandbox Code Playgroud)
鉴于邪恶的查询是长时间运行的,您不必担心与其执行同步捕获它。如果该方法相对轻巧且易于移除,那就太好了。
我会选择代理工作,按可能与邪恶查询重叠的时间表执行。鉴于邪恶的查询运行三十分钟左右,每隔几分钟就足够了。
此作业通过查询sys.dm_exec_requests 来检查所有当前运行的工作。如果 start_time 超过几分钟前,您可能是罪魁祸首。找到每件作品的实际 SQL 文本。
declare @query nvarchar(max);
declare @victim smallint;
select
@query = s.text,
@victim = r.session_id
from sys.dm_exec_requests as r
cross apply sys.dm_exec_sql_text(r.sql_handle) as s;
Run Code Online (Sandbox Code Playgroud)
一些 SUBSTRING()、CHARINDEX() 和 LIKE 将确认您正在处理没有“WHERE”的“SELECT”。如果恶意查询与其他查询一起提交,则在解析 SQL 文本时必须更加小心。
然后可以用KILL(@victim)结束。存在这样的风险,即在被识别和杀死之间,恶意查询完成并且其会话 ID 被重新分配给“好”查询。如果 evil 的执行时间一直很长,您可以使用 start_time 来降低这种风险。你知道你的环境和什么是可以接受的。