提高SQL开发人员嵌套循环中存储过程的性能
我有一个计划,为员工分配一辆首选车辆,最后我确保没有员工拥有相同的车辆 第一个循环获取所有首选车辆的列表,这些车辆多次出现,嵌套循环遍历拥有该车辆的每个员工。最终,只有一名员工将其设置为其首选车辆提高SQL开发人员嵌套循环中存储过程的性能,sql,oracle,performance,Sql,Oracle,Performance,我有一个计划,为员工分配一辆首选车辆,最后我确保没有员工拥有相同的车辆 第一个循环获取所有首选车辆的列表,这些车辆多次出现,嵌套循环遍历拥有该车辆的每个员工。最终,只有一名员工将其设置为其首选车辆 --Loop through to see if a pref_veh occurs more than once FOR every_duplicate_veh IN (SELECT PREFERRED_VEH FROM FLEET_USER GROUP BY PREFERRED_VEH HAV
--Loop through to see if a pref_veh occurs more than once
FOR every_duplicate_veh IN
(SELECT PREFERRED_VEH FROM FLEET_USER GROUP BY PREFERRED_VEH HAVING COUNT (PREFERRED_VEH) > 1)
LOOP
max_count:=0;
--Loop through all the employees with the duplicate vehicle
FOR every_employee IN (SELECT EMPLOYEE_ID FROM FLEET_USER WHERE PREFERRED_VEH=every_duplicate_veh.PREFERRED_VEH)
LOOP
--Find which employee is assigned the vehicle the most
SELECT COUNT(ASSIGN_VEH_ID) INTO assigned_veh_count FROM FLEET_TRANSACTION
WHERE ASSIGN_VEH_ID=every_duplicate_veh.PREFERRED_VEH AND DRIVER_EMP_ID=every_employee.EMPLOYEE_ID
AND SYSDATE - 30 <= RESERV_START_DT;
IF assigned_veh_count>max_count THEN
max_count:=assigned_veh_count;
preferred_employee_id:=every_employee.EMPLOYEE_ID;
END IF;
--Reset the employee's preferred vehicle to NULL
UPDATE FLEET_USER SET PREFERRED_VEH = NULL WHERE EMPLOYEE_ID = every_employee.EMPLOYEE_ID;
INSERT INTO FLEET_PREF_VEH_LOG VALUES (SYSDATE, every_employee.EMPLOYEE_ID, NULL);
END LOOP;
--One employee will get the preferred vehicle
UPDATE FLEET_USER SET PREFERRED_VEH = every_duplicate_veh.PREFERRED_VEH WHERE EMPLOYEE_ID = preferred_employee_id;
INSERT INTO FLEET_PREF_VEH_LOG VALUES (SYSDATE, preferred_employee_id, every_duplicate_veh.PREFERRED_VEH);
COMMIT;
END LOOP;
FLEET_USER是一个包含数千行的表…我的目标是消除嵌套循环。。。我可以这样做吗?我对sql还是相当陌生,因此我非常感谢您提供任何建议/指出我遗漏的任何内容首先,插入到FLEET\u PREF\u VEH\u日志中让我觉得它更适合作为触发器,而不是过程的一部分。通过这种方式卸载,我认为您可以将其简化为一条SQL语句 我没有您的对象或数据,因此这是完全未经测试的,但我认为它与您现有的代码非常接近,应该会导致性能的提高
MERGE INTO fleet_user fu_m
USING (SELECT employee_id,
cnt,
MAX (cnt) OVER (PARTITION BY fm_s.preferred_veh)
AS max_cnt
FROM (SELECT fu.employee_id, fu.preferred_veh, COUNT (*) AS cnt
FROM fleet_user fu
JOIN fleet_transaction ft
ON ft.assign_veh_id = fu.preferred_veh
AND ft.driver_emp_id = fu.employee_id
WHERE EXISTS
(SELECT preferred_veh
FROM fleet_user fu2
WHERE fu2.preferred_veh =
fu.preferred_veh
GROUP BY preferred_veh
HAVING COUNT (preferred_veh) > 1)
AND SYSDATE - 30 <= ft.reserv_start_dt
GROUP BY fu.employee_id, fu.preferred_veh)) fm_s
ON (fm_m.employee_id = fm_s.employee_id)
WHEN MATCHED THEN
UPDATE SET preferred_veh = NULL
WHERE max_cnt <> cnt;
按cnt order BY employee_id分区上的ROW_编号将为每个计数相同的员工提供一个序列号,从最低的员工id到最高的员工id。当并没有关联时,所有的值都将是1,所以查询将和以前一样工作。但是,当存在平局时,平局的每个成员(员工id最低的成员除外)都将设置为null
显然,您可以根据您选择的任意条件更改顺序
我已经改变了上述两个问题,以满足我认为在评论中提出的最新问题。通过仅按车辆编号获取最大计数,我们可以确保单独处理每辆车。是否最好先正确设置值,而不重复,而不是稍后尝试清理?我认为,在这个部分中,您可以同时多次更新同一行,作为旁白;您将所有匹配的行都清空,然后将其中一行恢复到最初的状态。看起来您希望将首选车辆设置为过去30天内使用次数最多的车辆,如果您是该车辆的第二大用户,您最终没有首选车辆,对吗?可能希望查看此网站:。你可能会有更好的运气。这很好,但是如果两个或两个以上的员工之间有关系,这就不适合这种情况。如果有多个重复的车辆怎么办?例如,如果员工A和B拥有车辆ABC,ABC的最大计数为18,但员工C和D拥有车辆DEF,此车辆的最大计数为15。。。此代码仅显示最大计数为18。现在C和D都没有DEF了,因为15=18.明白了-不是一分一,而是一分一。这给了我正确的数字。18用于车辆ABC,15用于车辆DEF。
MERGE INTO fleet_user fu_m
USING (SELECT employee_id,
cnt,
MAX (cnt) OVER (PARTITION BY fm_s.preferred_veh)
AS max_cnt,
ROW_NUMBER () OVER (PARTITION BY cnt ORDER BY employee_id)
AS tie_order
FROM (SELECT fu.employee_id, fu.preferred_veh, COUNT (*) AS cnt
FROM fleet_user fu
JOIN fleet_transaction ft
ON ft.assign_veh_id = fu.preferred_veh
AND ft.driver_emp_id = fu.employee_id
WHERE EXISTS
(SELECT preferred_veh
FROM fleet_user fu2
WHERE fu2.preferred_veh =
fu.preferred_veh
GROUP BY preferred_veh
HAVING COUNT (preferred_veh) > 1)
AND SYSDATE - 30 <= ft.reserv_start_dt
GROUP BY fu.employee_id, fu.preferred_veh)) fm_s
ON (fm_m.employee_id = fm_s.employee_id)
WHEN MATCHED THEN
UPDATE SET preferred_veh = NULL
WHERE max_cnt <> cnt or tie_order <> 1;