คุณสมบัติด้านประสิทธิภาพของ sqlite พร้อมไฟล์ฐานข้อมูลขนาดใหญ่มาก ๆ คืออะไร? [ปิด]


325

ฉันรู้ว่า sqlite ทำงานได้ไม่ดีกับไฟล์ฐานข้อมูลที่มีขนาดใหญ่มากแม้ว่าจะได้รับการสนับสนุน (เคยมีความคิดเห็นในเว็บไซต์ sqlite ที่ระบุว่าหากคุณต้องการขนาดไฟล์ที่สูงกว่า 1GB คุณอาจต้องการพิจารณาใช้ rdbms ระดับองค์กร ไม่พบอีกต่อไปอาจเกี่ยวข้องกับ SQL เวอร์ชันเก่ากว่า)

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

ฉันกำลังพูดถึงไฟล์ข้อมูล sqlite ในช่วงหลายกิกะไบต์ตั้งแต่ 2GB เป็นต้นไป ใครมีประสบการณ์กับสิ่งนี้บ้าง เคล็ดลับ / ความคิดใด ๆ


1
การใช้เธรด (การเชื่อมต่อต่อเธรด) อาจช่วยในการอ่านเท่านั้น - stackoverflow.com/a/24029046/743263
malkia


23
ปี 2559: ฉันมีฐานข้อมูล 5 GB ที่รันบน SQLite โดยไม่มีปัญหา ฉันติดตั้งชุดข้อมูลเดียวกันที่แน่นอนใน Postgres SQLite เรียกใช้คิวรีที่ซับซ้อนใน 2.7 ms, Postgres ใน 2.5 ms ฉันลงเอย Postgres สำหรับการเข้าถึง Regex ที่ง่ายขึ้นและคุณลักษณะดัชนีที่ดีขึ้น แต่ฉันรู้สึกประทับใจกับ SQLite และสามารถใช้ได้เช่นกัน
Paulb

คำตอบ:


246

ดังนั้นฉันจึงทำการทดสอบด้วย sqlite สำหรับไฟล์ที่มีขนาดใหญ่มากและมาถึงข้อสรุปบางอย่าง (อย่างน้อยสำหรับแอปพลิเคชันเฉพาะของฉัน)

การทดสอบเกี่ยวข้องกับไฟล์ sqlite ไฟล์เดียวที่มีทั้งตารางเดี่ยวหรือหลายตาราง แต่ละตารางมีประมาณ 8 คอลัมน์, จำนวนเต็มเกือบทั้งหมดและ 4 ดัชนี

แนวคิดคือการแทรกข้อมูลให้เพียงพอจนกระทั่งไฟล์ sqlite มีขนาดประมาณ 50GB

โต๊ะเดี่ยว

ฉันพยายามแทรกหลายแถวลงในไฟล์ sqlite ด้วยตารางเดียว เมื่อไฟล์มีขนาดประมาณ 7GB (ขออภัยฉันไม่สามารถระบุจำนวนแถวได้โดยเฉพาะ) การแทรกใช้เวลานานเกินไป ฉันคาดว่าการทดสอบของฉันจะแทรกข้อมูลทั้งหมดของฉันจะใช้เวลา 24 ชั่วโมงหรือมากกว่านั้น แต่ก็ไม่สมบูรณ์แม้หลังจาก 48 ชั่วโมง

นี่ทำให้ฉันสรุปได้ว่าตาราง sqlite ขนาดใหญ่มากเดียวจะมีปัญหาเกี่ยวกับการแทรกและอาจเป็นการดำเนินการอื่น ๆ ด้วย

ฉันเดาว่านี่ไม่น่าแปลกใจเนื่องจากตารางมีขนาดใหญ่ขึ้นการแทรกและการปรับปรุงดัชนีทั้งหมดใช้เวลานานขึ้น

หลายตาราง

จากนั้นฉันพยายามแยกข้อมูลตามเวลาในหลาย ๆ ตารางหนึ่งตารางต่อวัน ข้อมูลสำหรับ 1 ตารางต้นฉบับถูกแบ่งเป็น ~ 700 ตาราง

การตั้งค่านี้ไม่มีปัญหากับการแทรกมันไม่ใช้เวลานานขึ้นเนื่องจากมีการสร้างตารางใหม่ทุกวัน

ปัญหาสูญญากาศ

ตามที่ระบุโดย i_like_caffeine คำสั่ง VACUUM เป็นปัญหาของไฟล์ sqlite ที่ใหญ่กว่า เมื่อมีการแทรก / ลบมากขึ้นการกระจายตัวของไฟล์บนดิสก์จะแย่ลงดังนั้นเป้าหมายคือ VACUUM เป็นระยะเพื่อปรับไฟล์ให้เหมาะสมและกู้คืนพื้นที่ไฟล์

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

สรุปผลการวิจัย

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

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

ฉันอาจต้องตรวจสอบขนาดตารางต่อไฟล์เช่นกันเพื่อดูว่าความเร็วจะกลายเป็นปัญหาหรือไม่

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


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

24
ฉันอยากรู้อยากเห็น INSERTS ทั้งหมดของคุณอยู่ในการทำธุรกรรมหรือไม่?
Paul Lefebvre

9
ใช่มีการแทรกข้อความเป็นจำนวนมากถึง 10,000 ข้อความต่อหนึ่งธุรกรรม
Snazzer

6
คุณใช้ระบบไฟล์แบบใด หากต่อ {2,3,4} อะไรคือการตั้งค่า data = การเปิดใช้งานการทำเจอร์นัลคืออะไร นอกเหนือจากรูปแบบของ io แล้ว sqlite flushes บนดิสก์อาจมีนัยสำคัญ
Tobu

5
ฉันทำการทดสอบบน windows เป็นหลักดังนั้นจึงไม่สามารถออกความเห็นเกี่ยวกับพฤติกรรมของ linux
Snazzer

169

เราใช้ DBS ขนาด 50 GB ขึ้นไปบนแพลตฟอร์มของเรา ไม่มีบ่นใช้งานได้ดี ตรวจสอบให้แน่ใจว่าคุณทำทุกอย่างถูกต้อง! คุณใช้ข้อความที่กำหนดไว้ล่วงหน้าหรือไม่? * SQLITE 3.7.3

  1. การทำธุรกรรม
  2. งบที่ทำไว้ล่วงหน้า
  3. ใช้การตั้งค่าเหล่านี้ (ทันทีหลังจากที่คุณสร้างฐานข้อมูล)

    PRAGMA main.page_size = 4096;
    PRAGMA main.cache_size=10000;
    PRAGMA main.locking_mode=EXCLUSIVE;
    PRAGMA main.synchronous=NORMAL;
    PRAGMA main.journal_mode=WAL;
    PRAGMA main.cache_size=5000;

หวังว่านี่จะช่วยผู้อื่นได้ผลดีมากที่นี่


22
ทดสอบล่าสุดกับ dbs ในช่วง 160GB ใช้งานได้ดีเช่นกัน
Snazzer

10
PRAGMA main.temp_store = MEMORY;ด้วย
Vikrant Chaudhary

40
@Alex ทำไมมีสอง PRAGMA main.cache_size = 5000 ;?
แจ็ค

23
อย่าเพิ่งใช้การเพิ่มประสิทธิภาพเหล่านี้แบบสุ่ม ๆ โดยเฉพาะอย่างยิ่งซิงโครนัส = ปกติไม่ปลอดภัยผิดพลาด นั่นคือกระบวนการที่ผิดพลาดในเวลาที่เหมาะสมสามารถทำลายฐานข้อมูลของคุณได้แม้ในกรณีที่ไม่มีดิสก์ล้มเหลว sqlite.org/pragma.html#pragma_synchronous
mpm

22
@Alex คุณช่วยอธิบายค่าเหล่านั้นและความแตกต่างระหว่างค่าเอมกับค่าปริยายได้ไหม?
4m1nh4j1

65

ฉันสร้างฐานข้อมูล SQLite สูงถึง 3.5GB โดยไม่มีปัญหาเรื่องประสิทธิภาพ ถ้าฉันจำได้อย่างถูกต้องฉันคิดว่า SQLite2 อาจมีขีด จำกัด ที่ต่ำกว่า แต่ฉันไม่คิดว่า SQLite3 จะมีปัญหาดังกล่าว

ตามหน้าSQLite Limitsขนาดสูงสุดของแต่ละหน้าฐานข้อมูลคือ 32K และจำนวนหน้าสูงสุดในฐานข้อมูลคือ 1024 ^ 3 ดังนั้นโดยคณิตศาสตร์ของฉันที่มีขนาดสูงสุด 32 เทราไบต์ ฉันคิดว่าคุณจะถึงขีด จำกัด ของระบบไฟล์ของคุณก่อนที่จะกดปุ่ม SQLite!


3
ขึ้นอยู่กับการดำเนินการที่คุณกำลังแสดงอยู่พยายามลบ 3000 แถวในฐานข้อมูล 8G sqlite มันใช้เวลาพอสำหรับคุณที่จะสร้างสื่อฝรั่งเศสที่ดีหม้อ lol
benjaminz

4
@benjaminz คุณต้องทำผิด หากคุณตัดการลบแถว 3k ในหนึ่งธุรกรรมมันควรจะเป็นเกือบทันที ฉันมีข้อผิดพลาดนี้เอง: การลบ 10k แถวทีละหนึ่งใช้เวลา 30 นาที แต่เมื่อฉันรวมคำสั่งลบทั้งหมดในรายการเดียว
MVP

55

สาเหตุส่วนใหญ่ที่ใช้เวลา> 48 ชั่วโมงในการแทรกเม็ดมีดนั้นเป็นเพราะดัชนีของคุณ มันเร็วกว่าอย่างเหลือเชื่อเมื่อ:

1 - ดร็อปดัชนีทั้งหมด 2 - ทำการแทรกทั้งหมด 3 - สร้างดัชนีอีกครั้ง


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

24
@Snazzer ในสถานการณ์ที่คล้ายคลึงกันเราใช้ตาราง "accumulator": วันละครั้งเราจะย้ายแถวที่สะสมจากตารางตัวสะสมไปยังตารางหลักภายในธุรกรรมเดียว ในกรณีที่ต้องการมุมมองดูแลการนำเสนอทั้งสองตารางเป็นตารางเดียว
CAFxX

4
ตัวเลือกอื่นคือการเก็บดัชนี แต่เรียงลำดับข้อมูลตามลำดับดัชนีก่อนที่คุณจะแทรก
Steven Kryskalla

1
@StevenKryskalla เทียบกับการวางดัชนีและสร้างใหม่อย่างไร? ลิงก์ใด ๆ ที่คุณรู้ว่ามีการเปรียบเทียบกัน?
mcmillab

1
@mcmillab เมื่อหลายปีก่อนดังนั้นฉันจำไม่ได้ว่ารายละเอียดทั้งหมดหรือสถิติมาตรฐาน แต่การคิดอย่างสังหรณ์ใจการใส่องค์ประกอบที่เรียงลำดับแบบสุ่มเข้าไปในดัชนีจะใช้เวลา O (NlogN) ในขณะที่การแทรกองค์ประกอบที่เรียงลำดับจะใช้ O (N เวลา)
Steven Kryskalla

34

นอกจากคำแนะนำปกติ:

  1. วางดัชนีสำหรับการแทรกจำนวนมาก
  2. Batch แทรก / อัพเดทในการทำธุรกรรมขนาดใหญ่
  3. ปรับแคชบัฟเฟอร์ของคุณ / ปิดการใช้งาน journal / w PRAGMA
  4. ใช้เครื่อง 64 บิต (เพื่อให้สามารถใช้แคชได้มากมาย)
  5. [เพิ่มกรกฎาคม 2014] ใช้นิพจน์ตารางทั่วไป (CTE)แทนที่จะเรียกใช้แบบสอบถาม SQL หลายรายการ! ต้องการ SQLite release 3.8.3

ฉันได้เรียนรู้สิ่งต่อไปนี้จากประสบการณ์ของฉันกับ SQLite3:

  1. สำหรับความเร็วในการแทรกสูงสุดอย่าใช้สคีมากับข้อ จำกัด ของคอลัมน์ใด ๆ (แก้ไขตารางในภายหลังตามต้องการ คุณไม่สามารถเพิ่มข้อ จำกัด ด้วย ALTER TABLE)
  2. เพิ่มประสิทธิภาพสคีมาของคุณเพื่อเก็บสิ่งที่คุณต้องการ บางครั้งนี่หมายถึงการแยกย่อยตารางและ / หรือแม้แต่บีบอัด / แปลงข้อมูลของคุณก่อนที่จะแทรกลงในฐานข้อมูล ตัวอย่างที่ดีคือการจัดเก็บที่อยู่ IP เป็นจำนวนเต็ม (ยาว)
  3. หนึ่งตารางต่อไฟล์ db - เพื่อลดความขัดแย้งในการล็อก (ใช้ATTACH DATABASEหากคุณต้องการมีวัตถุเชื่อมต่อเดียว
  4. SQLite สามารถเก็บข้อมูลประเภทต่าง ๆ ไว้ในคอลัมน์เดียวกัน (การพิมพ์แบบไดนามิก), ใช้เพื่อประโยชน์ของคุณ

ยินดีต้อนรับคำถาม / ความคิดเห็น ;-)


1
คุณได้รับผลกระทบเท่าไรจาก 'หนึ่งตารางต่อไฟล์ db' ฟังดูน่าสนใจ. คุณคิดว่ามันจะมีความสำคัญมากหากโต๊ะของคุณมีเพียง 3 โต๊ะและถูกสร้างขึ้นใหม่ทั้งหมด?
Martin Velez

4
@ Martin เกลียดที่จะพูด แต่คำตอบคือมันขึ้นอยู่กับ แนวคิดนี้แบ่งพาร์ติชันข้อมูลเป็นขนาดที่สามารถจัดการได้ ในกรณีที่ใช้งานของฉันฉันรวบรวมข้อมูลจากโฮสต์ที่แตกต่างกันและทำการรายงานข้อมูลหลังจากข้อเท็จจริงเพื่อให้วิธีการนี้ทำงานได้ดี การแบ่งพาร์ติชันตามวันที่ / เวลาตามที่คนอื่นแนะนำควรทำงานได้ดีสำหรับข้อมูลที่มีระยะเวลายาวนานที่ฉันจินตนาการ
เลสเตอร์ Cheung

3
@Lester Cheung: เกี่ยวกับ # 1 ที่สองของคุณ: มันเป็นความเข้าใจของฉันจากเอกสารและประสบการณ์ส่วนตัวที่จนถึงทุกวันนี้ SQLite3 ไม่สนับสนุนการเพิ่มข้อ จำกัด ด้วย ALTER TABLE หลังจากการสร้างตาราง วิธีเดียวที่จะเพิ่มหรือลบข้อ จำกัด จากแถวตารางที่มีอยู่คือการสร้างตารางใหม่ที่มีคุณสมบัติที่ต้องการและคัดลอกไปยังแถวทั้งหมดซึ่งน่าจะช้ากว่าการแทรกครั้งเดียวด้วยข้อ จำกัด
Mumbleskates

3
@Widdershins คุณมีสิทธิ์อย่างสมบูรณ์ - ALTER TABLE ใน SQLite ไม่อนุญาตให้เพิ่มข้อ จำกัด ฉันไม่รู้ว่าฉันกำลังสูบบุหรี่ - จะปรับปรุงคำตอบ - ขอบคุณ
เลสเตอร์ Cheung

คำแนะนำเหล่านั้นไม่มีส่วนเกี่ยวข้องกับการใช้ไฟล์ SQLite db ที่มีค่ามาก คำถามถูกแก้ไขตั้งแต่คำตอบนี้ถูกส่งหรือไม่
A. Rager

9

ฉันคิดว่าข้อร้องเรียนหลักเกี่ยวกับการปรับขนาดของ sqlite คือ:

  1. เขียนกระบวนการเดียว
  2. ไม่มีการมิเรอร์
  3. ไม่มีการจำลองแบบ

9

ฉันมีฐานข้อมูล SQLite 7GB เพื่อดำเนินการค้นหาเฉพาะกับการเข้าร่วมภายในใช้เวลา 2.6 วินาทีเพื่อเพิ่มความเร็วฉันพยายามเพิ่มดัชนี ขึ้นอยู่กับดัชนีที่ฉันเพิ่มบางครั้งข้อความค้นหาลดลงเหลือ 0.1s และบางครั้งก็เพิ่มขึ้นมากถึง 7s ฉันคิดว่าปัญหาในกรณีของฉันคือถ้าคอลัมน์ซ้ำกันอย่างมากจากนั้นเพิ่มดัชนีลดประสิทธิภาพ:


9
เหตุใดคอลัมน์ที่มีการซ้ำซ้อนจำนวนมากจะลดประสิทธิภาพลง (คำถามที่จริงจัง)
Martin Velez

6
คอลัมน์ที่มีระดับความรุนแรงต่ำนั้นยากต่อการจัดทำดัชนี: stackoverflow.com/questions/2113181/…
metrix

9

เคยมีคำสั่งในเอกสารประกอบ SQLite ว่าข้อ จำกัด ขนาดการใช้งานจริงของไฟล์ฐานข้อมูลคือไม่กี่โหล GB: s ส่วนใหญ่เกิดจากความต้องการของ SQLite ในการ "จัดสรรบิตแมปหน้าสกปรก" ทุกครั้งที่คุณเริ่มทำธุรกรรม ดังนั้นจำเป็นต้องใช้ RAM 256 ไบต์สำหรับแต่ละ MB ในฐานข้อมูล การแทรกลงในไฟล์ DB 50 GB จะต้องมีขนาดใหญ่ (2 ^ 8) * (2 ^ 10) = 2 ^ 18 = 256 MB RAM

แต่เมื่อเป็นรุ่นล่าสุดของ SQLite สิ่งนี้ไม่จำเป็นอีกต่อไป อ่านเพิ่มเติมที่นี่


25
ฉันเสียใจมากที่ต้องชี้ประเด็นนี้ แต่2^18จริงๆแล้วมีเพียง 256 เค
กาเบรียลชรีเบอร์

7
@GabrielSchreiber นั้นและความจริงที่ว่า 50GB ไม่ใช่ (2 ^ 10) MB นั่นเป็นเพียง 1GB ดังนั้นสำหรับฐานข้อมูล 50GB คุณต้องมีหน่วยความจำ 12.5MB: (2 ^ 8) * (2 ^ 10) * 50
elipoultorak

8

ฉันประสบปัญหากับไฟล์ sqlite ขนาดใหญ่เมื่อใช้คำสั่ง vacuum

ฉันยังไม่ได้ลองใช้คุณสมบัติ auto_vacuum หากคุณคาดหวังว่าจะได้รับการอัปเดตและลบข้อมูลบ่อยๆ

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