Lưu trữ nhiều thẻ trên cơ sở dữ liệu phân tích


7

Tôi muốn lưu trữ thẻ tùy chỉnh mua của người dùng trên mỗi giao dịch, ví dụ: nếu người dùng đã mua giày thì thẻ là "SPORTS", "NIKE", SHOES, COLOUR_BLACK, SIZE_12,..

Các thẻ này là người bán quan tâm truy vấn trở lại để hiểu doanh số.

Ý tưởng của tôi là khi bao giờ thẻ mới xuất hiện tạo mã mới (giống như mã băm nhưng tuần tự) cho thẻ đó và mã bắt đầu từ "a-z"26 chữ cái sau đó "aa, ab, ac...zz"tiếp tục. Bây giờ giữ tất cả các thẻ được cung cấp cho một giao dịch trong một cột được gọi tag (varchar)bằng cách tách bằng "|".

Chúng ta hãy giả sử ánh xạ là (ở cấp ứng dụng)

"SPORTS" = a
"TENNIS" = b
"CRICKET" = c
...
...
"NIKE"  = z        //Brands company
"ADIDAS" = aa
"WOODLAND" = ab
...
...
SHOES   = ay
...
...
COLOUR_BLACK = bc
COLOUR_RED = bd
COLOUR_BLUE = be
...
SIZE_12 = cq
...

Vì vậy, lưu trữ giao dịch mua hàng ở trên, thẻ sẽ giống như tag="|a|z|ay|bc|cq|"Và bây giờ cho phép người bán tìm kiếm số lượng GIÀY được bán bằng cách thêm WHEREđiều kiện tag LIKE %|ay|%. Bây giờ vấn đề là tôi không thể sử dụng chỉ mục (khóa sắp xếp trong db dịch chuyển đỏ) cho "THÍCH bắt đầu bằng%". Vậy làm thế nào để giải quyết vấn đề này, vì tôi có thể có 100 triệu hồ sơ? không muốn quét toàn bộ bảng ..

giải pháp nào để khắc phục điều này?

Update_1: Tôi chưa theo bridge tablekhái niệm (bảng tham chiếu chéo) vì tôi muốn thực hiện nhóm theo kết quả sau khi tìm kiếm các thẻ được chỉ định. Giải pháp của tôi sẽ chỉ cung cấp một hàng khi hai thẻ khớp trong một giao dịch, nhưng bảng cầu sẽ cho tôi hai hàng? thì tổng của tôi () sẽ được nhân đôi.

Tôi có đề nghị như dưới đây

EXISTS (CHỌN 1 TỪ giao dịch_tag WHERE tag_id = 'zz' và trans_id = tr.trans_id) trong mệnh đề WHERE một lần cho mỗi thẻ (lưu ý: giả sử tr là bí danh cho bảng giao dịch trong truy vấn xung quanh)

Tôi đã không theo dõi điều này; vì tôi phải thực hiện điều kiện AND và OR trên các thẻ, ví dụ ("THỂ THAO" VÀ "ADIDAS") ---- "GIÀY" VÀ ("NIKE" HOẶC "ADIDAS")

Update_2: Tôi chưa theo dõi bitfield, vì không biết redshift có hỗ trợ này không. Tôi giả sử nếu hệ thống của tôi sẽ có tối thiểu 3500 thẻ và phân bổ một bit cho mỗi thẻ; dẫn đến 437 byte cho mỗi giao dịch, mặc dù sẽ chỉ có tối đa 5 thẻ có thể được cung cấp cho một giao dịch. Bất kỳ tối ưu hóa ở đây?

Giải pháp_1:

Tôi đã nghĩ đến việc thêm min (SMALL_INT) và giá trị tối đa (SMALL_INT) cùng với cột thẻ và áp dụng chỉ mục trên đó.

một cái gì đó như thế này

"SPORTS" = a = 1
"TENNIS" = b = 2
"CRICKET" = c = 3
...
...
"NIKE"  = z  = 26
"ADIDAS" = aa = 27

Vì vậy, giá trị cột của tôi là

`tag="|a|z|ay|bc|cq|"` //sorted?
`minTag=1`
`maxTag=95` //for cq

Và truy vấn để tìm kiếm giày (ay = 51) là

maxTag <= 51 AND tag LIKE %|ay|%

Và truy vấn để tìm kiếm giày (ay = 51) VÀ SIZE_12 (cq = 95) là

minTag >= 51 AND maxTag <= 95 AND tag LIKE %|ay|%|cq|%

Điều này sẽ mang lại lợi ích gì? Vui lòng đề nghị bất kỳ lựa chọn thay thế.


2
Bạn đã xem xét một transaction_tagbảng, liên kết transactiontagtrong một mối quan hệ nhiều-nhiều? Theo nguyên tắc chung, hiệu suất khôn ngoan, lưu trữ nhiều giá trị dưới dạng văn bản được phân tách đơn giản trong một cột là một ý tưởng tồi.
RDFozz

@RDFozz Tôi muốn thực hiện nhóm theo kết quả sau khi tìm kiếm các thẻ được chỉ định. Giải pháp của tôi sẽ chỉ cung cấp một hàng khi hai thẻ khớp trong một giao dịch, nhưng bảng cầu sẽ cho tôi hai hàng? thì tổng của tôi () sẽ được nhân đôi. giải pháp nào để khắc phục điều này?
Kanagavelu Sugumar

@RDFozz Ngoài ra tôi không lưu trữ giá trị thực, chỉ mã hóa giá trị (tối đa 2 ký tự) tối đa 5 thẻ -> vì vậy 10 ký tự + 6 ký tự (dấu phân cách). Tôi nghĩ rằng đó là cột đơn giản với varchar (16) và điều đó được xác nhận đối với toán tử THÍCH. Nhưng bảng cầu sẽ thực hiện tìm kiếm dựa trên "5 lần * số hàng thực tế", tôi nghĩ ở đây cần thêm RAM sau khi tham gia.
Kanagavelu Sugumar

@RDFozz Nếu bạn đang bận, xin vui lòng xóa downvote của bạn, để tôi sẽ nhận được một số câu trả lời từ người khác.
Kanagavelu Sugumar

Có thể loại bỏ giá trị nhân bản bởi một trong hai INNER JOINđể transaction_tagmột lần cho mỗi thẻ được yêu cầu, hoặc sử dụng EXISTS (SELECT 1 FROM transaction_tag WHERE tag_id = 'zz' and trans_id = tr.trans_id)trong các WHEREđiều khoản một lần cho mỗi thẻ (lưu ý: giả tr là một bí danh cho các transactionbảng trong truy vấn xung quanh).
RDFozz

Câu trả lời:


5

Tôi vẫn tin rằng sử dụng bảng tra cứu nhiều-nhiều (bảng cầu) vẫn là lựa chọn tốt nhất của bạn ở đây. Mối quan tâm của bạn về việc khớp nhiều hàng có thể được khắc phục bằng thiết kế truy vấn phù hợp. Giả sử các bảng của bạn là:

CREATE TABLE purchases(PurchaseID,CustomerID,PurchaseDate,...)
CREATE TABLE tags(TagID,TagType,TagName)
CREATE TABLE purchasetags(PurchaseID,TagID)

Vì vậy, mỗi lần mua có thể có nhiều thẻ được đặt (không giới hạn) và để giải trí, tôi đã thêm khả năng phân loại các thẻ theo TagType , có thể chứa những thứ như "ProductType", "Brand", "Color", "Sport", vì vậy bạn có cách để nói rằng "giày" là thẻ "ProductType", "Nike" là thẻ thương hiệu và "bóng đá" là thẻ thể thao .

Sau đó, nếu bạn muốn truy vấn (và chỉ trả về các hàng đơn), chỉ cần làm:

SELECT *
FROM purchases 
WHERE PurchaseID IN (SELECT pt.PurchaseID 
                     FROM purchasetag pt
                     INNER JOIN tags t ON pt.TagID=t.TagID
                     WHERE t.TagName IN ('Adidas','Nike'))
GROUP BY whatever...

Nếu bạn cần thực hiện tìm kiếm kết hợp fancier (tìm mua giày Nike hoặc giày Adidas , truy vấn của bạn cũng sẽ phải là fancier:

SELECT *
FROM purchases 
WHERE PurchaseID IN (SELECT pt.PurchaseID 
                     FROM purchasetag pt
                     INNER JOIN tags t ON pt.TagID=t.TagID
                     WHERE t.TagName = 'Shoes')
AND   PurchaseID IN (SELECT pt.PurchaseID 
                     FROM purchasetag pt
                     INNER JOIN tags t ON pt.TagID=t.TagID
                     WHERE t.TagName IN ('Adidas','Nike'))

Một lần nữa, điều đó vẫn trả về một hàng cho mỗi lần mua phù hợp với kết hợp thẻ mong muốn của bạn.


Cộng với một. Cảm ơn rât nhiều! Hãy để tôi thử điều này và sẽ lấy lại cho bạn !!
Kanagavelu Sugumar

Tôi không chấp nhận câu trả lời này vì truy vấn IN có nhiều ID có tác động đến hiệu suất.
Kanagavelu Sugumar

2

Cách thông thường để giải quyết vấn đề như vậy, là sử dụng bitfield .

Vì vậy, bạn sẽ tạo một bảng thẻ và liên kết thông qua bảng n: m với các số liệu hoặc sản phẩm bán hàng. Sau đó, trong bảng thẻ, đối với mỗi thẻ bạn sẽ gán một bitvalue độc đáo như một sức mạnh của 2, ví dụ như 1, 2, 4, 8, ..., 1024, 2048, ...cho sports, tennis, cricket, ...và vân vân.

Sử dụng bit_orthì bạn có thể ngưng tụ những giá trị này thành một giá trị số duy nhất và lưu trữ này cùng với các số liệu về sản phẩm hoặc bán hàng. Ví dụ: thẻ "thể thao" và "cricket" trên một sản phẩm trở thành 5.

Nếu kích thước bit của loại số bạn có sẵn không đủ để lưu trữ tất cả các thẻ của bạn, hãy sử dụng nhiều trường này và lưu trữ số hoặc tên cột của trường và bitvalue với thẻ.

Sau đó, để truy vấn sử dụng mệnh đề có dạng:

flags & 1024 = 1024 hoặc flags & 1024 <> 0= bộ cờ thứ 10

Bây giờ bạn có thể thực hiện bất kỳ biểu thức Boolean nào trên các cờ. Nếu bạn chỉ định một trường duy nhất cho tất cả các màu, bạn cũng có thể thực hiện các thủ thuật khác, như truy vấn các sản phẩm có thẻ Màu: colorflags <> 0v.v.

Vì bạn đang ở trong cơ sở dữ liệu hướng theo cột (dịch chuyển đỏ), &chỉ được thực hiện một lần cho mỗi giá trị duy nhất trong cột. Tùy thuộc vào việc triển khai, cơ sở dữ liệu sẽ giảm thêm điều này, bằng cách phân tích các &ràng buộc và sử dụng các ràng buộc về kích thước thông qua thứ tự sắp xếp các giá trị cột (miễn phí).

Và nếu bạn cần chút hiệu suất cuối cùng đó, bạn có thể thực hiện các thủ thuật bằng cách thu thập số liệu thống kê về các cờ và các truy vấn và nhóm chúng lại với nhau một cách thông minh. Tôi hy vọng trong trường hợp sử dụng mà bạn mô tả (thực hiện tổng ... nhóm sau khi lọc), hiệu suất mà bạn có thể đạt được thông qua điều này, sẽ không đáng kể so với chi phí tính toán.


1

Những cái bàn

brand 
ID
Name  

size 
ID
name  

color 
ID 
name  

customer 
ID 
Name  

purchase 
ID
customerID
date 

purchaseDetail 
purchaseID  
brandID 
sizeID 
colorID

Bạn cần buyDetail để liên kết tất cả các thẻ với mục

select * 
from purchase 
join purchaseDetail 
  on purchase.ID = purchaseDetail.purchaseID 
join brand 
  on brand.ID    = purchaseDetail.brandID 
 and brand.Name in ('Nike', 'Adidas')
join size 
  on size.ID     = purchaseDetail.sizeID
join color 
  on color.ID    = purchaseDetail.colorID 
 and color.Name = 'black' 

cộng với một. Cảm ơn! Tôi sẽ thử nó, và lấy lại cho bạn!
Kanagavelu Sugumar
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.