Thiết kế cơ sở dữ liệu để xử lý 1 tỷ hàng và đếm


10

Chúng tôi nhận được dữ liệu GPS thời gian thực với tốc độ khoảng 5000 pr. phút (từ 4 máy chủ TCP). Mỗi máy chủ sử dụng một kết nối duy nhất để chèn dữ liệu và đệm dữ liệu vào giữa các lần chèn. Cứ sau 15 phút, một dịch vụ sẽ lấy dữ liệu này và xử lý nó thành các chuyến đi. Khi các chuyến đi đã được tạo, dữ liệu GPS thực tế thường không quá quan trọng, chỉ khi người dùng muốn xem tuyến đường trên bản đồ.

Vấn đề là dường như cơ sở dữ liệu đang vật lộn để theo kịp tốc độ dữ liệu được chèn vào. Đôi khi khi tải tăng lên, thời gian chèn đột ngột tăng mạnh (> 30 giây), điều này cho phép nhiều dữ liệu được đệm hơn, từ đó dẫn đến việc chèn lớn hơn và thời gian chèn lâu hơn.

Tôi hy vọng sẽ nhận được một số nhận xét về thiết kế hiện tại và một số ý tưởng chúng tôi phải cải thiện hiệu suất và câu trả lời cho một số câu hỏi của chúng tôi - và bất kỳ lời khuyên nào khác mà mọi người có thể có!

Thiết kế hiện hành

Dữ liệu hiện được phân tách thành các bảng biểu thị một tuần và dữ liệu cũ hơn một năm được lưu trữ vào cơ sở dữ liệu thứ cấp. Toàn bộ mọi thứ được nối với nhau trong một khung nhìn có thể chỉnh sửa, được sử dụng cho cả chèn và đọc.

Thiết kế bảng

  • Id (PK, định danh duy nhất)
  • Thiết bị (FK, int)
  • PersonId (FK, int)
  • XeId (FK, int)
  • TokenId (FK, int)
  • UtcTime (PK, datetime2 (3))
  • Vĩ độ (nổi)
  • Kinh độ (phao)
  • Tốc độ (nhỏ)
  • Tiêu đề (smallint)
  • Vệ tinh (tinyint)
  • IOData (phương sai (100))
  • IgnitionState (tinyint)
  • UserInput (tinyint)
  • CreatTimeUtc (datetime2 (3))

Chỉ số

  • DeviceId_CreateTimeUtc_Desc
  • DeviceId_UtcTime_Desc (Đã nhóm)
  • PersonId_UtcTime_Desc
  • TokenId_UtcTime_Desc
  • XeId_UtcTime_Desc

Mỗi tuần hiện chiếm khoảng 10 GB bao gồm các chỉ số và hiện có khoảng 300 GB dữ liệu trong cơ sở dữ liệu chính.

Các bảng dữ liệu trong cơ sở dữ liệu chính có filegroup riêng với 1 tệp, nhưng nó nằm trên cùng một đĩa với tất cả các bảng khác trong cơ sở dữ liệu chính. Cơ sở dữ liệu thứ cấp nằm trên một đĩa khác, nhưng trên cùng một máy.

Tôi nghĩ rằng chúng tôi cũng đang chạy một công việc xây dựng lại chỉ mục hàng tuần, khi một phân vùng bảng mới (tuần) được sử dụng. Không co lại được thực hiện.

Máy là một HP 8 lõi với bộ nhớ 12 GB và đĩa chứa cơ sở dữ liệu chính đang chạy RAID 10.

Ý tưởng

  • Giới hạn số lượng dữ liệu được lưu trữ trong cơ sở dữ liệu chính là tối đa 1 tháng. Ít nhất nó sẽ làm cho cơ sở dữ liệu dễ quản lý hơn để sao lưu / phục hồi, nhưng chúng ta có thể mong đợi để thấy một sự cải thiện hiệu suất bằng cách làm điều này không?
  • Tạo 2 tệp trong filegroup cho dữ liệu hiện tại và phân phối chúng vào 2 phân vùng vật lý khác nhau
  • Tạo cơ sở dữ liệu chủ-nô chứa dữ liệu hiện tại, do đó việc chèn và đọc được thực hiện trên các cơ sở dữ liệu khác nhau
  • Đặt các tệp cho dữ liệu hiện tại trên các đĩa SSD (việc phản chiếu có làm thay đổi hiệu suất với các ổ SSD không?)

Xin vui lòng cho tôi biết nếu cần thêm thông tin. Có rất nhiều yếu tố ảnh hưởng đến hiệu suất, và có lẽ cũng có nhiều cách để điều chỉnh nó.


Bình luận không dành cho thảo luận mở rộng; cuộc trò chuyện này đã được chuyển sang trò chuyện .
Paul White 9

Câu trả lời:


8

5000 chèn mỗi phút là khoảng 83 chèn mỗi giây. Với 5 chỉ mục đó là 400 hàng vật lý được chèn mỗi giây. Nếu khối lượng công việc nằm trong bộ nhớ thì điều này sẽ không gây ra vấn đề gì ngay cả với các máy chủ nhỏ nhất. Ngay cả khi đây là một lần chèn liên tiếp bằng cách sử dụng cách không hiệu quả nhất mà tôi có thể nghĩ ra. 83 truy vấn tầm thường mỗi giây không thú vị theo quan điểm của CPU.

Có lẽ, bạn bị ràng buộc đĩa. Bạn có thể xác minh điều này bằng cách xem số liệu thống kê chờ hoặc STATISTICS IO.

Các truy vấn của bạn có thể chạm vào rất nhiều trang khác nhau để nhóm bộ đệm không có không gian cho tất cả chúng. Điều này gây ra đọc trang thường xuyên và có thể đĩa ghi ngẫu nhiên là tốt.

Hãy tưởng tượng một bảng mà bạn chỉ chèn vật lý vào cuối vì một khóa ngày càng tăng. Bộ làm việc sẽ là một trang: trang cuối cùng. Điều này sẽ tạo ra IO tuần tự cũng như khi người viết lười biếng hoặc quá trình điểm kiểm tra ghi "kết thúc" của bảng vào đĩa.

Tưởng tượng một bảng có chèn được đặt ngẫu nhiên (ví dụ cổ điển: khóa hướng dẫn). Ở đây, tất cả các trang là tập làm việc vì một trang ngẫu nhiên sẽ được chạm vào cho mỗi lần chèn. IO là ngẫu nhiên. Đây là trường hợp xấu nhất khi nói đến thiết lập làm việc.

Bạn đang ở giữa. Các chỉ mục của bạn là của cấu trúc (SomeValue, SequentialDateTime). Thành phần đầu tiên ngẫu nhiên một phần tính tuần tự được cung cấp bởi phần thứ hai. Tôi đoán có khá nhiều giá trị có thể cho " SomeValue" để bạn có nhiều điểm chèn được đặt ngẫu nhiên trong các chỉ mục của mình.

Bạn nói rằng dữ liệu được chia thành các bảng 10 GB mỗi tuần. Đó là một điểm khởi đầu tốt vì bộ công việc hiện bị giới hạn bởi 10GB (không tính đến bất kỳ lần đọc nào bạn có thể làm). Tuy nhiên, với 12GB bộ nhớ máy chủ, không chắc là tất cả các trang có liên quan đều có thể nằm trong bộ nhớ.

Nếu bạn có thể giảm kích thước của "phân vùng" hàng tuần hoặc tăng bộ nhớ máy chủ thêm một chút thì có lẽ bạn vẫn ổn.

Tôi hy vọng rằng việc chèn vào đầu tuần sẽ nhanh hơn vào cuối tuần. Bạn có thể kiểm tra lý thuyết này trên máy chủ dev bằng cách chạy điểm chuẩn với kích thước dữ liệu nhất định và giảm dần bộ nhớ máy chủ cho đến khi bạn thấy bể hiệu suất.

Bây giờ ngay cả khi tất cả các lần đọc và ghi phù hợp với bộ nhớ, bạn vẫn có thể có IO bẩn trang ngẫu nhiên. Cách duy nhất để thoát khỏi điều đó là viết vào các vị trí đồng vị trí trong các chỉ mục của bạn. Nếu bạn hoàn toàn có thể chuyển đổi các chỉ mục của mình để sử dụng (nhiều hơn) các khóa liên tiếp sẽ giúp ích rất nhiều.

Như một giải pháp nhanh chóng, tôi sẽ thêm một lớp đệm giữa các máy khách và bảng chính. Có thể tích lũy 15 phút viết vào một bảng dàn dựng và định kỳ xả nó. Điều đó lấy đi các gai tải và sử dụng một kế hoạch hiệu quả hơn để ghi vào bảng lớn.


1
@usr Cảm ơn câu trả lời rất toàn diện và được giải thích rõ ràng! Chúng tôi đã thực sự thảo luận về việc tăng bộ nhớ máy chủ, mà không biết nó sẽ có tác dụng như thế nào - nhưng bây giờ chúng tôi thực sự có một lý do rất thuyết phục để làm như vậy :) Bạn đã đúng rằng "Một số giá trị" ngẫu nhiên một phần các điểm chèn - có lẽ có khoảng 10000 id thiết bị. Về bảng phân tầng, đề xuất của bạn có phải là bảng không có bất kỳ chỉ số nào không, và sau đó một công việc để chèn vào bảng chính cứ sau X phút?
sondergard

@usr Reg. đề xuất của bạn để chuyển đổi chỉ mục được nhóm thành tuần tự, chúng tôi có thể thêm tự động inc. cột định danh (số nguyên) và thay đổi chỉ mục được nhóm thành cột này cho mục đích duy nhất là giữ cho nó tuần tự? Nó sẽ không phải là duy nhất trên các bảng, nhưng miễn là khóa chính là, chúng ta sẽ ổn.
sondergard

1
Nếu bảng phân tầng nhỏ và các truy vấn của bạn có thể tồn tại với nó thì bạn không cần phải lập chỉ mục. Nhưng bạn có thể.; Một chiến lược sẽ là tạo CI trên một cột nhận dạng (như bạn nói). Điều này có thể làm việc kỳ diệu nếu CI lớn và các chỉ số khác nhỏ. Bởi vì các CI được viết hiện đang tuần tự, chúng đóng góp ít hơn nhiều cho vấn đề của bạn. Chiến lược này là thành công nhất nếu có sự khác biệt về kích thước có ý nghĩa.; Một ý tưởng khác là có một bàn mỗi ngày. Có thể hợp nhất hàng tháng.
usr

Ok, vì vậy chúng tôi đã xem xét việc tạo cột nhận dạng cho CI, nhưng thật không may, không thể xem trên chế độ xem chia tay (không cho phép cột nhận dạng, không có giá trị mặc định và tất cả các cột phải được đưa vào chèn). Có thể quan điểm chia tay là một thiết kế được lựa chọn kém, mặc dù nó được khuyến nghị bởi một chuyên gia tư vấn
sondergard

2
Nghiêm túc mà nói, đối với bất kỳ ai gặp phải vấn đề tương tự, nếu bạn có nhiều bài viết và chỉ một vài lần đọc, bạn thực sự muốn nối thêm vào cuối và trì hoãn bất kỳ lập chỉ mục nào. Mặt khác, nếu bạn muốn đọc nhanh và không quan tâm mất bao lâu để chèn, bạn cần một chỉ mục được nhóm.
tiktak
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.