Các đặc tính hiệu suất của sqlite với các tệp cơ sở dữ liệu rất lớn là gì? [đóng cửa]


325

Tôi biết rằng sqlite không hoạt động tốt với các tệp cơ sở dữ liệu cực lớn ngay cả khi chúng được hỗ trợ (đã từng có một nhận xét trên trang web sqlite nói rằng nếu bạn cần kích thước tệp trên 1GB, bạn có thể muốn xem xét sử dụng rdbms doanh nghiệp. Không tìm thấy nó nữa, có thể liên quan đến một phiên bản cũ hơn của sqlite).

Tuy nhiên, với mục đích của tôi, tôi muốn có được một ý tưởng về việc nó thực sự tồi tệ như thế nào trước khi tôi xem xét các giải pháp khác.

Tôi đang nói về các tệp dữ liệu sqlite trong phạm vi nhiều gigabyte, từ 2GB trở đi. Ai có kinh nghiệm với cái này rồi nào? Bất kỳ lời khuyên / ý tưởng?


1
Sử dụng luồng (kết nối trên mỗi luồng) chỉ có thể giúp đọc - stackoverflow.com/a/24029046/743263
malkia


23
Năm 2016: Tôi có cơ sở dữ liệu 5 GB chạy trên SQLite mà không gặp vấn đề gì. Tôi đã cài đặt cùng một bộ dữ liệu trên Postgres. SQLite đã chạy một truy vấn phức tạp trong 2,7 ms, Postgres trong 2,5 ms. Tôi đã kết thúc trên Postgres để truy cập Regex dễ dàng hơn và các tính năng chỉ mục tốt hơn. Nhưng tôi đã bị ấn tượng bởi SQLite và có thể đã sử dụng nó.
Paulb

Câu trả lời:


246

Vì vậy, tôi đã thực hiện một số thử nghiệm với sqlite cho các tệp rất lớn và đưa ra một số kết luận (ít nhất là cho ứng dụng cụ thể của tôi).

Các thử nghiệm liên quan đến một tệp sqlite duy nhất với một bảng hoặc nhiều bảng. Mỗi bảng có khoảng 8 cột, hầu hết tất cả các số nguyên và 4 chỉ số.

Ý tưởng là chèn đủ dữ liệu cho đến khi các tệp sqlite có dung lượng khoảng 50 GB.

Bảng đơn

Tôi đã cố gắng chèn nhiều hàng vào một tệp sqlite chỉ bằng một bảng. Khi tệp có dung lượng khoảng 7 GB (xin lỗi, tôi không thể nói cụ thể về số lượng hàng), quá trình chèn đã mất quá nhiều thời gian. Tôi đã ước tính rằng thử nghiệm của tôi để chèn tất cả dữ liệu của tôi sẽ mất 24 giờ hoặc lâu hơn, nhưng nó đã không hoàn thành ngay cả sau 48 giờ.

Điều này dẫn đến tôi kết luận rằng một bảng sqlite duy nhất, rất lớn sẽ có vấn đề với các phần chèn thêm, và có lẽ các hoạt động khác cũng vậy.

Tôi đoán điều này không có gì đáng ngạc nhiên, vì bảng trở nên lớn hơn, việc chèn và cập nhật tất cả các chỉ số mất nhiều thời gian hơn.

Nhiều bàn

Sau đó tôi đã thử chia dữ liệu theo thời gian qua nhiều bảng, một bảng mỗi ngày. Dữ liệu cho 1 bảng gốc được chia thành ~ 700 bảng.

Thiết lập này không có vấn đề gì với việc chèn, nó không mất nhiều thời gian hơn vì thời gian đã được tạo ra cho mỗi bảng.

Vấn đề chân không

Như i_like_caffeine đã chỉ ra, lệnh VACUUM là một vấn đề khi tệp sqlite càng lớn. Khi nhiều thao tác chèn / xóa được thực hiện, sự phân mảnh của tệp trên đĩa sẽ trở nên tồi tệ hơn, vì vậy mục tiêu là định kỳ VACUUM để tối ưu hóa tệp và khôi phục không gian tệp.

Tuy nhiên, như được chỉ ra bởi tài liệu , một bản sao đầy đủ của cơ sở dữ liệu được tạo ra để làm chân không, mất một thời gian rất dài để hoàn thành. Vì vậy, cơ sở dữ liệu càng nhỏ, thao tác này sẽ kết thúc càng nhanh.

Kết luận

Đối với ứng dụng cụ thể của tôi, có lẽ tôi sẽ phân tách dữ liệu qua một số tệp db, mỗi tệp một ngày, để đạt hiệu suất tốt nhất cả về hiệu suất chân không và tốc độ chèn / xóa.

Điều này làm phức tạp các truy vấn, nhưng đối với tôi, đó là một sự đánh đổi đáng giá để có thể lập chỉ mục nhiều dữ liệu này. Một lợi thế nữa là tôi có thể xóa toàn bộ tệp db để giảm giá trị dữ liệu trong một ngày (một thao tác chung cho ứng dụng của tôi).

Có lẽ tôi cũng phải theo dõi kích thước bảng trên mỗi tệp để xem khi nào tốc độ sẽ trở thành vấn đề.

Thật tệ khi dường như không có một phương pháp chân không gia tăng nào ngoài việc hút bụi tự động . Tôi không thể sử dụng nó vì mục tiêu của tôi đối với chân không là chống phân mảnh tệp (không gian tệp không phải là vấn đề lớn), điều mà máy hút bụi tự động không làm được. Trong thực tế, tài liệu nói rằng nó có thể làm cho sự phân mảnh trở nên tồi tệ hơn, vì vậy tôi phải dùng đến việc định kỳ thực hiện toàn bộ chân không trên tệp.


5
Thông tin rất hữu ích. Đầu cơ thuần túy nhưng tôi tự hỏi liệu api sao lưu mới có thể được sử dụng để tạo một phiên bản cơ sở dữ liệu không phân mảnh của bạn hàng ngày hay không và tránh phải chạy VACUUM.
eodonohoe

24
Tôi tò mò, có phải tất cả các KHAI THÁC của bạn trong một giao dịch?
Paul Lefebvre

9
Có, việc chèn được thực hiện theo lô 10000 tin nhắn cho mỗi giao dịch.
Snazzer

6
Bạn đã sử dụng hệ thống tập tin nào? Nếu máy lẻ {2,3,4}, dữ liệu = cài đặt là gì, đã ghi nhật ký chưa? Bên cạnh các mẫu io, cách sqlite tuôn ra đĩa có thể là đáng kể.
Tobu

5
Tôi đã thử nghiệm chủ yếu trên windows, vì vậy không thể nhận xét về hành vi trên linux.
Snazzer

169

Chúng tôi đang sử dụng DBS 50 GB + trên nền tảng của chúng tôi. không phàn nàn công việc tuyệt vời. Hãy chắc chắn rằng bạn đang làm mọi thứ đúng! Bạn đang sử dụng báo cáo được xác định trước? * SQLITE 3.7.3

  1. Giao dịch
  2. Báo cáo trước
  3. Áp dụng các cài đặt này (ngay sau khi bạn tạo DB)

    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;

Hy vọng điều này sẽ giúp những người khác, làm việc tuyệt vời ở đây


22
Gần đây đã thử nghiệm với dbs trong phạm vi 160GB, cũng hoạt động rất tốt.
Snazzer

10
Ngoài ra PRAGMA main.temp_store = MEMORY;.
Vikrant Chaudhary

40
@Alex, tại sao có hai PRAGMA main.cache_size = 5000;?
Jack

23
Đừng chỉ mù quáng áp dụng những tối ưu hóa này. Cụ thể là đồng bộ = BÌNH THƯỜNG không an toàn. Tức là, một sự cố quá trình vào đúng thời điểm có thể làm hỏng cơ sở dữ liệu của bạn ngay cả khi không có lỗi đĩa. sqlite.org/pragma.html#pragma_synyncous
mpm

22
@Alex bạn có thể vui lòng giải thích các giá trị đó và sự khác biệt giữa các giá trị mặc định và giá trị mặc định không?
4m1nh4j1

65

Tôi đã tạo cơ sở dữ liệu SQLite có kích thước lên tới 3,5 GB mà không gặp vấn đề gì về hiệu suất. Nếu tôi nhớ chính xác, tôi nghĩ rằng SQLite2 có thể có một số giới hạn thấp hơn, nhưng tôi không nghĩ SQLite3 có bất kỳ vấn đề nào như vậy.

Theo trang Giới hạn SQLite , kích thước tối đa của mỗi trang cơ sở dữ liệu là 32K. Và các trang tối đa trong cơ sở dữ liệu là 1024 ^ 3. Vì vậy, theo toán học của tôi, con số này lên tới 32 terabyte là kích thước tối đa. Tôi nghĩ bạn sẽ đạt giới hạn hệ thống tệp của mình trước khi nhấn SQLite!


3
Tùy thuộc vào hoạt động bạn đang thực hiện, thử xóa 3000 hàng trong cơ sở dữ liệu sqlite 8G, bạn cần có đủ thời gian để pha một nồi báo chí tiếng Pháp, lol
benjaminz

4
@benjaminz, bạn phải làm sai. Nếu bạn gói xóa 3k hàng trong một giao dịch, thì nó sẽ gần như ngay lập tức. Tôi đã có lỗi này: xóa từng hàng 10k từng cái mất 30 phút. Nhưng một khi tôi gói tất cả các câu lệnh xóa vào một giao dịch, phải mất 5s.
mvp

55

Phần lớn lý do khiến bạn mất> 48 giờ để thực hiện thao tác chèn là do chỉ mục của bạn. Nó cực kỳ nhanh hơn để:

1 - Thả tất cả các chỉ mục 2 - Thực hiện tất cả các chèn 3 - Tạo lại các chỉ mục


23
Đó là điều nổi tiếng ... nhưng trong một quá trình dài, bạn sẽ không định kỳ bỏ chỉ mục của mình để xây dựng lại chúng, đặc biệt là khi bạn sẽ truy vấn chúng để thực hiện công việc. Đó là cách tiếp cận được thực hiện mặc dù khi db sqlite phải được xây dựng lại từ đầu, các chỉ mục được tạo sau khi tất cả các thao tác chèn được thực hiện.
Snazzer

24
@Snazzer trong một tình huống tương tự, chúng tôi đã sử dụng bảng "tích lũy": một lần mỗi ngày chúng tôi sẽ chuyển các hàng tích lũy từ bảng tích lũy sang bảng chính trong một giao dịch. Trường hợp cần một khung nhìn quan tâm đến việc trình bày cả hai bảng dưới dạng một bảng.
CAFxX

4
Một tùy chọn khác là giữ các chỉ mục, nhưng sắp xếp trước dữ liệu theo thứ tự chỉ mục trước khi bạn chèn nó.
Steven Kryskalla

1
@StevenKryskalla làm thế nào mà so sánh với việc bỏ chỉ mục và tạo lại chúng? Bất kỳ liên kết bạn biết về điều đó đã được điểm chuẩn?
mcmillab

1
@mcmillab Đây là cách đây nhiều năm nên tôi không nhớ tất cả các chi tiết hoặc số liệu thống kê điểm chuẩn, nhưng suy nghĩ bằng trực giác, việc chèn N phần tử được sắp xếp ngẫu nhiên vào một chỉ mục sẽ mất thời gian O (NlogN), trong khi chèn N phần tử được sắp xếp sẽ mất O (N ) thời gian.
Steven Kryskalla

34

Bên cạnh các khuyến nghị thông thường:

  1. Chỉ số thả cho chèn số lượng lớn.
  2. Batch chèn / cập nhật trong các giao dịch lớn.
  3. Điều chỉnh bộ đệm bộ đệm của bạn / vô hiệu hóa tạp chí / w PRAGMAs.
  4. Sử dụng máy 64 bit (để có thể sử dụng nhiều bộ đệm ™).
  5. [đã thêm vào tháng 7 năm 2014] Sử dụng biểu thức bảng chung (CTE) thay vì chạy nhiều truy vấn SQL! Yêu cầu phát hành SQLite 3.8.3.

Tôi đã học được những điều sau từ kinh nghiệm của mình với SQLite3:

  1. Để có tốc độ chèn tối đa, không sử dụng lược đồ với bất kỳ ràng buộc cột nào. (Thay đổi bảng sau khi cần thiết Bạn không thể thêm các ràng buộc với ALTER TABLE).
  2. Tối ưu hóa lược đồ của bạn để lưu trữ những gì bạn cần. Đôi khi, điều này có nghĩa là phá vỡ các bảng và / hoặc thậm chí nén / chuyển đổi dữ liệu của bạn trước khi chèn vào cơ sở dữ liệu. Một ví dụ tuyệt vời là lưu trữ địa chỉ IP dưới dạng số nguyên (dài).
  3. Một bảng cho mỗi tệp db - để giảm thiểu sự tranh chấp khóa. (Sử dụng ATTACH DATABASE nếu bạn muốn có một đối tượng kết nối.
  4. SQLite có thể lưu trữ các loại dữ liệu khác nhau trong cùng một cột (gõ động), sử dụng điều đó cho lợi thế của bạn.

Câu hỏi / bình luận chào mừng. ;-)


1
Bạn nhận được bao nhiêu tác động từ 'một bảng cho mỗi tệp db'? Nghe có vẻ thú vị. Bạn có nghĩ nó sẽ quan trọng hơn nếu bảng của bạn chỉ có 3 bảng và được xây dựng từ đầu không?
Martin Velez

4
@martin ghét nói nhưng câu trả lời là tùy . Ý tưởng là phân vùng dữ liệu đến kích thước có thể quản lý. Trong trường hợp sử dụng của tôi, tôi thu thập dữ liệu từ các máy chủ khác nhau và báo cáo dữ liệu sau khi thực tế để phương pháp này hoạt động tốt. Phân vùng theo ngày / giờ theo đề xuất của người khác sẽ hoạt động tốt đối với dữ liệu kéo dài trong khoảng thời gian dài mà tôi sẽ tưởng tượng.
Lester Cheung

3
@Lester Cheung: Về số 1 thứ hai của bạn: Theo hiểu biết của tôi từ các tài liệu và kinh nghiệm cá nhân cho đến ngày nay, SQLite3 không hỗ trợ thêm các ràng buộc với ALTER TABLE sau khi tạo bảng. Cách duy nhất để thêm hoặc xóa các ràng buộc khỏi các hàng của bảng hiện có là tạo một bảng mới với các đặc điểm mong muốn và sao chép trên tất cả các hàng, có khả năng chậm hơn nhiều so với chèn một lần với các ràng buộc.
Mumbledkates

3
@Widdershins bạn hoàn toàn đúng - ALTER TABLE trong SQLite không cho phép thêm các ràng buộc. Tôi không biết mình đang hút thuốc gì - sẽ cập nhật câu trả lời - cảm ơn.
Lester Cheung

Không có gợi ý nào trong số đó có liên quan đến việc sử dụng các tệp db SQLite khiêm tốn. Là câu hỏi được chỉnh sửa kể từ khi câu trả lời này được gửi?
A. Rager

9

Tôi nghĩ rằng những phàn nàn chính về quy mô sqlite là:

  1. Quá trình viết đơn.
  2. Không phản chiếu.
  3. Không nhân rộng.

9

Tôi có cơ sở dữ liệu SQLite 7GB. Để thực hiện một truy vấn cụ thể với một phép nối bên trong phải mất 2,6 giây Để tăng tốc độ này, tôi đã thử thêm các chỉ mục. Tùy thuộc vào chỉ số nào tôi đã thêm, đôi khi truy vấn giảm xuống còn 0,1 giây và đôi khi nó tăng lên đến 7 giây. Tôi nghĩ vấn đề trong trường hợp của tôi là nếu một cột có độ trùng lặp cao thì việc thêm chỉ mục làm giảm hiệu suất :(


9
Tại sao một cột có nhiều bản sao làm giảm hiệu suất (câu hỏi nghiêm trọng)?
Martin Velez

6
một cột có số lượng thẻ thấp sẽ khó lập chỉ mục hơn: stackoverflow.com/questions/2113181/NH
metrix

9

Đã từng có một tuyên bố trong tài liệu SQLite rằng giới hạn kích thước thực tế của tệp cơ sở dữ liệu là vài chục GB: s. Điều đó chủ yếu là do SQLite cần "phân bổ một bitmap trang bẩn" bất cứ khi nào bạn bắt đầu giao dịch. Do đó, 256 byte RAM được yêu cầu cho mỗi MB trong cơ sở dữ liệu. Chèn vào tệp DB 50 GB sẽ cần một lượng lớn (2 ^ 8) * (2 ^ 10) = 2 ^ 18 = 256 MB RAM.

Nhưng như các phiên bản gần đây của SQLite, điều này không còn cần thiết nữa. Đọc thêm ở đây .


25
Tôi rất xin lỗi vì tôi phải chỉ ra điều này, nhưng 2^18thực tế chỉ có 256 K.
Gabriel Schreiber

7
@GabrielSchreiber rằng, và thực tế là 50 GB không phải (2 ^ 10) MB, đó chỉ là 1 GB. Vì vậy, đối với cơ sở dữ liệu 50 GB, bạn cần 12,5 MB bộ nhớ: (2 ^ 8) * (2 ^ 10) * 50
elipoultorak

8

Tôi đã gặp vấn đề với các tệp sqlite lớn khi sử dụng lệnh chân không.

Tôi chưa thử tính năng auto_vacuum. Nếu bạn dự kiến ​​sẽ cập nhật và xóa dữ liệu thường xuyên thì điều này đáng để xem xét.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.