เรียกกระบวนงานที่เก็บไว้จากทริกเกอร์


17

ฉันได้สร้างกระบวนงานที่เก็บไว้ใน mysql โดยใช้ไวยากรณ์ต่อไปนี้

DROP PROCEDURE IF EXISTS `sp-set_comment_count`;

DELIMITER $$

CREATE PROCEDURE `sp_set-comment_count` (IN _id INT)
BEGIN
   -- AC   - AllCount
   DECLARE AC INT DEFAULT 0;

   SELECT COUNT(*) AS ac
     INTO AC
     FROM usergroups AS ug
LEFT JOIN usergroup_comments AS ugm ON ugm.`gid` = ug.`id`
LEFT JOIN mediagallery AS dm ON ugm.mid = dm.`id`
    WHERE dm.`status` NOT IN (200, 201, 202, 203, 204, 205)
      AND ug.`id` = _id;

   UPDATE usergroups
      SET allCount = AC,
    WHERE usergroups.`id` = _id;

END $$
DELIMITER ;

FYI ฉันทำให้ขั้นตอนการจัดเก็บง่ายขึ้น แต่ฉันรู้ว่ามันใช้งานได้โดยไม่มีปัญหาใด ๆ

สิ่งที่ฉันสามารถทำได้คือตั้งค่าทริกเกอร์จาก usergroup_comments ที่ใช้งานได้เช่นนี้

DROP TRIGGER IF EXISTS `usergroups_comments_insert` 

CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
    FOR EACH ROW
    BEGIN
       CALL sp-set-comment_count(NEW.`gid`);
    END;

แต่ด้วยเหตุผลบางอย่างทุกครั้งที่ฉันทำ mysql จะส่งข้อผิดพลาดมาที่ฉันซึ่งมีประโยชน์น้อยกว่าที่ระบุว่ามีข้อผิดพลาดทางไวยากรณ์ในบรรทัดที่ 4

ฉันได้อ่านเอกสารของ mysql แล้วและพบข้อมูลบางอย่างเกี่ยวกับข้อ จำกัด ของทริกเกอร์ แต่พบว่ามันค่อนข้างซับซ้อน

http://dev.mysql.com/doc/refman/5.1/en/stored-program-restrictions.html

ความคิดใด ๆ ที่จะเป็นประโยชน์


ดังนั้นจึงกลายเป็นปัญหากับขั้นตอนการจัดเก็บข้างต้นที่ถูกเรียกว่าเป็นความจริงที่ว่ามันมียัติภังค์ในชื่อของมัน การเปลี่ยนชื่อกระบวนงานที่เก็บไว้เป็น sp_set_comment_count แก้ไขปัญหาได้
Mark D

คำตอบ:


24

มีเหตุผลที่ดีว่าทำไมคุณไม่ควรเรียกขั้นตอนการจัดเก็บจากภายในทริกเกอร์

ทริกเกอร์คือโดยธรรมชาติแล้วขั้นตอนการจัดเก็บ การกระทำของพวกเขาเป็นจริงยากที่จะย้อนกลับ แม้ว่าตารางพื้นฐานทั้งหมดจะเป็น InnoDB คุณจะได้สัมผัสกับสัดส่วนของการล็อคแถวที่ใช้ร่วมกันและช่วงเวลาที่น่ารำคาญจากการล็อคแถวแบบเอกสิทธิ์ ดังกล่าวจะเป็นกรณีที่หากทริกเกอร์ได้รับการจัดการกับตารางที่มีแทรกและการปรับปรุงถูกหยุดนิ่งในการดำเนินงานหนักMVCCภายในโทรแต่ละครั้งจะเรียก

อย่าลืมว่า Triggers ต้องการค่าใช้จ่าย ในความเป็นจริงตามการเขียนโปรแกรม MySQL กระบวนงานที่เก็บไว้หน้า 256 ใต้หัว "Trigger Overhead" กล่าวว่าต่อไปนี้:

เป็นสิ่งสำคัญที่ต้องจำไว้ว่าสิ่งกระตุ้นให้เพิ่มค่าใช้จ่ายในคำสั่ง DML ที่พวกเขาใช้ จำนวนค่าโสหุ้ยที่แท้จริงจะขึ้นอยู่กับลักษณะของทริกเกอร์ แต่ --- เนื่องจากทริกเกอร์ MySQL ทั้งหมดเรียกใช้สำหรับแต่ละแถว --- ค่าโสหุ้ยสามารถสะสมอย่างรวดเร็วสำหรับข้อความที่ประมวลผลแถวจำนวนมาก คุณควรหลีกเลี่ยงการวางคำสั่ง SQL ราคาแพงหรือรหัสโพรซีเดอร์ในทริกเกอร์

คำอธิบายเพิ่มเติมของค่าใช้จ่ายทริกเกอร์จะได้รับในหน้า 529-531 จุดสรุปจากส่วนนั้นระบุสิ่งต่อไปนี้:

บทเรียนที่นี่คือ: เนื่องจากรหัสทริกเกอร์จะทำงานหนึ่งครั้งสำหรับทุกแถวที่ได้รับผลกระทบจากคำสั่ง DML ทริกเกอร์สามารถกลายเป็นปัจจัยที่สำคัญที่สุดในประสิทธิภาพของ DML ได้อย่างง่ายดาย โค้ดภายในร่างกายของทริกเกอร์จำเป็นต้องมีน้ำหนักเบาที่สุดเท่าที่จะเป็นไปได้และโดยเฉพาะอย่างยิ่งคำสั่ง SQL ใด ๆ ในทริกเกอร์ควรได้รับการสนับสนุนโดยดัชนีเมื่อใดก็ตามที่เป็นไปได้

ฉันอธิบายแง่มุมที่น่ารังเกียจอื่น ๆ ของ Triggers ในโพสต์ก่อนหน้านี้

สรุป

ฉันขอแนะนำอย่างยิ่งว่าอย่าเรียกขั้นตอนการจัดเก็บใด ๆ จาก Triggerแม้ว่า MySQL จะอนุญาตก็ตาม คุณควร wlays ตรวจสอบข้อ จำกัด ในปัจจุบันสำหรับ MySQL 5.5


ที่น่าสนใจขอบคุณสำหรับหัวขึ้น การขาดการค้นหาธุรกรรมในสภาพแวดล้อมของเราช่วยลดปัญหาการทำธุรกรรม อย่างไรก็ตามฉันสามารถชื่นชมความคิดในการสะสมค่าโสหุ้ย ฉันเดาว่าฉันจะดู db สักครู่เพื่อดูว่าผลลัพธ์ของการเปลี่ยนแปลงนี้คืออะไร
Mark D

ฉันไม่คิดว่ามันถูกต้องที่จะทำให้เกิดทริกเกอร์กับขั้นตอนการจัดเก็บ อย่างน้อยก็สามารถเริ่มต้นและกระทำธุรกรรมในขั้นตอนการจัดเก็บ MySQL บ่นถ้าคุณพยายามทำสิ่งเดียวกันในทริกเกอร์ ซึ่งโง่เพราะมีทริกเกอร์ที่จำเป็นต้องปรับปรุงหนึ่งหรือหลายตารางธุรกรรมเพื่อตอบสนองต่อการเปลี่ยนแปลงบางอย่างเป็นกรณีใช้ที่ถูกต้องทั้งหมดซึ่งควรได้รับการสนับสนุนในลักษณะที่ตรงไปตรงมา
aroth

ดังนั้นฉันจึงมีทริกเกอร์นี้ซึ่งใหญ่มาก มันทำการคำนวณหลายอย่างในตารางของฉันทั้งที่แทรกและอัปเดต ทริกเกอร์ใน Mysql สามารถเจ็บปวดได้จริงเมื่อซับซ้อน มันจะง่ายขึ้นมากในการแยกทริกเกอร์ออกเป็นขั้นตอน
ลามาร์

8

ดังนั้นปรากฎว่านี่เป็นปัญหาที่รบกวนฉันไม่กี่ชั่วโมงที่เชื่อหรือไม่

ฉันสามารถกำหนดโพรซีเดอร์ที่เรียกว่า, sp_set-comment_count ได้อย่างง่ายดาย อย่างไรก็ตามเมื่อเรียกขั้นตอนดังกล่าวจะไม่ทำงานในลักษณะเดียวกัน

CALL sp_set-comment_count (ฉันสามารถสันนิษฐานได้ว่านี่เป็นเพราะเซิร์ฟเวอร์ตีความ - เป็นเครื่องหมายลบ)

ฉันเปลี่ยนชื่อโพรซีเดอร์ที่เก็บไว้เป็นใช้ขีดล่างเท่านั้นและดูเหมือนว่าจะแก้ไขทุกอย่างแล้ว


มาสายปาร์ตี้ แต่: คุณได้สร้าง SP ของคุณโดยใช้ตัวระบุที่เสนอราคาซึ่งอนุญาตให้ใช้อักขระพิเศษในชื่อของมันดังนั้นคุณควรอ้างอิงในลักษณะเดียวกันที่อื่น: CALL `sp-set-comment_count`(NEW.`gid`);
mustaccio

5

หากมีข้อความระบุว่าเกี่ยวกับข้อผิดพลาดทางไวยากรณ์มีแนวโน้มมากที่สุดที่คุณลืมเปลี่ยนตัวคั่น ดังนั้นคุณต้องการ

DELIMITER $$
CREATE TRIGGER `usergroups_comments_insert` AFTER INSERT ON `usergroups_comment`
FOR EACH ROW
BEGIN
   CALL sp_set_count(NEW.`gid`);
END;
$$

ขอบคุณจริง ๆ ที่ทำให้ฉันคิดไปตามเส้นทางที่ถูกต้อง อันที่จริง sp ของฉันถูกเรียกว่า sp-set_comment_count เมื่อถูกเรียกโดยทริกเกอร์จะปรากฏว่าปัญหาคือว่าเมื่อเรียก SP จากทริกเกอร์ - การขว้างข้อผิดพลาดไปเรื่อย ๆ
Mark D

1

ดูเหมือนว่าเครื่องหมายจุลภาคหลังจากACเป็นข้อผิดพลาดทางไวยากรณ์:

UPDATE usergroups
   SET allCount = AC,
 WHERE ........

จุดที่ถูกต้อง แต่ไม่ใช่สาเหตุที่แท้จริงของข้อผิดพลาดในกรณีนี้ฉันเพียงแค่ตัดชุดพิเศษบางส่วนออกจากข้อความค้นหานั้นและลืมที่จะลบออก
Mark D
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.