สำหรับคนที่ดูแลฐานข้อมูล WordPress มาอย่างยาวนาน ปัญหาเรื่อง ID Gap หรือตัวเลข ID ในตาราง wp_posts กระโดดข้าม เป็นเรื่องที่พบได้บ่อยมาก ไม่ว่าจะเกิดจากการลบโพสต์ทิ้ง, การสร้าง auto-draft ซ้ำซ้อน, หรือการทดสอบระบบจนค่า AUTO_INCREMENT พุ่งนำหน้า ID จริงไปไกล
บทความนี้จะพามาดูเทคนิคการใช้ Common Table Expressions (CTE) แบบ Recursive เพื่อสร้างตัวเลขรันตั้งแต่ 1 จนถึงค่าก่อน Auto Increment และดึงเฉพาะช่องว่างที่ยังไม่มีข้อมูลมาทำ Placeholder Draft รวดเดียวเกือบ 12,000 แถว ในเวลาไม่ถึงครึ่งวินาที
ทำไมต้องเติม Gap ให้เต็ม?
- จองสิทธิ์ ID ไว้ใช้งาน: บางระบบต้องการแมป URL แบบสั้น (เช่น
/?p=123) ให้มีสถานะเป็น Draft ล่วงหน้า เพื่อป้องกันไม่ให้ระบบไปหยิบ ID ตัวเลขสวย ๆ ไปใช้กับ revision หรือ attachment อื่น - ความต่อเนื่องของข้อมูล: ลดความกระจัดกระจายของลำดับ ID ก่อนที่จะเริ่มรันข้อมูลชุดใหม่
- ความเร็วระดับ Native SQL: การรันผ่าน PHP loop ทั่วไปเพื่อสร้าง 10,000+ โพสต์อาจใช้เวลานานและติด timeout แต่การใช้ CTE สามารถจบงานได้ในระดับ millisecond
โครงสร้างคำสั่ง SQL
หลักการทำงานคือการให้ CTE วนลูปสร้างตัวเลข n เริ่มต้นที่ 1 ไปจนถึง AUTO_INCREMENT - 1 จากนั้นใช้ LEFT JOIN ตรวจหาแถวที่ ID IS NULL เพื่อแทรกเฉพาะ ID ที่ยังว่างอยู่เท่านั้น
-- ขยายขีดจำกัดการวนซ้ำสำหรับ MariaDB
-- SET SESSION cte_max_recursion_depth = 100000; -- สำหรับ MySQL 8.0+
SET SESSION max_recursive_iterations = 100000; -- สำหรับ MariaDB 10.2+
INSERT INTO `wp700_posts` (
`ID`,
`post_author`,
`post_date`,
`post_date_gmt`,
`post_content`,
`post_title`,
`post_excerpt`,
`post_status`,
`comment_status`,
`ping_status`,
`post_password`,
`post_name`,
`to_ping`,
`pinged`,
`post_modified`,
`post_modified_gmt`,
`post_content_filtered`,
`post_parent`,
`guid`,
`menu_order`,
`post_type`,
`post_mime_type`,
`comment_count`
)
WITH RECURSIVE id_sequence (n, max_id) AS (
SELECT
1 AS n,
(
SELECT `AUTO_INCREMENT` - 1
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'wp700_posts'
) AS max_id
UNION ALL
SELECT
n + 1,
max_id
FROM id_sequence
WHERE n < max_id
)
SELECT
s.n,
1,
'1982-08-05 00:00:00',
'1982-08-05 00:00:00',
'',
CAST(s.n AS CHAR),vj
'',
'draft',
'closed',
'closed',
'',
CAST(s.n AS CHAR),
'',
'',
'1982-08-05 00:00:00',
'1982-08-05 00:00:00',
'',
0,
CONCAT('https://pitt.plusmagi.com/?p=', s.n),
0,
'post',
'',
0
FROM id_sequence AS s
LEFT JOIN `wp700_posts` AS t ON s.n = t.ID
WHERE t.ID IS NULL;
ผลลัพธ์และประสิทธิภาพ
จากการทดสอบใช้งานจริงบนฐานข้อมูล MariaDB คำสั่งสามารถประมวลผลและแทรกแถวข้อมูลได้รวดเร็วอย่างไม่น่าเชื่อ
11,917 rows inserted. (Query took 0.4613 seconds.)
การแทรกข้อมูลเกือบ 12,000 แถว ใช้เวลาไปเพียง 0.46 วินาที เท่านั้น โดยได้ผลลัพธ์เป็น Post Placeholder ที่มีสถานะ draft พร้อมใช้งาน โดยไม่รบกวนข้อมูลโพสต์เดิมที่มีอยู่ และยังคงรักษาเลข ID ตามลำดับที่ถูกต้องสมบูรณ์
อ่านเพิ่มเติม