Menu

Thursday, August 29, 2019

[Laravel - Exception] ระวังข้อผิดพลาด "Prepared statement contains too many placeholders" หากมีการ Bulk Insert ข้อมูลจำนวนมาก
[Laravel - Exception] Warning: "Prepared statement contains too many placeholders" Exception if Bulk Insert Large Data

การทำ bulk insert หรือการ insert ข้อมูลทีละเยอะๆ สามารถช่วยลดจำนวนการยิง query หลายๆรอบได้ ซึ่งส่งผลให้เวลาในการทำงานลดลงอย่างเห็นได้ชัด โดยเฉพาะอย่างยิ่ง เมื่อ Database อยู่คนละเครื่อง Server

แต่... อย่าเพิ่งคิดนะครับว่า เราจะยิงข้อมูลเป็นก้อนใหญ่ๆไปเลยทีเดียวได้

เพราะว่ามันก็มี limit ในเรื่องของ placeholder อยู่เหมือนกัน ซึ่งถ้าหากเราส่งข้อมูลก้อนใหญ่เกินไปก็จะได้ error นี้กลับมา
PDOException: SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders in /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:77
แล้ว placeholder มาจากไหน?


สำหรับ Laravel แล้ว เวลาเราสั่ง Model::insert($data); แทนที่ข้อมูลทั้งหมดใน $data จะถูกแปลงเป็น Query String เพียงประโยคเดียว

แต่ในความเป็นจริงแล้ว Query ฺBuilder จะสร้าง Query String ขึ้นมาตัวนึง โดยแทนที่ข้อมูลในส่วนของ VALUES ทั้งหมดด้วย ? หรือ placeholder นั่นเอง (จำนวนของ placeholder จึงเท่ากับจำนวนข้อมูลทั้งหมดใน $data) ซึ่ง placeholder นี้จะถูกแทนค่าด้วยข้อมูลใน $data เมื่อทำการ query จริงๆเท่านั้น

ถ้าเจอ error ข้างต้น วิธีแก้ไขที่ง่ายที่สุด คือ การแบ่งข้อมูลออกเป็นก้อนๆ เพื่อให้มีขนาดที่เล็กลง แล้วใช้การ insert หลายครั้งแทน

นอกจากการ insert แล้ว placeholder นี้ยังถูกใช้สำหรับการ select และ update อีกด้วย

กรณีที่เรามี Query Builder และต้องการแสดง Query String ที่แทนค่า placeholder ด้วย $data เรียบร้อยแล้ว สามารถเข้าไปอ่านวิธีการได้ที่ การแปลง Query Builder ไปเป็น SQL Query String

ข้อมูลเพิ่มเติม สามารถอ่านได้ที่ https://stackoverflow.com/questions/18100782/import-of-50k-records-in-mysql-gives-general-error-1390-prepared-statement-con

No comments:

Post a Comment