Những cách có thể để tránh trùng lặp khi bạn không thể thêm một chỉ mục duy nhất


10

Tôi bị mắc kẹt trong một vấn đề tương tranh.

Là một vấn đề điển hình trong đó người dùng gửi 2 o 3 giao dịch để duy trì một số dữ liệu KHÔNG NÊN được sao chép trong DB, trong trường hợp bản ghi trùng lặp, bạn sẽ trả về lỗi.

Vấn đề này rất dễ dàng khi bạn chỉ có thể thêm một chỉ mục (duy nhất) vào một cột nơi bạn lưu trữ hàm băm.

Nhưng trong trường hợp này, tôi có một bảng rất lớn (có thể là hàng triệu bản ghi) và tôi không thể sửa đổi bảng.

Trên thực tế, chúng tôi có một cột nơi chúng tôi lưu trữ dữ liệu băm không được sao chép nhưng chỉ mục duy nhất không được đặt.

Tôi đang thử mã java của mình để kiểm tra xem có tồn tại ngay trước khi tuôn ra không, vẫn nhận được các bản sao.

Các giải pháp khả thi của tôi cho việc này là:

  • Tạo một trình kích hoạt để kiểm tra xem hàm băm mà tôi đang cố gắng chèn đã tồn tại trên bảng chưa.
  • Tạo một bảng khác để lưu các chỉ mục duy nhất cho bảng này và thêm khóa ngoại vào bảng chính.
  • Ngồi vào vị trí của thai nhi và khóc

Là kiểm tra của bạn về băm không thành công do va chạm băm hoặc một lỗi trong kiểm tra?
candied_orange

4
Tôi không nhận được câu hỏi của bạn. Vì vậy, thay vì lập chỉ mục một lần cho tất cả bảng khổng lồ của bạn với hàng triệu bản ghi, bạn thích đọc cho mỗi triệu bản ghi tiếp theo mà bạn sẽ thêm, hàng triệu bản hiện có để tìm kiếm gấp đôi? hoặc sao chép một số thông tin và thêm tham gia để thực hiện kiểm tra của bạn?
Christophe

Vấn đề là, để thực hiện thay đổi này, tôi đã được cảnh báo rằng chúng tôi cần nhiều không gian và thời gian ngừng hoạt động lâu dài cho dịch vụ của chúng tôi, để đáp ứng một số yêu cầu dịch vụ của chúng tôi không thể ngừng hơn 2 giờ mỗi tháng. Tôi biết cách tốt nhất là thực hiện bảo trì trên bảng này, nhưng là điều tôi không thể làm vào lúc này, vì vậy chúng tôi cần một cách giải quyết.
rafuru

4
Tôi không hiểu điều đó - tại sao việc thêm một trình kích hoạt hoặc thêm một bảng khác để "mô phỏng" một chỉ mục mất ít thời gian chết hơn là chỉ thêm một chỉ mục vào bảng hiện có?
Doc Brown

2
@rafuru: ai nói bạn cần tạo một chỉ mục duy nhất? Một chỉ mục tiêu chuẩn, không duy nhất có thể sẽ là tất cả những gì bạn cần để nhanh chóng tìm thấy tất cả các hàng có cùng giá trị băm.
Doc Brown

Câu trả lời:


3

Có một vài tình huống có thể dễ giải quyết và một tình huống nguy hiểm không xảy ra.

Đối với người dùng nhập một giá trị, sau đó nhập cùng một giá trị sau đó một CHỌN đơn giản trước khi INSERT sẽ phát hiện vấn đề. Điều này hoạt động trong trường hợp một người dùng gửi một giá trị và một thời gian sau, một người dùng khác gửi cùng một giá trị.

Nếu người dùng gửi danh sách các giá trị có trùng lặp - giả sử {ABC, DEF, ABC} - trong một lần gọi mã, ứng dụng có thể phát hiện và lọc các bản sao, có thể gây ra lỗi. Bạn cũng cần kiểm tra DB không chứa bất kỳ giá trị duy nhất nào trước khi chèn.

Kịch bản khó khăn là khi một người viết viết bên trong DBMS cùng lúc với người viết khác và họ đang viết cùng một giá trị. Sau đó, bạn có một cuộc đua một điều kiện giữa họ. Vì DBMS (rất có thể - bạn không nói bạn đang sử dụng hệ thống nào), một hệ thống đa nhiệm được ưu tiên, bất kỳ nhiệm vụ nào cũng có thể bị tạm dừng tại bất kỳ thời điểm nào trong quá trình thực thi. Điều đó có nghĩa là tác vụ của user1 có thể kiểm tra không có hàng nào hiện có, sau đó tác vụ của user2 có thể kiểm tra không có hàng nào tồn tại, sau đó tác vụ của user1 có thể chèn hàng đó, sau đó tác vụ của user2 có thể chèn hàng đó. Tại mỗi thời điểm, các nhiệm vụ đều hạnh phúc riêng lẻ, họ đang làm điều đúng đắn. Trên toàn cầu, một lỗi xảy ra.

Thông thường, một DBMS sẽ xử lý việc này bằng cách khóa một giá trị trong câu hỏi. Trong vấn đề này, bạn đang tạo một hàng mới để không có gì để khóa. Câu trả lời là một khóa phạm vi. Vì nó cho thấy điều này khóa một loạt các giá trị, cho dù chúng có tồn tại hay không. Khi khóa, phạm vi đó không thể được truy cập bởi một tác vụ khác cho đến khi khóa được giải phóng. Để có được khóa phạm vi, bạn phải chỉ định và mức cô lập SERIALIZABLE . Hiện tượng một nhiệm vụ khác lẻn vào một hàng sau khi nhiệm vụ của bạn đã được kiểm tra được gọi là các bản ghi ảo .

Đặt mức cô lập thành Nối tiếp trên toàn bộ ứng dụng sẽ có ý nghĩa. Thông lượng sẽ được giảm. Các điều kiện chủng tộc khác hoạt động đủ tốt trong quá khứ có thể bắt đầu hiển thị lỗi ngay bây giờ. Tôi sẽ đề nghị thiết lập nó trên kết nối thực thi mã tạo ra trùng lặp của bạn và để lại phần còn lại của ứng dụng.

Một thay thế dựa trên mã là để kiểm tra sau khi viết chứ không phải trước đó. Vì vậy, thực hiện INSERT, sau đó đếm số lượng hàng có giá trị băm đó. Nếu có trùng lặp rollback hành động. Điều này có thể có một số kết quả đồi trụy. Nói tác vụ 1 viết rồi tác vụ 2. Sau đó, nhiệm vụ 1 kiểm tra và tìm một bản sao. Nó quay trở lại mặc dù là lần đầu tiên. Tương tự, cả hai tác vụ có thể phát hiện trùng lặp và cả rollback. Nhưng ít nhất bạn sẽ có một thông điệp để làm việc, một cơ chế thử lại và không có bản sao mới. Rollback được nhăn mặt, giống như sử dụng các ngoại lệ để kiểm soát dòng chương trình. Lưu ý rằng tất cảcông việc trong giao dịch sẽ được khôi phục, không chỉ là việc viết trùng lặp. Và bạn sẽ phải có các giao dịch rõ ràng có thể làm giảm sự tương tranh. Kiểm tra trùng lặp sẽ chậm khủng khiếp trừ khi bạn có một chỉ mục trên hàm băm. Nếu bạn làm bạn cũng có thể làm cho nó một duy nhất!

Như bạn đã nhận xét, giải pháp thực sự là một chỉ số duy nhất. Dường như với tôi như thế này sẽ phù hợp với cửa sổ bảo trì của bạn (mặc dù tất nhiên bạn biết rõ hệ thống của mình nhất). Nói băm là tám byte. Đối với một trăm triệu hàng khoảng 1GB. Kinh nghiệm cho thấy một chút phần cứng hợp lý sẽ xử lý nhiều hàng này trong một hoặc hai phút. Kiểm tra và loại bỏ trùng lặp sẽ thêm vào điều này, nhưng có thể được viết kịch bản trước. Đây chỉ là một bên, mặc dù.


2

Trên thực tế, chúng tôi có một cột nơi chúng tôi lưu trữ dữ liệu băm không được sao chép nhưng chỉ mục duy nhất không được đặt.

Kiểm tra va chạm băm là bước đầu tiên tốt, nhưng hãy cẩn thận, bạn không thể đảm bảo cùng một chương trình sẽ tạo ra cùng một hàm băm trên cùng một dữ liệu nếu nó được khởi động lại . Nhiều hàm băm "nhanh" sử dụng một prng sẵn có được khởi tạo tại thời điểm bắt đầu chương trình. Sử dụng hàm băm mật mã nếu hàm băm cần phải luôn giống nhau cho dù bạn có làm gì trong ứng dụng này. Lưu ý rằng bạn không cần băm mật mã tốt hoặc an toàn.

Bước thứ hai là thực sự kiểm tra sự bình đẳng dữ liệu, vì ngay cả các hàm băm tốt nhất đôi khi cũng sẽ dẫn đến xung đột, vì bạn (thường) giảm entropy của dữ liệu của bạn.

Vì thế:

Bước 1: kiểm tra xem bạn có va chạm vào hàm băm mật mã không

Bước 2: nếu băm khớp, kiểm tra dữ liệu thực tế có giống nhau không


Tôi không thấy làm thế nào điều này trả lời câu hỏi. Giả sử trong giây lát, cột băm có sẵn được lấp đầy bởi hàm băm xác định (nếu không mọi nỗ lực sử dụng nó sẽ không có ý nghĩa). Theo hiểu biết của tôi, vấn đề là không có chỉ mục trên cột băm đó trong cơ sở dữ liệu, vì vậy ngay cả bước đầu tiên trong câu trả lời của bạn - kiểm tra xem có xung đột hay không - vẫn sẽ yêu cầu quét toàn bộ bảng cho mỗi bản ghi mới trên bảng với vài triệu hồ sơ, có thể sẽ trở nên quá chậm.
Doc Brown

Đó là điều tốt nhất bạn có thể làm mà không cần tạo chỉ mục, đó là những gì câu hỏi đang hỏi. Quét băm ít nhất có nghĩa là bạn chỉ phải kiểm tra một cột, nhanh hơn nhiều so với kiểm tra tuy nhiên nhiều cột họ sẽ phải kiểm tra.
Turksarama

Tôi khá chắc chắn, ngay cả khi không thể tạo chỉ mục (trong trường hợp này có thể là như vậy), đề xuất ban đầu của OP là " tạo một bảng khác để lưu trữ các chỉ mục duy nhất cho bảng này và thêm khóa ngoại vào bảng chính ". Ý nghĩa hơn.
Doc Brown

Băm xác định và băm mật mã là hai khái niệm trực giao phải không? băm mật mã có thể không mang tính xác định và ngược lại, băm xác định rất có thể không có sức mạnh về mật mã.
Newtopian

Chúng không giống nhau, nhưng chúng cũng không trực giao. Băm mật mã là một tập hợp con của băm xác định, nhưng không ai thực sự bận tâm thực hiện băm xác định không mã hóa trừ khi bạn đặc biệt muốn nó có thể đảo ngược vì một số lý do.
Turksarama

2

Tạo một bảng mới với khóa chính duy nhất

Về phía khách hàng bắt đầu tạo GUID cho mỗi bản ghi để bạn có thể phát hiện các lần gửi lại đơn giản.

Đặt các bản ghi mới vào bảng mới để ít nhất bạn có lợi cho dữ liệu mới.

Có một cột trong bảng mới "CheckedAgainstOldData"

Có một nhiệm vụ phụ trợ, thực hiện bất cứ điều gì bạn kiểm tra băm chậm hiện tại là xem liệu nó có thể tìm thấy một bản sao trong dữ liệu cũ hay không và đặt cờ phù hợp, từ chối trùng lặp tại thời điểm này, Gửi thông báo lại cho khách hàng.

Trong khi đó, có một tác vụ phụ trợ khác giúp chuyển dữ liệu từ bảng cũ sang bảng mới, kiểm tra các bản sao với kiểm tra băm của bạn và tạo GUID.

Bạn có thể để nhiệm vụ này chạy trong vài ngày (nếu cần), chuyển dữ liệu qua mà không có thời gian chết.

Khi quá trình chuyển hoàn tất, bạn có thể tắt quá trình "CheckedAgainstOldData" chậm. và chuyển tất cả dữ liệu vào một bảng duy nhất.

Thành thật mà nói nếu vấn đề tồi tệ như bạn mô tả và phần mềm đã cũ, thì bạn sẽ có hàng ngàn bản sao.


1

Giả sử rằng dữ liệu đến từ "người dùng" có nghĩa là ai đó đang ngồi trên bàn phím và các bản sao phát sinh từ hai người dùng nhập cùng một dữ liệu vào cùng một thời điểm. Hãy thử thêm vào một hàm gây ra độ trễ ngẫu nhiên khi bắt đầu kích hoạt. Tuy nhiên, hãy dành tối thiểu thời gian để viết một bản ghi mới vào bảng và có thể là tối đa không quá một nanocury hoặc hơn thế. Theo cách đó, khi bạn nhận được các yêu cầu lừa đảo, yêu cầu đầu tiên sẽ được thực hiện và trình kích hoạt tồn tại sẽ đưa ra kết quả chính xác. (Làm rõ: mỗi cuộc gọi nên có thời gian trễ ngẫu nhiên duy nhất của riêng mình, cùng với các nguyên tắc giống như giao thức ALOHA )

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.