SQL - 防止函数在短时间内执行

Bri*_* SP 3 sql-server functions sql-server-2016

我使用了很多函数来启动和运行网站,该网站中的几乎每个操作都会导致执行 SQL 函数。想象一下,几乎所有的数据处理和网站逻辑都是由数据库和部分网络服务器处理的,疯了吧?不是我的错。

但是这里有一个问题,前端有多个事件处理程序,它们向数据库发送请求并返回请求大量数据,例如单击请求大的JSON字符串,因此用户有可能错误地调用这些SQL通过在短时间内同时单击这些事件来运行,这可能导致数据库连接断开或服务器关闭。

那么,我只需要知道是否可以防止 SQL 函数在短时间内多次执行?或者至少在返回数据之前执行一次?如何?

Han*_*non 6

您可以使用表跟踪给定过程的最后运行时间,从而防止存储过程比每“x”秒更频繁地运行。

创建一个表来存储上次运行时间:

CREATE TABLE dbo.ProcControl
(
    ProcName sysname NOT NULL
        CONSTRAINT PK_ProcControl
        PRIMARY KEY
        CLUSTERED
    , LastExecution datetime NOT NULL
);
INSERT INTO dbo.ProcControl (ProcName, LastExecution)
VALUES (N'dbo.TestProc', '2017-01-01 00:00:00')
GO
Run Code Online (Sandbox Code Playgroud)

创建一个测试存储过程:

CREATE PROCEDURE dbo.TestProc
AS
BEGIN
    SET NOCOUNT ON;
    IF NOT EXISTS (
        SELECT 1 
        FROM dbo.ProcControl pc
        WHERE pc.ProcName = N'dbo.TestProc'
            AND pc.LastExecution >= DATEADD(SECOND, -5, GETDATE())
            )
    BEGIN
        /*
            run the code you want to run at most every 5 seconds.
        */
        SELECT Result = 'This is a result'
            , [Timestamp] = GETDATE();
        UPDATE dbo.ProcControl
        SET LastExecution = GETDATE()
        WHERE ProcName = N'dbo.TestProc';
    END
END
GO
Run Code Online (Sandbox Code Playgroud)

在这里,我们快速连续两次运行 proc;第一次迭代返回有效结果,第二次迭代不返回。然后我们等待 6 秒,再次运行该过程,它又返回一个结果:

DECLARE @returnVal int;
EXEC @returnVal = dbo.TestProc;
PRINT @returnVal;
EXEC @returnVal = dbo.TestProc;
PRINT @returnVal;
WAITFOR DELAY '00:00:06';
EXEC @returnVal = dbo.TestProc;
PRINT @returnVal;
Run Code Online (Sandbox Code Playgroud)

结果:

在此处输入图片说明

清理:

IF OBJECT_ID(N'dbo.ProcControl', N'U') IS NOT NULL
DROP TABLE dbo.ProcControl;
IF OBJECT_ID(N'dbo.TestProc', N'P') IS NOT NULL
DROP PROCEDURE dbo.TestProc;
GO
Run Code Online (Sandbox Code Playgroud)

我会建议这样做吗? 绝对不是

如果您有两个客户同时使用该网站怎么办?第一个客户会得到结果,第二个客户可能不会。此外,dbo.ProcControl不必要地写入表可能会降低性能,并可能成为中心瓶颈。

重新设计您的网站以使用缓存,并且仅在需要数据时才调用数据库。