2013-05-27 45 views
6

Tôi có một danh sách các tiền tố số điện thoại được xác định cho số lượng lớn các vùng (trong truy vấn được xác định bởi gvcode và cgi). Tôi cần tìm một tiền tố dài nhất phù hợp với số lượng PHONE_NR đã cho.Cách nhanh nhất để tìm kiếm tiền tố dài nhất trong ORACLE

Tôi sử dụng mệnh đề LIKE ngược trên các chữ số trường (có chứa tiền tố ở dạng + 48%, + 49%, + 1%, + 1232% v.v.).

Vì vậy, tôi không thể sử dụng chỉ mục bình thường trên trường đó.

Tôi đã xoay sở để cải thiện đáng kể bằng cách sử dụng IOT trên trường gvcode và cgi (là một phần (hai cột đầu tiên) của khóa chính). Tôi cũng xem xét một số chỉ mục văn bản oracle nhưng không thể tìm thấy một trong đó sẽ phù hợp với đầu vào dài hơn với tiền tố ngắn hơn trong bảng.

Có cách nào khác để thực hiện tìm kiếm nhanh hơn phương pháp này hay không.

Đây là truy vấn cung cấp danh sách tất cả các tiền tố phù hợp (sau đó tôi sắp xếp nó theo chiều dài chữ số).

select t.gvcode, t.digits 
       from NUMBERS t 
        where 
         t.gvcode=ZONE_SET_CODE 
         and t.cgi=cgi_f 
         and (PHONE_NR like t.digits) 
         order by length(digits) desc 
+0

Có thể nếu bạn tạo chỉ mục dựa trên hàm trên 'substr (chữ số, 2, độ dài (chữ số) -1)' và sau đó thêm vào truy vấn của bạn ở đó mệnh đề điều kiện khác 'và substr (chữ số, 2, length (digit) -1) <= PHONE_NR' bạn có thể thấy một số cải thiện trong một số trường hợp –

+0

Nên là 'và substr (chữ số, 1, chiều dài (chữ số) -1) <= PHONE_NR' (không cần phải xóa '+') –

Trả lời

1

Ngoài chỉ mục trên "chữ số", bạn có thể tạo chỉ mục trên rpad(substr(digits,1,length(digits)-1), 10, '9'). "10" là độ dài tối đa bạn muốn hỗ trợ.Bạn sẽ thêm một điều kiện bổ sung cho các mệnh đề where: rpad(substr(digits,1,length(digits)-1), 10, '9') >= PHONE_NR

SQL của bạn sẽ là:

select t.gvcode, t.digits 
from NUMBERS t 
    where 
     t.gvcode=ZONE_SET_CODE 
     and t.cgi=cgi_f 
     and PHONE_NR like t.digits 
     and substr(digits, 1, length(digits)-1) <= PHONE_NR 
     and rpad(substr(digits,1,length(digits)-1), 10, '9') >= PHONE_NR 
order by length(digits) desc 

Dưới đây là một ví dụ trong sqlfiddle

0

Tôi không chắc chắn điều này có thực sự hữu ích hay không, nhưng tôi nghĩ bạn nên thử.

Tạo một Function Index Dựa trên substr(digits, 1, length(digits)-1) (điều này chỉ là một con số chỉ số mà không có sự '%')

Sau đó, trong truy vấn của bạn, bạn có thể thêm điều kiện khác:

AND substr(digits, 1, length(digits)-1) <= PHONE_NR 

Here is a sqlfiddle demo

Ý tưởng là với lexical so sánh, bạn có thể "cắt bỏ" tất cả các chữ số sau PHONE_NR

1

tôi có vẻ ngu ngốc, nhưng khi tôi chạy vào vấn đề như vậy tôi đã đi ở hầu hết các phi không gian hiệu quả brute force cách:

phép nói rằng:

L=length of longest prefix to match (without obvious +, of course) 

Thêm L trường bổ sung đặt tên cho chúng, ví dụ , P1, P2,...,PL

cập nhật những lĩnh vực với

UPDATE NUMBERS set P1=SUBSTR(PHONE_NR,1,1), P2=SUBSTR(PHONE_NR,1,2), ..., PL=SUBSTR(PHONE_NR,1,L) 

(trong tương lai bạn có thể làm điều này trong 01.kích hoạt quá)

Bây giờ bạn có L trường để tạo chỉ mục và so sánh với bất kỳ thứ gì bạn thích.

0

Được rồi, chỉ cần viết vì tôi đã có cùng một vấn đề. Nếu bạn biết phạm vi của độ dài tiền tố bạn có, bạn có thể làm điều gì đó tương tự như sau. Ví dụ sau đây giả định tiền tố độ dài 2-6

select t.num, coalesce(p6.PREFIX, p5.PREFIX, p4.PREFIX, p3.PREFIX, p2.PREFIX) PREFIX 
    from NUMBERS t 
LEFT OUTER JOIN PREFIXES p2 ON substr(t.num,1,2)=p2.PREFIX 
LEFT OUTER JOIN PREFIXES p3 ON substr(t.num,1,3)=p3.PREFIX 
LEFT OUTER JOIN PREFIXES p4 ON substr(t.num,1,4)=p4.PREFIX 
LEFT OUTER JOIN PREFIXES p5 ON substr(t.num,1,5)=p5.PREFIX 
LEFT OUTER JOIN PREFIXES p6 ON substr(t.num,1,6)=p6.PREFIX 

bình đẳng tham gia là tốt như bạn có thể nhận được.

Tôi tin rằng nó chạy cách tốt hơn so với bất kỳ giải pháp khác có thể ở đây, hy vọng nó sẽ giúp bất cứ ai tình cờ trên cùng một vấn đề

Sqlfiddle link sửa đổi từ câu trả lời sailaway của mà kịch bản vẫn mang lại cho tất cả các trận đấu thay vì chỉ dài nhất một

Các vấn đề liên quan