2017-01-26 16 views
9

Tôi có bảng trong cơ sở dữ liệu SQL Server có trường địa chỉ (ví dụ: Farnham Road, Guildford, Surrey, GU2XFF) mà tôi muốn tìm kiếm bằng ký tự đại diện trước và sau chuỗi tìm kiếm .Tối ưu hóa biểu thức LIKE bắt đầu bằng ký tự đại diện

SELECT * 
FROM Table 
WHERE Address_Field LIKE '%nham%' 

Tôi có khoảng 2 triệu bản ghi trong bảng này và tôi thấy rằng các truy vấn mất từ ​​5-10 giây, điều này không lý tưởng. Tôi tin rằng điều này là do ký tự đại diện trước đó.

Tôi nghĩ rằng tôi đúng khi nói rằng mọi chỉ mục sẽ không được sử dụng để tìm kiếm các hoạt động vì ký tự đại diện trước.

Sử dụng tìm kiếm văn bản đầy đủ và CONTAINS là không thể vì tôi muốn tìm kiếm các phần sau của từ (tôi biết rằng bạn có thể thay thế chuỗi tìm kiếm cho Guil * trong truy vấn dưới đây và điều này sẽ trả lại kết quả). Chắc chắn chạy các kết quả sau không có kết quả nào

SELECT * 
FROM Table 
WHERE CONTAINS(Address_Field, '"nham"') 

Có cách nào để tối ưu hóa truy vấn bằng ký tự đại diện trước không?

+2

Theo như tôi biết, SQL Server không có kiểu chỉ mục được xây dựng sẵn mà thực hiện những gì bạn muốn (Postgres thực hiện). Có nhiều cách để làm những gì bạn muốn, nhưng họ đòi hỏi rất nhiều công việc. –

+1

Bạn đang ở trong các chỉ mục đó sẽ không thể tìm kiếm trên đó, nhưng ngay cả việc quét chỉ mục bằng tra cứu chính có thể nhanh hơn quét bảng nếu đó là những gì nó đang làm bây giờ. Bạn sẽ phải kiểm tra nó và xem. – SqlZim

+1

Một điểm làm rõ: Bạn có thể tìm kiếm các phần của các từ có chỉ mục toàn văn, nhưng nó phải là phần đầu tiên của từ đó. Sử dụng ví dụ về chuỗi của bạn, bạn có thể tận dụng thành công chỉ mục toàn văn bằng cách tìm kiếm 'Guil', nhưng bạn đúng khi nói rằng nó sẽ không hoạt động cho 'nham'. – dfundako

Trả lời

4

Đây là một giải pháp (không thực sự được khuyến nghị).

Tạo bảng AddressSubstrings. Bảng này sẽ có nhiều hàng cho mỗi địa chỉ và khóa chính của table.

Khi bạn chèn địa chỉ vào table, hãy chèn đoạn bắt đầu từ mỗi vị trí. Vì vậy, nếu bạn muốn chèn 'abcd', sau đó bạn sẽ chèn:

  • abcd
  • BCD
  • cd
  • d

cùng với id duy nhất của dòng trong Bàn. (Tất cả điều này có thể được thực hiện bằng cách sử dụng trình kích hoạt.)

Tạo chỉ mục trên AddressSubstrings(AddressSubstring).

Sau đó, bạn có thể cụm từ truy vấn của bạn như:

SELECT * 
FROM Table t JOIN 
    AddressSubstrings ads 
    ON t.table_id = ads.table_id 
WHERE ads.AddressSubstring LIKE 'nham%'; 

Bây giờ sẽ có một dòng tương ứng bắt đầu với nham. Vì vậy, like nên sử dụng chỉ mục (và chỉ mục văn bản đầy đủ cũng hoạt động).

Nếu bạn thú vị theo cách phải để xử lý vấn đề này, một nơi hợp lý để bắt đầu là Postgres documentation. Điều này sử dụng một phương pháp tương tự như trên, nhưng sử dụng n-gram. Vấn đề duy nhất với n-gram cho vấn đề cụ thể của bạn là họ yêu cầu viết lại so sánh cũng như thay đổi việc lưu trữ.

1

Không phải không có nỗ lực chuẩn bị nghiêm túc, hwilson1.

Nguy cơ lặp lại rõ ràng - mọi tối ưu hóa đường dẫn tìm kiếm - dẫn đến quyết định liệu chỉ mục được sử dụng hay loại toán tử nối nào để sử dụng, v.v. (độc lập với DBMS mà chúng ta đang nói đến) hoạt động trên bình đẳng (bằng) hoặc kiểm tra phạm vi (lớn hơn và nhỏ hơn).

Với các ký tự đại diện hàng đầu, bạn đã hết may mắn.

Cách giải quyết là một nỗ lực chuẩn bị nghiêm túc, như đã nêu lên phía trước:

Nó sẽ đun sôi xuống văn bản tìm kiếm tính năng Vertica, nơi vấn đề đó được giải quyết. Xem ở đây:

https://my.vertica.com/docs/8.0.x/HTML/index.htm#Authoring/AdministratorsGuide/Tables/TextSearch/UsingTextSearch.htm

Đối với bất kỳ nền tảng cơ sở dữ liệu khác, bao gồm MS SQL, bạn sẽ phải làm điều đó bằng tay.

Tóm lại: Nó dựa trên khóa chính hoặc số nhận dạng duy nhất của bảng có tìm kiếm văn bản bạn muốn tối ưu hóa.

Bạn tạo một bảng phụ, khóa chính là khóa chính của bảng cơ sở của bạn, cộng với số thứ tự, và cột VARCHAR sẽ chứa một chuỗi các chuỗi của bảng cơ sở ban đầu mà bạn đã tìm kiếm bằng ký tự đại diện. Trong một cách quá đơn giản:

Nếu bảng đầu vào của bạn (chỉ hiển thị các cột quan trọng) là thế này:

id |the_search_col       |other_col 
    42|The Restaurant at the End of the Universe|Arthur Dent 
    43|The Hitch-Hiker's Guide to the Galaxy |Ford Prefect 

bảng tìm kiếm phụ trợ của bạn có thể bao gồm:

id |seq|search_token 
    42| 1|Restaurant 
    42| 2|End 
    42| 3|Universe 
    43| 1|Hitch-Hiker 
    43| 2|Guide 
    43| 3|Galaxy 

Thông thường, bạn ngăn chặn các "chất độn" điển hình như các bài báo và giới từ và các dấu nháy đơn, và được chia thành các thẻ được phân tách bằng dấu câu và khoảng trắng. Tuy nhiên, đối với ví dụ '% nham%' của bạn, bạn có thể cần nói chuyện với một nhà ngôn ngữ học chuyên về hình thái học tiếng Anh để tìm các ứng cử viên mã thông báo ....: -]

Bạn có thể bắt đầu bằng kỹ thuật tương tự mà tôi sử dụng khi tôi bỏ trục một loạt ngang các biện pháp mà không có khoản pIVOT, như ở đây:

Pivot sql convert rows to columns

Sau đó, sử dụng một sự kết hợp của, có lẽ lồng nhau, CHARINDEX() và substring() sử dụng các chỉ số bạn nhận được từ CROSS JOIN với một loạt các số nguyên chỉ mục như được mô tả trong bài đăng của tôi được đề xuất ở trên và sử dụng chỉ mục đó làm chuỗi cho bảng tìm kiếm phụ trợ.

Đặt chỉ mục trên search_token và bạn sẽ có đường dẫn truy cập rất nhanh đến một bảng lớn.

Không đi dạo trong công viên, tôi đồng ý, nhưng đầy hứa hẹn ...

Chúc mừng chơi -

Marco các Sane

3

tôi không thể đưa ra một giải pháp hoàn chỉnh cho vấn đề khó khăn này.

Nhưng nếu bạn đang tìm kiếm để tạo ra một khả năng tìm kiếm hậu tố, trong đó, ví dụ, bạn muốn có thể tìm thấy hàng chứa HWilson với ilson và hàng chứa ABC123000654 với 654, đây là một gợi ý.

WHERE REVERSE(textcolumn) LIKE REVERSE('ilson') + '%' 

Tất nhiên đây không phải là sargable cách tôi đã viết ở đây.Nhưng nhiều DBMS hiện đại, bao gồm các phiên bản gần đây của máy chủ SQL, cho phép định nghĩa và lập chỉ mục các cột được tính toán hoặc ảo.

Tôi đã triển khai kỹ thuật này, với niềm vui của người dùng cuối, trong hệ thống chăm sóc sức khỏe có nhiều ID bản ghi như ABC123000654.

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