与相同代码的存储功能相比,为什么存储过程需要更多的时间执行?

时间:2019-05-30 06:34:26

标签: mysql stored-procedures stored-functions

我使用OUT参数创建了存储过程,以基于其他表的值来处理自动化INSERT操作。我还对同一操作做了存储功能。我面临的是两者的执行时间有很大不同的问题,这让我感到担忧,我不知道为什么会这样。

以下汇总表值:

    emp_personal中的
  • 2016行

我正在使用MariaDB 10.3.14。我正在测试HeidiSQL 10.1.0.5577。 我还尝试使用MariaDB Node.js ConnectorNode.JS调用它。但是在两种情况下,我几乎都得到了相同的结果。

这是存储过程

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_auto_attendance`(
    OUT `result` INT
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN 
DECLARE empId,done,isHoliday,isEmpHoliday,isWeekOff,isApprovedLeave,insertedRows INT DEFAULT 0;
DECLARE attendance VARCHAR(20) DEFAULT 'Present';
DECLARE empIds VARCHAR(500) DEFAULT '';

-- declare cursor with all employee Ids who are active
DECLARE empIds_cursor CURSOR FOR
SELECT id from emp_personal where isActive=1;

-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

-- Check if today is holiday
SELECT COUNT(id) INTO isHoliday
FROM apexa_portal.public_holiday_dates
WHERE dateOfHoliday= CURDATE(); 

OPEN empIds_cursor;
    get_id: LOOP
        SET attendance = 'Present';
        FETCH empIds_cursor INTO empId;

            -- Following check if NOT FOUND handler has called, if yes exit loop else continue. NOTE: If you don't write this, it will be infinite loop.
            IF done = 1 THEN 
                LEAVE get_id;
            END IF;

            -- Check if public holiday for employee
            IF isHoliday > 0 THEN
                SELECT COUNT(phtd.isActive) INTO isEmpHoliday FROM public_holiday_template_days as phtd 
                LEFT JOIN emp_office_details as eod ON eod.publicHolidayTemplate=phtd.templateId 
                LEFT JOIN public_holiday_dates as phd ON phd.pub_holiday_id=phtd.holidayId
                WHERE eod.empID=empId AND phd.dateOfHoliday=CURDATE() AND phtd.isActive=1;
                IF isEmpHoliday > 0 THEN
                    SET attendance = 'Public Holiday';
                END IF;
            END IF;

            -- if not public holiday, Check if week off
            IF attendance <> 'Public Holiday' THEN
                SELECT COUNT(eowd.id) INTO isWeekOff FROM emp_office_working_days as eowd
                WHERE DAY=DAYOFWEEK(CURDATE()) AND eowd.empId=empId AND eowd.isActive=0; 
                IF isWeekOff > 0 THEN
                    SET attendance = 'Week Off';
                END IF;
            END IF;

            -- if not week off, Check if approved leave
            IF attendance <> 'Week Off' THEN
                SELECT COUNT(la.id) INTO isApprovedLeave FROM leave_application as la
                WHERE la.fromDate <= CURDATE() AND la.toDate >= CURDATE() AND la.empID=empId AND la.leaveStatus='Approved';
                IF isApprovedLeave > 0 THEN
                    SET attendance = 'Approved Leave';
                END IF;
            END IF;

            -- insert attendance
            INSERT INTO attendance_master(empID,dateOfAttendance,attendance) VALUES(empId,CURDATE(),attendance);
            SET insertedRows = insertedRows + 1;
    END LOOP get_id;
CLOSE empIds_cursor;
SET result = insertedRows;
END

这是存储的功能

CREATE DEFINER=`root`@`localhost` FUNCTION `test_auto_att_func`()
RETURNS int(11)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN 
DECLARE empId,done,isHoliday,isEmpHoliday,isWeekOff,isApprovedLeave,insertedRows INT DEFAULT 0;
DECLARE attendance VARCHAR(20) DEFAULT 'Present';
DECLARE empIds VARCHAR(500) DEFAULT '';

-- declare cursor with all employee Ids who are active
DECLARE empIds_cursor CURSOR FOR
SELECT id from emp_personal where isActive=1;

-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

-- Check if today is holiday
SELECT COUNT(id) INTO isHoliday
FROM apexa_portal.public_holiday_dates
WHERE dateOfHoliday= CURDATE(); 

OPEN empIds_cursor;
    get_id: LOOP
        SET attendance = 'Present';
        FETCH empIds_cursor INTO empId;

            -- Following check if NOT FOUND handler has called, if yes exit loop else continue. NOTE: If you don't write this, it will be infinite loop.
            IF done = 1 THEN 
                LEAVE get_id;
            END IF;

            -- Check if public holiday for employee
            IF isHoliday > 0 THEN
                SELECT COUNT(phtd.isActive) INTO isEmpHoliday FROM public_holiday_template_days as phtd 
                LEFT JOIN emp_office_details as eod ON eod.publicHolidayTemplate=phtd.templateId 
                LEFT JOIN public_holiday_dates as phd ON phd.pub_holiday_id=phtd.holidayId
                WHERE eod.empID=empId AND phd.dateOfHoliday=CURDATE() AND phtd.isActive=1;
                IF isEmpHoliday > 0 THEN
                    SET attendance = 'Public Holiday';
                END IF;
            END IF;

            -- if not public holiday, Check if week off
            IF attendance <> 'Public Holiday' THEN
                SELECT COUNT(eowd.id) INTO isWeekOff FROM emp_office_working_days as eowd
                WHERE DAY=DAYOFWEEK(CURDATE()) AND eowd.empId=empId AND eowd.isActive=0; 
                IF isWeekOff > 0 THEN
                    SET attendance = 'Week Off';
                END IF;
            END IF;

            -- if not week off, Check if approved leave
            IF attendance <> 'Week Off' THEN
                SELECT COUNT(la.id) INTO isApprovedLeave FROM leave_application as la
                WHERE la.fromDate <= CURDATE() AND la.toDate >= CURDATE() AND la.empID=empId AND la.leaveStatus='Approved';
                IF isApprovedLeave > 0 THEN
                    SET attendance = 'Approved Leave';
                END IF;
            END IF;

            -- insert attendance
            INSERT INTO attendance_master(empID,dateOfAttendance,attendance) VALUES(empId,CURDATE(),attendance);
            SET insertedRows = insertedRows + 1;
    END LOOP get_id;
CLOSE empIds_cursor;
RETURN insertedRows;

END

执行存储功能的时间

SELECT `test_auto_att_func`();
/* Affected rows: 0  Found rows: 1  Warnings: 0  Duration for 1 query: 0.328 sec. */

执行存储过程的时间

CALL `sp_auto_attendance`(@res);
SELECT @res;
/* Affected rows: 6,049  Found rows: 1  Warnings: 0  Duration for 2 queries: 00:01:21.6 */

Stored Function OutputStored Procedure Output

任何人都可以解释为什么会这样吗?如果我做错了什么,请告诉我该如何纠正?

谢谢。

1 个答案:

答案 0 :(得分:0)

当您将代码作为过程或函数运行时,类似代码的性能应该没有差异。

最可能的解释(请参阅“受影响的行”)是在函数运行时,光标没有找到任何活动的人,而在过程运行时,它找到了任何活动的人,因此运行了循环查询。