การจัดเก็บภาพใน PostgreSQL


111

เอาล่ะฉันกำลังทำงานกับแอปพลิเคชันซึ่งจะใช้ PostgreSQL แบ็คเอนด์ที่รัน Linux เพื่อให้บริการรูปภาพไปยังกล่อง Windows โดยส่วนหน้าเขียนด้วย C # .NET แม้ว่าส่วนหน้าจะไม่สำคัญ คำถามของฉันคือ:

  • วิธีที่ดีที่สุดในการจัดการกับการจัดเก็บภาพใน Postgres คืออะไร?

ภาพมีขนาดประมาณ 4-6 ล้านพิกเซลแต่ละภาพและเราจัดเก็บได้มากกว่า 3000 ภาพนอกจากนี้ยังควรทราบด้วยว่านี่ไม่ใช่เว็บแอปพลิเคชันโดยส่วนใหญ่จะมีส่วนหน้าประมาณสองส่วนในการเข้าถึงฐานข้อมูลพร้อมกัน

คำตอบ:


64

อัปเดตเป็นปี 2012 เมื่อเราเห็นว่าขนาดภาพและจำนวนภาพกำลังเติบโตขึ้นเรื่อย ๆ ในทุกแอปพลิเคชัน ...

เราต้องการความแตกต่างระหว่าง "ภาพต้นฉบับ" และ "ภาพที่ผ่านการประมวลผล" เช่นภาพขนาดย่อ

ดังที่คำตอบของ Jcoby กล่าวว่ามีสองทางเลือกดังนั้นฉันขอแนะนำ:

  • ใช้blob (Binary Large OBject): สำหรับที่เก็บภาพต้นฉบับที่โต๊ะของคุณ ดูคำตอบของ Ivan (ไม่มีปัญหาในการสำรองข้อมูล blobs!), โมดูลที่ให้มาเพิ่มเติมของ PostgreSQL , How-tosเป็นต้น

  • ใช้ฐานข้อมูลแยกกับDBlink : สำหรับที่เก็บอิมเมจดั้งเดิมที่ฐานข้อมูลอื่น (แบบรวม / เฉพาะทาง) ในกรณีนี้ฉันชอบbyteaแต่blob ใกล้เคียงกัน การแยกฐานข้อมูลเป็นวิธีที่ดีที่สุดสำหรับ "บริการเว็บรูปภาพแบบรวม"

  • ใช้bytea (BYTE Array): สำหรับการแคชภาพขนาดย่อ แคชรูปภาพเล็ก ๆ น้อย ๆ เพื่อส่งไปยังเว็บเบราว์เซอร์อย่างรวดเร็ว (เพื่อหลีกเลี่ยงปัญหาการแสดงผล) และลดการประมวลผลของเซิร์ฟเวอร์ แคชยังเป็นข้อมูลเมตาที่สำคัญเช่นความกว้างและความสูง การแคชฐานข้อมูลเป็นวิธีที่ง่ายที่สุด แต่ให้ตรวจสอบความต้องการและการกำหนดค่าเซิร์ฟเวอร์ (เช่นโมดูล Apache): การจัดเก็บภาพขนาดย่อที่ระบบไฟล์อาจดีกว่าเปรียบเทียบประสิทธิภาพ โปรดจำไว้ว่าเป็นบริการบนเว็บ (แบบรวม) จากนั้นสามารถจัดเก็บไว้ที่ฐานข้อมูลแยกต่างหาก (โดยไม่มีการสำรองข้อมูล) โดยให้บริการหลายตาราง ดูเพิ่มเติมประเภท PostgreSQL ข้อมูลไบนารีคู่มือ , การทดสอบกับคอลัมน์ byteaฯลฯ

NOTE1: วันนี้การใช้"โซลูชันคู่" (ฐานข้อมูล + ระบบไฟล์)เลิกใช้แล้ว (!) มีข้อดีหลายประการในการใช้ "ฐานข้อมูลเท่านั้น" แทนคู่ PostgreSQL มีประสิทธิภาพเทียบเท่าและเครื่องมือที่ดีสำหรับการส่งออก / นำเข้า / อินพุต / เอาต์พุต

Note2: จำได้ว่ามีเพียง PostgreSQL byteaไม่ต้องเริ่มต้นของออราเคิลหยด : "การกำหนดมาตรฐาน SQL ( ... ) หยดใส่รูปแบบจะแตกต่างกันจาก bytea แต่ฟังก์ชั่นที่มีให้และผู้ประกอบการส่วนใหญ่จะเป็นเหมือนกัน." คู่มือการใช้งาน


แก้ไข2014 : วันนี้ฉันยังไม่ได้เปลี่ยนข้อความต้นฉบับด้านบน (คำตอบของฉันคือ 22 เม.ย. 55 ตอนนี้มีคะแนนโหวต 14 โหวต) ฉันกำลังเปิดคำตอบสำหรับการเปลี่ยนแปลงของคุณ (ดู "โหมดวิกิพีเดีย" คุณสามารถแก้ไขได้!) เพื่อพิสูจน์อักษรและสำหรับการปรับปรุง
คำถามมีเสถียรภาพ (คำตอบ '08 ของ @ Ivans ด้วยคะแนนโหวต 19 คะแนน) โปรดช่วยปรับปรุงข้อความนี้


2
การอ้างอิงสำหรับ "... การใช้" โซลูชันคู่ "(ฐานข้อมูล + ระบบไฟล์) เลิกใช้แล้ว ... " คืออะไร?
dangel

ข่าวปี 2019! ตั้งแต่ปี 2018 PostgREST สนับสนุนการส่งออกไบต์โดยตรงไปยังเว็บ ดูการกำหนดค่าแบบง่ายของ NGINXนี้เพื่อใช้งาน ดูคำแนะนำ PostgREST เกี่ยวกับเอาต์พุตไบนารี
Peter Krauss

52

คำตอบของ Re jcoby:

bytea เป็นคอลัมน์ "ปกติ" ยังหมายถึงค่าที่อ่านลงในหน่วยความจำอย่างสมบูรณ์เมื่อคุณดึงข้อมูล ในทางตรงกันข้าม Blobs คุณสามารถสตรีมเป็น stdout ได้ ซึ่งช่วยในการลดรอยเท้าหน่วยความจำของเซิร์ฟเวอร์ โดยเฉพาะอย่างยิ่งเมื่อคุณจัดเก็บภาพขนาด 4-6 MPix

ไม่มีปัญหากับการสำรองข้อมูล blobs pg_dump มีตัวเลือก "-b" เพื่อรวมอ็อบเจ็กต์ขนาดใหญ่ไว้ในข้อมูลสำรอง

ดังนั้นฉันชอบใช้ pg_lo_ * คุณอาจเดาได้

คำตอบของ Re Kris Erickson:

ฉันจะพูดตรงกันข้าม :) เมื่อรูปภาพไม่ใช่ข้อมูลเดียวที่คุณจัดเก็บอย่าเก็บไว้ในระบบไฟล์เว้นแต่คุณจะต้องเก็บไว้อย่างแน่นอน เป็นประโยชน์อย่างยิ่งที่จะต้องแน่ใจเสมอเกี่ยวกับความสอดคล้องของข้อมูลของคุณและการมีข้อมูล "เป็นชิ้นเดียว" (ฐานข้อมูล) BTW, PostgreSQL นั้นยอดเยี่ยมในการรักษาความสม่ำเสมอ

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


15
หลังจากผ่านไป 10 ปีคุณคิดว่าคะแนนของคุณยังใช้ได้หรือไม่? มีการอัปเดตตั้งแต่นั้นมาหรือไม่?
leventunver

3
@leventunver ไม่จุดที่จะไม่ถือ ตัวอย่างเช่นBYTEAประการแรกเกี่ยวกับการเป็นคอลัมน์ "ปกติ" Postgres สนับสนุนการสตรีมไปยัง / จากBYTEAคอลัมน์เป็นเวลาหลายปีซึ่งหมายความว่าคุณไม่จำเป็นต้องเก็บเนื้อหาในหน่วยความจำก่อนที่จะจัดเก็บในฐานข้อมูล
oligofren

29

ในฐานข้อมูลมีสองตัวเลือก:

  • bytea เก็บข้อมูลในคอลัมน์ส่งออกเป็นส่วนหนึ่งของข้อมูลสำรอง ใช้ฟังก์ชันฐานข้อมูลมาตรฐานในการบันทึกและเรียกค้น แนะนำสำหรับความต้องการของคุณ
  • blobs จัดเก็บข้อมูลภายนอกโดยปกติจะไม่ส่งออกเป็นส่วนหนึ่งของข้อมูลสำรอง ต้องการฟังก์ชั่นฐานข้อมูลพิเศษเพื่อบันทึกและดึงข้อมูล

ฉันเคยใช้คอลัมน์ bytea ประสบความสำเร็จอย่างมากในอดีตที่เก็บรูปภาพ 10 + gb ด้วยแถวหลายพัน ฟังก์ชั่น TOAST ของ PG ปฏิเสธข้อได้เปรียบใด ๆ ที่ blobs มี คุณจะต้องรวมคอลัมน์ข้อมูลเมตาไม่ว่าในกรณีใดสำหรับชื่อไฟล์ประเภทเนื้อหามิติข้อมูล ฯลฯ


1
10GB ไม่มาก :-( ฉันกำลังมองหาโซลูชัน TBs
Valentin Heinitz

2
@ValentinHeinitz สำหรับ TBs vanilla Postgres ต้องดิ้นรนแม้จะมีคอลัมน์ข้อความที่เล็กกว่าก็ตาม
sudo

23

อัปเดตอย่างรวดเร็วถึงกลางปี ​​2015:

คุณสามารถใช้อินเทอร์เฟซ Postgres Foreign Dataเพื่อจัดเก็บไฟล์ในฐานข้อมูลที่เหมาะสมกว่า ตัวอย่างเช่นใส่ไฟล์ใน GridFS ซึ่งเป็นส่วนหนึ่งของ MongoDB จากนั้นใช้ https://github.com/EnterpriseDB/mongo_fdw เพื่อเข้าถึงใน Postgres

นั่นมีข้อดีคือคุณสามารถเข้าถึง / อ่าน / เขียน / สำรองข้อมูลได้ใน Postrgres และ MongoDB ขึ้นอยู่กับสิ่งที่ให้ความยืดหยุ่นมากขึ้น

นอกจากนี้ยังมีการห่อข้อมูลต่างประเทศสำหรับระบบไฟล์: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

ตัวอย่างเช่นคุณสามารถใช้สิ่งนี้: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (ดูตัวอย่างการใช้งานสั้น ๆ ที่นี่)

นั่นช่วยให้คุณได้รับประโยชน์จากความสอดคล้อง (ไฟล์ที่เชื่อมโยงทั้งหมดแน่นอนอยู่ที่นั่น) และ ACID อื่น ๆ ทั้งหมดในขณะที่ยังมีอยู่ในระบบไฟล์จริงซึ่งหมายความว่าคุณสามารถใช้ระบบไฟล์ใดก็ได้ที่คุณต้องการและเว็บเซิร์ฟเวอร์สามารถให้บริการได้โดยตรง ( การแคช OS ก็ใช้ได้เช่นกัน)


1
ขอบคุณ .. เครื่องห่อข้อมูลต่างประเทศ (file_fdw) ให้สิทธิ์การเขียนสำหรับรูปภาพหรือไม่ ฉันต้องการจัดเก็บรูปภาพลงใน FileSystem และข้อมูลเมตาของมันใน Postgresql แต่ฉันต้องรักษาความสม่ำเสมอด้วย คุณมีวิธีแก้ปัญหาโดยละเอียดหรือไม่? มีนามสกุลอื่นอีกไหม Multicorn ต้องการ python และฉันอยากจะทำโดยไม่ใช้ Python ..
Jay Khatwani

1
ใช่พวกเขามีสิทธิ์เขียน มีความสอดคล้องกันอย่างเต็มที่จาก / ทั้งสองทิศทาง และไม่ฉันไม่รู้วิธีแก้ปัญหาที่เท่าเทียมกันที่ทำสิ่งนี้โดยไม่ใช้ python
Kenyakorn Ketsombut

18

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

ต้นฉบับ

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

//linuxserver/images/imagexxx.jpg

จากนั้นคุณสามารถตั้งค่าเว็บเซิร์ฟเวอร์และจัดเก็บ URL ของเว็บในฐานข้อมูลได้อย่างรวดเร็ว (เช่นเดียวกับเส้นทางภายในเครื่อง) ในขณะที่ฐานข้อมูลสามารถจัดการ LOB และ 3000 ภาพ (4-6 ล้านพิกเซลสมมติว่า 500K ภาพ) 1.5 Gigs ไม่ใช่ระบบไฟล์พื้นที่จำนวนมากที่ออกแบบมาสำหรับการจัดเก็บไฟล์ขนาดใหญ่ได้ดีกว่าฐานข้อมูล


15
แต่คุณต้องคิดวิธีการแจกจ่ายไฟล์ผ่านไดเรกทอรีต่างๆ ระบบไฟล์ไม่ค่อยดีในการจัดเก็บไฟล์เป็นล้าน ๆ ไฟล์ในไดเร็กทอรีเดียว (จริงๆแล้วหมื่นไฟล์นั้นมีปัญหาอยู่แล้ว)
a_horse_with_no_name

1
ไม่ตอบคำถามเดิม โดยส่วนตัวแล้วฉันต้องการจัดเก็บภาพใน Postgres เพียงเพราะฉันต้องการให้ SQL เป็นเลเยอร์นามธรรมและไม่ต้องการจัดการไฟล์ในระบบไฟล์ ext4 ของฉัน
sudo

ฉันขัดแย้งนี่ไม่ได้ตอบคำถาม แต่ฉันโหวตให้เพราะมันเป็นคำตอบที่ดีกว่าคำตอบสำหรับคำถาม
Andrew Carr

6

ลองนี้ ฉันใช้รูปแบบ Large Object Binary (LOB) เพื่อจัดเก็บเอกสาร PDF ที่สร้างขึ้นซึ่งบางส่วนมีขนาด 10+ MB ในฐานข้อมูลและทำงานได้อย่างยอดเยี่ยม


2

หากรูปภาพของคุณมีขนาดเล็กให้พิจารณาจัดเก็บเป็น base64 ในฟิลด์ข้อความธรรมดา

เหตุผลก็คือในขณะที่ base64 มีค่าใช้จ่าย 33% ด้วยการบีบอัดที่ส่วนใหญ่หายไป (ดูพื้นที่เหนือศีรษะของการเข้ารหัส Base64 คือเท่าใด ) ฐานข้อมูลของคุณจะใหญ่ขึ้น แต่แพ็กเก็ตที่เว็บเซิร์ฟเวอร์ของคุณส่งไปยังไคลเอนต์จะไม่เป็นเช่นนั้น ใน html คุณสามารถอินไลน์ base64 ในแท็ก <img src = ""> ซึ่งอาจทำให้แอปของคุณง่ายขึ้นเนื่องจากคุณไม่ต้องแสดงรูปภาพเป็นไบนารีในการเรียกเบราว์เซอร์แยกต่างหาก การจัดการรูปภาพเป็นข้อความยังช่วยลดความยุ่งยากเมื่อคุณต้องส่ง / รับ json ซึ่งจัดการไบนารีได้ไม่ดีนัก

ใช่ฉันเข้าใจว่าคุณสามารถจัดเก็บไบนารีไว้ในฐานข้อมูลและแปลงเป็น / จากข้อความระหว่างทางเข้าและออกจากฐานข้อมูลได้ แต่บางครั้ง ORM ก็ทำให้ยุ่งยาก อาจง่ายกว่านี้เพียงแค่ถือว่าเป็นข้อความตรงเช่นเดียวกับช่องอื่น ๆ ของคุณ

นี่เป็นวิธีจัดการภาพขนาดย่อที่ถูกต้อง

(ภาพของ OP มีไม่มากดังนั้นนี่จึงไม่ใช่คำตอบสำหรับคำถามของเขาจริงๆ)

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