ปรับแต่ง PostgreSQL สําหรับ pgvector
ปริมาณงานการค้นหาเวกเตอร์มีความต้องการ PostgreSQL ที่แตกต่างกันเมื่อเทียบกับการสืบค้นธุรกรรมหรือการวิเคราะห์แบบดั้งเดิม การทําความเข้าใจความแตกต่างเหล่านี้ช่วยให้คุณปรับแต่งพารามิเตอร์การกําหนดค่าเพื่อปรับเวลาแฝงของคิวรี การใช้หน่วยความจํา และประสิทธิภาพการประมวลผลสําหรับแอปพลิเคชัน AI ให้เหมาะสม
Note
ตัวอย่างโค้ดในหน่วยนี้สาธิตรูปแบบการกําหนดค่าสําหรับ PostgreSQL และ pgvector ค่าพารามิเตอร์ที่แสดงเป็นจุดเริ่มต้นสําหรับการปรับแต่ง การตั้งค่าที่เหมาะสมที่สุดจะขึ้นอยู่กับปริมาณงาน ขนาดชุดข้อมูล และฮาร์ดแวร์เฉพาะของคุณ เปรียบเทียบการเปลี่ยนแปลงในสภาพแวดล้อมการทดสอบเสมอก่อนที่จะนําไปใช้กับการผลิต
ข้อกําหนดด้านการประมวลผลและหน่วยความจําของ Pgvector
การค้นหาความคล้ายคลึงกันของเวกเตอร์เกี่ยวข้องกับการคํานวณระยะทางระหว่างเวกเตอร์แบบสอบถามและเวกเตอร์ที่เก็บไว้หลายล้านรายการ รูปแบบการคํานวณนี้แตกต่างจากการดําเนินการฐานข้อมูลแบบดั้งเดิมที่กรองแถวตามคอลัมน์ที่จัดทําดัชนีหรือรวมตารางบนค่าคีย์
เมื่อคุณดําเนินการสืบค้นความคล้ายคลึงกันของเวกเตอร์ pgvector จะต้องคํานวณระยะห่างระหว่างเวกเตอร์การสืบค้นและเวกเตอร์ผู้สมัคร สําหรับการฝัง 1536 มิติ (ทั่วไปกับโมเดล OpenAI) การคํานวณระยะทางแต่ละครั้งเกี่ยวข้องกับการดําเนินการจุดลอยตัว 1,536 รายการ การค้นหาเวกเตอร์หนึ่งล้านรายการโดยไม่มีดัชนีต้องใช้การดําเนินการทศนิยมมากกว่า 1.5 พันล้านรายการต่อการสืบค้น ฟังก์ชันระยะทางทั้งสามมีต้นทุนการคํานวณที่แตกต่างกันซึ่งส่งผลต่อตัวเลือกของคุณตามลักษณะข้อมูลและข้อกําหนดด้านประสิทธิภาพของคุณ
-
ระยะทาง L2 (ยุคลิด): ใช้ตัว
<->ดําเนินการและคํานวณรากที่สองของผลรวมของผลต่างกําลังสอง นี่เป็นตัวเลือกที่แพงที่สุดในการคํานวณ -
ระยะโคไซน์: ใช้ตัว
<=>ดําเนินการและวัดมุมระหว่างเวกเตอร์ มันทําให้เวกเตอร์เป็นมาตรฐานภายใน เพิ่มการคํานวณ แต่ให้ความคล้ายคลึงกันแบบไม่แปรผันของมาตราส่วน -
ผลิตภัณฑ์ภายใน: ใช้ตัว
<#>ดําเนินการและคํานวณผลิตภัณฑ์ดอท นี่เป็นการดําเนินการที่เร็วที่สุด แต่ต้องใช้เวกเตอร์ที่ทําให้เป็นมาตรฐานล่วงหน้าสําหรับการเปรียบเทียบความคล้ายคลึงกันที่มีความหมาย
สําหรับเครื่องมือแนะนําและการค้นหาเชิงความหมาย ระยะทางโคไซน์มักเป็นที่ต้องการเนื่องจากจะจัดการกับเวกเตอร์ที่มีขนาดต่างกันอย่างสม่ําเสมอ หากการฝังของคุณถูกทําให้เป็นมาตรฐานแล้ว (API การฝังจํานวนมากส่งคืนเวกเตอร์ที่ปรับให้เป็นมาตรฐาน) ผลิตภัณฑ์ภายในจะให้ผลลัพธ์ที่เทียบเท่าโดยมีการคํานวณน้อยลง
คอลัมน์เวกเตอร์ใช้พื้นที่เก็บข้อมูลจํานวนมากเมื่อเทียบกับประเภทข้อมูลแบบเดิม เวกเตอร์ 1536 มิติเดียวที่จัดเก็บเป็น float4 (ความแม่นยําเดียว) ต้องใช้ 6,144 ไบต์ บวกค่าโสหุ้ย ตารางที่มีการฝังผลิตภัณฑ์หนึ่งล้านรายการต้องการประมาณ 6 GB สําหรับคอลัมน์เวกเตอร์เท่านั้น เมื่อ PostgreSQL ประมวลผลการสืบค้นเวกเตอร์ จะโหลดข้อมูลเวกเตอร์ลงในหน่วยความจํา ความสัมพันธ์ระหว่างหน่วยความจําที่มีอยู่และขนาดข้อมูลเวกเตอร์ส่งผลโดยตรงต่อการสืบค้นสามารถดําเนินการได้อย่างมีประสิทธิภาพในหน่วยความจําหรือต้องอ่านซ้ําๆ จากดิสก์
การฝังมิติที่สูงขึ้นให้ความละเอียดเชิงความหมายมากขึ้น แต่เพิ่มทั้งต้นทุนการจัดเก็บและการคํานวณเป็นกําลังสอง เวกเตอร์ 3072 มิติ (ใช้โดยโมเดลการฝังตัวที่ใหม่กว่าบางรุ่น) ต้องใช้งานคํานวณระยะทางสี่เท่าและการจัดเก็บเวกเตอร์ 1536 มิติเป็นสองเท่า พิจารณาข้อกําหนดด้านความแม่นยําของคุณเมื่อเลือกขนาดการฝัง สําหรับแอปพลิเคชันการแนะนําและการค้นหาจํานวนมาก มิติข้อมูล 768 หรือ 1,024 ให้คุณภาพที่เพียงพอและการใช้ทรัพยากรที่ต่ําลงอย่างมีนัยสําคัญ
การกําหนดค่าหน่วยความจําสําหรับปริมาณงานเวกเตอร์
พารามิเตอร์หน่วยความจําของ PostgreSQL ส่งผลต่อประสิทธิภาพการสืบค้นเวกเตอร์อย่างมีนัยสําคัญ การปรับแต่งที่เหมาะสมช่วยให้มั่นใจได้ว่าดัชนีเวกเตอร์และข้อมูลที่เข้าถึงบ่อยจะยังคงอยู่ในหน่วยความจํา ซึ่งช่วยลดการทํางานของดิสก์ที่มีราคาแพง
พารามิเตอร์จะ shared_buffers ควบคุมแคชหน่วยความจําที่ใช้ร่วมกันของ PostgreSQL ซึ่งมีหน้าข้อมูลที่เข้าถึงบ่อยอยู่ สําหรับปริมาณงานเวกเตอร์ แคชนี้ควรมีขนาดใหญ่พอที่จะเก็บดัชนีเวกเตอร์และข้อมูลร้อนของคุณ อัตราส่วนการเข้าชมแคชที่ต่ํากว่า 99% สําหรับปริมาณงานที่มีเวกเตอร์มากบ่งชี้ว่าอาจมี shared_buffers ขนาดเล็กเกินไป บน Azure Database for PostgreSQL พารามิเตอร์นี้จะถูกปรับแต่งโดยอัตโนมัติตามระดับการประมวลผลของคุณ แต่คุณสามารถปรับได้ภายในช่วงที่อนุญาตสําหรับระดับของคุณ สําหรับปริมาณงานการค้นหาเวกเตอร์โดยเฉพาะ ให้ตั้งเป้าให้ shared_buffers มีขนาดใหญ่พอที่จะเก็บดัชนีเวกเตอร์ของคุณบวกกับระยะขอบสําหรับข้อมูลที่แคชไว้อื่นๆ จุดเริ่มต้นคือหน่วยความจําที่พร้อมใช้งาน 25% โดยเพิ่มขึ้นตามการตรวจสอบ แบบสอบถามต่อไปนี้จะช่วยคุณตรวจสอบการตั้งค่าปัจจุบันและประสิทธิภาพของแคช
-- Check current setting
SHOW shared_buffers;
-- View buffer cache hit ratio
SELECT
sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_ratio
FROM pg_statio_user_tables;
work_memพารามิเตอร์ควบคุมหน่วยความจําที่พร้อมใช้งานสําหรับการดําเนินการคิวรีแต่ละรายการ เช่น การเรียงลําดับและการรวมแฮช แบบสอบถามความคล้ายคลึงกันของเวกเตอร์ โดยเฉพาะอย่างยิ่งการรวมการค้นหาเวกเตอร์เข้ากับการกรองและการจัดลําดับ ได้รับประโยชน์จาก work_mem. ค่าเริ่มต้น work_mem (โดยทั่วไปคือ 4 MB) มักจะเล็กเกินไปสําหรับการดําเนินการเวกเตอร์ที่ต้องจัดเรียงผลลัพธ์ตามความคล้ายคลึงกัน คุณสามารถเพิ่มค่านี้สําหรับเซสชันหรือคําค้นหาที่ทําการค้นหาเวกเตอร์ด้วยชุดผลลัพธ์ขนาดใหญ่โดยใช้SET work_mem = '256MB'; โปรดระมัดระวังกับการเพิ่ม work_mem ส่วนกลางเป็น เนื่องจากการตั้งค่าจะใช้ต่อการดําเนินการต่อการเชื่อมต่อ ดังนั้นเซิร์ฟเวอร์ที่จัดการการเชื่อมต่อพร้อมกัน 100 รายการที่มีการสืบค้นที่ซับซ้อนอาจใช้การดําเนินการ 100 × work_mem ×ต่อคิวรีในหน่วยความจํา สําหรับปริมาณงานเวกเตอร์ ให้พิจารณาการตั้งค่า work_mem ที่ระดับเซสชันสําหรับการค้นหาที่เฉพาะเจาะจงแทนที่จะเป็นแบบสากล
พารามิเตอร์จะ effective_cache_size บอกผู้วางแผนการสืบค้นว่ามีหน่วยความจําเท่าใดสําหรับการแคช รวมถึงแคชของไฟล์ทั้ง PostgreSQL shared_buffers และระบบปฏิบัติการ การตั้งค่านี้ไม่ได้จัดสรรหน่วยความจํา แต่จะส่งผลต่อการที่ผู้วางแผนเลือกการสแกนดัชนีมากกว่าการสแกนตามลําดับหรือไม่ ตั้งค่า effective_cache_size เป็นประมาณ 75% ของหน่วยความจําระบบทั้งหมดบนเซิร์ฟเวอร์ฐานข้อมูลเฉพาะ ค่าที่สูงขึ้นจะกระตุ้นให้ผู้วางแผนใช้ดัชนี ซึ่งโดยทั่วไปจะเป็นประโยชน์สําหรับการค้นหาเวกเตอร์ บน Azure Database for PostgreSQL สิ่งนี้จะถูกกําหนดค่าโดยอัตโนมัติตามระดับของคุณ
การตั้งค่าเครื่องมือวางแผนแบบสอบถามสําหรับการค้นหาเวกเตอร์
เครื่องมือวางแผนการสืบค้นของ PostgreSQL จะตัดสินใจเกี่ยวกับวิธีดําเนินการสืบค้นตามการประมาณการต้นทุน พารามิเตอร์หลายตัวส่งผลต่อการประมาณการเหล่านี้ และการปรับแต่งสําหรับที่เก็บข้อมูล SSD ที่ทันสมัยจะช่วยปรับปรุงการวางแผนการสืบค้นเวกเตอร์
พารามิเตอร์จะ random_page_cost ประมาณค่าใช้จ่ายในการอ่านหน้าดิสก์แบบสุ่มที่สัมพันธ์กับหน้าตามลําดับ ค่าเริ่มต้นของ 4.0 สะท้อนถึงลักษณะดิสก์หมุนที่การเข้าถึงแบบสุ่มช้ากว่าการเข้าถึงตามลําดับอย่างมาก Azure Database for PostgreSQL ใช้ที่เก็บข้อมูล SSD ที่การเข้าถึงแบบสุ่มและตามลําดับมีประสิทธิภาพใกล้เคียงกัน การ random_page_cost ลดระดับลงเหลือ 1.1-1.5 จะกระตุ้นให้ผู้วางแผนใช้การสแกนดัชนีได้ง่ายขึ้น ซึ่งเป็นประโยชน์ต่อการค้นหาเวกเตอร์ที่เข้าถึงหน้าข้อมูลที่กระจัดกระจาย คุณสามารถปรับการตั้งค่านี้ได้ด้วยSET random_page_cost = 1.1;
พารามิเตอร์จะ effective_io_concurrency บอก PostgreSQL จํานวนการดําเนินการ I/O ของดิสก์พร้อมกันที่ระบบจัดเก็บข้อมูลสามารถจัดการได้ ค่าที่สูงขึ้นทําให้การสแกนฮีปบิตแมปสามารถดึงข้อมูลหน้าล่วงหน้าได้มากขึ้นพร้อมกัน ที่เก็บข้อมูล SSD จัดการ I/O พร้อมกันได้ดี ดังนั้นควรตั้งค่า effective_io_concurrency เป็น 200 สําหรับอินสแตนซ์ Azure Database for PostgreSQL ที่ใช้ SSD สิ่งนี้ช่วยปรับปรุงประสิทธิภาพสําหรับคิวรีที่รวมความคล้ายคลึงกันของเวกเตอร์เข้ากับการกรองข้อมูลเมตา
ตัวควบคุมพารามิเตอร์ parallel_tuple_cost และ parallel_setup_cost เมื่อ PostgreSQL ใช้การดําเนินการคิวรีแบบขนาน การดําเนินการเวกเตอร์จะได้รับประโยชน์จากความขนาน โดยเฉพาะอย่างยิ่งสําหรับการสแกนตามลําดับบนตารางขนาดใหญ่ ค่าที่ต่ํากว่าสําหรับ parallel_tuple_cost (ค่าเริ่มต้น 0.1) และ parallel_setup_cost (ค่าเริ่มต้น 1000) สนับสนุนการดําเนินการแบบขนาน สําหรับปริมาณงานเวกเตอร์ที่มีตารางขนาดใหญ่ การเปิดใช้งานแบบขนานสามารถลดเวลาคิวรีได้อย่างมากเมื่อไม่ได้ใช้ดัชนี คุณสามารถตรวจสอบการตั้งค่าแบบขนานปัจจุบันของคุณโดยใช้ SHOW parallel_tuple_cost;, SHOW parallel_setup_cost;, และSHOW max_parallel_workers_per_gather;
กําหนดค่าพารามิเตอร์เฉพาะ pgvector
ส่วนขยาย pgvector มีพารามิเตอร์การกําหนดค่าที่ควบคุมการแลกเปลี่ยนความแม่นยําและความเร็วสําหรับการค้นหาตามดัชนี พารามิเตอร์เหล่านี้มีความสําคัญต่อการปรับแต่งประสิทธิภาพการสืบค้นเวกเตอร์
เมื่อใช้ดัชนี ivfflat.probes IVFFlat พารามิเตอร์จะควบคุมจํานวนพาร์ติชันดัชนี (รายการ) ที่ค้นหาสําหรับแต่ละแบบสอบถาม ค่าที่สูงขึ้นจะเพิ่มการเรียกคืน (ค้นหาเพื่อนบ้านที่ใกล้ที่สุดที่แท้จริงมากขึ้น) แต่การสืบค้นช้า การแลกเปลี่ยนนี้เป็นหัวใจสําคัญของการปรับแต่งประสิทธิภาพ IVFFlat คุณกําลังสร้างสมดุลระหว่างความเสี่ยงที่จะพลาดการจับคู่ที่ดีกับค่าใช้จ่ายในการค้นหาพาร์ติชันเพิ่มเติม ค่าเริ่มต้นของ 1 จะค้นหาเฉพาะพาร์ติชันที่มีแนวโน้มมากที่สุดเพียงพาร์ติชันเดียว ซึ่งรวดเร็ว แต่อาจพลาดผลลัพธ์ที่เกี่ยวข้องที่จัดเก็บไว้ในพาร์ติชันที่อยู่ติดกัน สําหรับกลไกการแนะนําที่การขาดการจับคู่ที่ดีทําให้ประสบการณ์ของผู้ใช้ลดลง ให้เริ่มต้นด้วย ivfflat.probes การตั้งค่าเป็น 5-10% ของพารามิเตอร์ของคุณและ lists ปรับตามการเรียกคืนที่วัดได้
-- Configure IVFFlat search depth
SET ivfflat.probes = 10;
-- Execute vector search
SELECT id, name, embedding <=> $1 AS distance
FROM products
ORDER BY embedding <=> $1
LIMIT 10;
สําหรับดัชนี HNSW พารามิเตอร์จะ hnsw.ef_search ควบคุมขนาดของรายชื่อผู้สมัครแบบไดนามิกในระหว่างการค้นหา ค่าที่ใหญ่ขึ้นจะสํารวจกราฟได้มากขึ้น ซึ่งช่วยปรับปรุงการเรียกคืนโดยแลกกับความเร็ว ซึ่งแตกต่างจากพาร์ติชันแบบแยกของ IVFFlat โครงสร้างกราฟของ HNSW หมายความว่าพารามิเตอร์นี้ส่งผลต่อการสํารวจการเชื่อมต่อเพื่อนบ้านอย่างละเอียดถี่ถ้วนก่อนที่จะส่งคืนผลลัพธ์ ค่าเริ่มต้น 40 ให้ความสมดุลที่สมเหตุสมผลสําหรับปริมาณงานจํานวนมาก สําหรับข้อกําหนดที่มีความแม่นยําสูง (เช่น การค้นหาการจับคู่ 10 อันดับแรกที่แท้จริง) ให้เพิ่มเป็น 100-200 สําหรับแอปพลิเคชันที่มีความสําคัญต่อเวลาแฝงที่ยอมรับผลลัพธ์โดยประมาณ ค่าต่ําถึง 20 สามารถใช้งานได้ กําหนดค่า hnsw.ef_search ด้วย SET hnsw.ef_search = 100; ก่อนดําเนินการค้นหาเวกเตอร์ของคุณ ค่าที่เหมาะสมที่สุดขึ้นอยู่กับข้อกําหนดด้านความแม่นยําและงบประมาณเวลาแฝงของคุณ เปรียบเทียบกับคําถามที่เป็นตัวแทนเพื่อค้นหาเครื่องชั่งที่เหมาะสมสําหรับการใช้งานของคุณ
ตรวจสอบและวัดผลการดําเนินงาน
การปรับแต่งโดยไม่ต้องวัดเป็นการคาดเดา ใช้เครื่องมือในตัวของ PostgreSQL และ Azure Monitor เพื่อทําความเข้าใจพฤติกรรมการสืบค้นและตรวจสอบการเปลี่ยนแปลงการกําหนดค่า
คําสั่งนี้ EXPLAIN ANALYZE แสดงให้เห็นว่า PostgreSQL ดําเนินการสืบค้นอย่างไร และให้ข้อมูลเวลาจริง สําหรับแบบสอบถามแบบเวกเตอร์ จะเปิดเผยว่ามีการใช้ดัชนีอยู่หรือไม่และใช้เวลาไปที่ไหน การทําความเข้าใจแผนการดําเนินการจะช่วยให้คุณระบุได้ว่าประสิทธิภาพที่ไม่ดีเกิดจากดัชนีที่ขาดหายไป เรียกใช้ EXPLAIN ANALYZE ก่อนการสืบค้นเวกเตอร์ของคุณเพื่อดูแผนการดําเนินการ มองหาการ สแกนดัชนีโดยใช้ [index_name] (ระบุว่ามีการใช้ดัชนีเวกเตอร์อยู่), Seq Scan (ระบุการสแกนตามลําดับ ซึ่งช้าสําหรับตารางขนาดใหญ่) ค่า เวลาจริง (แสดงตําแหน่งที่ใช้เวลาในการดําเนินการ) และจํานวน แถว (ช่วยระบุว่าการกรองทํางานได้อย่างมีประสิทธิภาพหรือไม่) ถ้าคุณเห็นการสแกนตามลําดับเมื่อคุณคาดว่าจะมีการใช้ดัชนี ให้ตรวจสอบว่าตัวดําเนินการระยะทางของคิวรีตรงกับคลาสตัวดําเนินการของดัชนี (ตัวอย่างเช่น ใช้กับ <=> ดัชนีที่สร้างขึ้นโดยใช้ vector_cosine_ops)
บางครั้ง PostgreSQL เลือกที่จะไม่ใช้ดัชนีที่มีอยู่ สาเหตุทั่วไปสําหรับการค้นหาเวกเตอร์ ได้แก่ การสืบค้นที่ส่งคืนส่วนใหญ่ของตาราง (ค่าโสหุ้ยดัชนีเกินการสแกนตามลําดับ) สถิติที่ล้าสมัยหลังจากการเปลี่ยนแปลงข้อมูลที่สําคัญ หรือตัวดําเนินการระยะทางที่ไม่ตรงกับคลาสตัวดําเนินการของดัชนี เรียกใช้ ANALYZE products; เพื่ออัปเดตสถิติเพื่อการวางแผนที่แม่นยํา คุณสามารถตรวจสอบข้อมูลดัชนีได้ด้วยSELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'products';
Azure Database for PostgreSQL แสดงเมตริกผ่าน Azure Monitor ที่ช่วยระบุปัญหาคอขวดด้านประสิทธิภาพ ตรวจสอบ เปอร์เซ็นต์ CPU (CPU ที่ต่อเนื่องสูงบ่งชี้ถึงการดําเนินการเวกเตอร์ที่ผูกไว้กับการประมวลผล) เปอร์เซ็นต์หน่วยความจํา (ขีดจํากัดที่ใกล้จะถึงหมายถึงการเพิ่มระดับการประมวลผลหรือการเพิ่มประสิทธิภาพการสืบค้น) เปอร์เซ็นต์ IO ของพื้นที่จัดเก็บ (ค่าที่สูงบ่งชี้ว่าข้อมูลไม่พอดีกับแคช) และ การเชื่อมต่อที่ใช้งานอยู่ (ขีดจํากัดที่ใกล้เข้ามาบ่งชี้ว่าการรวมการเชื่อมต่ออาจช่วยได้) ตั้งค่าการแจ้งเตือนสําหรับเมตริกเหล่านี้เพื่อตรวจจับการลดลงของประสิทธิภาพก่อนที่จะส่งผลกระทบต่อผู้ใช้
แนวทางปฏิบัติที่ดีที่สุดสําหรับการปรับแต่ง pgvector
การปรับแต่งที่มีประสิทธิภาพเป็นไปตามแนวทางที่เป็นระบบมากกว่าการเปลี่ยนแปลงพารามิเตอร์แบบสุ่ม
- สร้างพื้นฐานก่อน: วัดเวลาแฝงของคิวรีและการใช้ทรัพยากรก่อนทําการเปลี่ยนแปลง หากไม่มีพื้นฐาน คุณจะไม่สามารถระบุได้ว่าการเปลี่ยนแปลงช่วยหรือทําร้าย
- เปลี่ยนพารามิเตอร์ทีละตัว: การเปลี่ยนแปลงพร้อมกันหลายครั้งทําให้ไม่สามารถระบุแหล่งที่มาของการปรับปรุงหรือการถดถอยกับการตั้งค่าเฉพาะได้
- ทดสอบด้วยข้อมูลที่คล้ายกับการผลิต: ประสิทธิภาพของคิวรีจะแตกต่างกันอย่างมากตามขนาดและการกระจายข้อมูล การปรับแต่งชุดข้อมูลการทดสอบขนาดเล็กมักจะสร้างการตั้งค่าที่ล้มเหลวในวงกว้าง
- ตรวจสอบการถดถอย: พารามิเตอร์ที่ปรับปรุงการค้นหาเวกเตอร์อาจส่งผลเสียต่อปริมาณงานอื่นๆ ตรวจสอบความสมบูรณ์ของระบบโดยรวมหลังการเปลี่ยนแปลง
- จัดทําเอกสารการตั้งค่าของคุณ: บันทึกสิ่งที่คุณเปลี่ยนแปลง ทําไม และมีผลอย่างไร เอกสารนี้มีค่ามากในการแก้ไขปัญหาในอนาคต