Truy vấn được đề xuất của bạn dường như hoạt động; xem this SQLFiddle demo. Nó tạo ra sự phân phối sai mặc dù; xem bên dưới.
Để ngăn PostgreSQL tối ưu hóa truy vấn con tôi đã gói nó trong hàm SQL VOLATILE
. PostgreSQL không có cách nào để biết rằng bạn có ý định truy vấn con chạy một lần cho mỗi hàng của truy vấn bên ngoài, vì vậy nếu bạn không ép nó biến động, nó sẽ thực thi nó một lần. Một khả năng khác - mặc dù một khả năng mà trình hoạch định truy vấn có thể tối ưu hóa trong tương lai - là làm cho nó xuất hiện như một truy vấn con tương quan, như hack này sử dụng mệnh đề where-true, như sau: http://sqlfiddle.com/#!12/3039b/9
Khi đoán (trước khi bạn cập nhật để giải thích lý do tại sao nó không hoạt động) phương pháp thử nghiệm của bạn bị lỗi hoặc bạn đang sử dụng phương thức này làm truy vấn con trong truy vấn bên ngoài, nơi PostgreSQL nhận thấy đó không phải là truy vấn con tương quan và thực thi nó một lần , như trong số this example. .
CẬP NHẬT: Bản phân phối được tạo ra không phải là những gì bạn mong đợi. Vấn đề ở đây là bạn đang lệch phân phối bằng cách lấy nhiều mẫu trong số random()
; bạn cần mẫu đơn.
truy vấn này tạo ra sự phân bố chính xác (SQLFiddle):
WITH random_weight(rw) AS (SELECT random() * (SELECT sum(percent) FROM test))
SELECT id
FROM (
SELECT
id,
sum(percent) OVER (ORDER BY id),
coalesce(sum(prev_percent) OVER (ORDER BY id),0) FROM (
SELECT
id,
percent,
lag(percent) OVER() AS prev_percent
FROM test
) x
) weighted_ids(id, weight_upper, weight_lower)
CROSS JOIN random_weight
WHERE rw BETWEEN weight_lower AND weight_upper;
Hiệu suất là, không cần phải nói, khủng khiếp. Nó sử dụng hai bộ cửa sổ lồng nhau. Những gì tôi đang làm là:
- Tạo (id, percent, previous_percent) sau đó sử dụng để tạo hai số tiền chạy được sử dụng làm dấu ngoặc; sau đó
- Lấy một giá trị ngẫu nhiên, nhân rộng nó vào phạm vi của trọng lượng, và sau đó chọn một giá trị mà có trọng lượng trong khung mục tiêu
Nguồn
2012-10-23 22:44:09
Ý của bạn là gì do kết quả sai? –
@Clodoaldo, sau 10k lượt truy vấn ở trên tôi nhận được kết quả tiếp theo (vị trí cần đếm): {1 = 6293, 2 = 3302, 3 = 405}, nhưng tôi hy vọng chúng gần giống như sau: {1 = 5000, 2 = 3500, 3 = 1500}. –
@OlegGolovanov OK, vì vậy truy vấn hoạt động, nhưng phân phối là sai. –