2010-05-01 18 views
12

Tôi đang sử dụng tìm kiếm văn bản đầy đủ sql 2008 và tôi đang gặp vấn đề nghiêm trọng với hiệu suất tùy thuộc vào cách tôi sử dụng Chứa hoặc Chứa. Dưới đây là mẫu: (bảng một có khoảng 5000 hồ sơ và có một chỉ số được bảo hiểm trên bảng 1 có tất cả các trường trong mệnh đề where. Tôi đã cố đơn giản hóa các câu lệnh để tha thứ cho tôi nếu có vấn đề về cú pháp.)Sql phục vụ tìm kiếm văn bản đầy đủ với không ổn định là rất chậm khi sử dụng trong JOIN!

Kịch bản 1:

select * from table1 as t1 
where t1.field1=90 
and t1.field2='something' 
and Exists(select top 1 * from containstable(table1,*, 'something') as t2 
where t2.[key]=t1.id) 

kết quả: 10 giây (rất chậm)

Kịch bản 2:

select * from table1 as t1 
join containstable(table1,*, 'something') as t2 on t2.[key] = t1.id 
where t1.field1=90 
and t1.field2='something' 

kết quả: 10 giây (rất chậm)

Kịch bản 3:

Declare @tbl Table(id uniqueidentifier primary key) 
insert into @tbl select {key] from containstable(table1,*, 'something') 

select * from table1 as t1 
where t1.field1=90 
and t1.field2='something' 
and Exists(select id from @tbl as tbl where id=req1.id) 

kết quả: phần nhỏ của một giây (siêu nhanh)

Bottom line, có vẻ như nếu tôi sử dụng Containstable trong bất kỳ loại điều kiện tham gia hoặc điều kiện nào của câu lệnh chọn cũng có các điều kiện khác, hiệu suất thực sự là xấu. Ngoài ra nếu bạn nhìn vào hồ sơ, số lần đọc từ cơ sở dữ liệu đi lên mái nhà. Nhưng nếu tôi lần đầu tiên thực hiện tìm kiếm văn bản đầy đủ và đưa kết quả vào một biến bảng và sử dụng biến đó mọi thứ diễn ra siêu nhanh. Số lần đọc cũng thấp hơn nhiều. Có vẻ như trong các kịch bản "xấu", bằng cách nào đó nó bị mắc kẹt trong một vòng lặp khiến nó đọc nhiều lần từ cơ sở dữ liệu, nhưng tất nhiên tôi không hiểu tại sao.

Bây giờ câu hỏi đặt ra trước hết là tại sao lại xảy ra? và câu hỏi hai là các biến bảng có thể mở rộng được không? điều gì sẽ xảy ra nếu nó dẫn đến 10 của hàng ngàn hồ sơ? là nó vẫn sẽ được nhanh chóng.

Bất kỳ ý tưởng nào? Cảm ơn

+0

Dường như vấn đề này áp phích này có http://stackoverflow.com/questions/2746303/freetext-query-is-slow-includes-top-and-order-by/2749322#2749322. Các hàng ước tính và thực tế từ truy vấn văn bản miễn phí khi bạn xem kế hoạch thực hiện là gì? –

+0

Ồ, Và trong câu trả lời cho truy vấn của bạn về các biến bảng, chúng được quyết định unscalalable nếu bạn đang đi để tham gia vào các bảng khác với họ. Trình tối ưu hóa truy vấn luôn giả định rằng chúng sẽ chỉ trả lại 1 hàng có thể dẫn đến một số kế hoạch tối ưu phụ rất nhỏ trong trường hợp chúng có hàng chục nghìn bản ghi. Bảng tạm thời không nhận được số liệu thống kê được tạo cho chúng. –

Trả lời

3

Tôi sẽ đoán ở đây rằng vấn đề của bạn giống với vấn đề khác mà tôi đã liên kết đến. Bạn có thấy vấn đề nảy sinh với nhiều cụm từ tìm kiếm không?

Nếu vậy câu trả lời của tôi từ chuỗi đó sẽ được áp dụng.

Từ http://technet.microsoft.com/en-us/library/cc721269.aspx#_Toc202506240

Điều quan trọng nhất là các đúng tham gia loại được chọn cho truy vấn toàn văn. Cardinality ước tính trên FulltextMatch STVF là rất quan trọng cho đúng kế hoạch. Vì vậy, điều đầu tiên cần kiểm tra là ước tính số thẻ FulltextMatch. Đây là số lần truy cập ước tính trong chỉ mục cho tìm kiếm toàn văn chuỗi. Ví dụ: trong truy vấn trong Hình 3, số này phải gần với số tài liệu có chứa cụm từ ‘từ’ . Trong hầu hết các trường hợp, cần rất chính xác nhưng nếu ước tính bị tắt một chặng đường dài, bạn có thể tạo các kế hoạch xấu.Ước tính cho các cụm từ đơnthường là rất tốt, nhưng ước tính nhiều cụm từ như cụm từ hoặc truy vấn AND phức tạp hơn vì không thể biết được điều gì trong chỉ số sẽ dựa trên tần suất của các điều khoản trong chỉ mục. Nếu ước tính sốlà tốt, một kế hoạch xấu có thể do truy vấn mô hình chi phí trình tối ưu hóa gây ra. Cách duy nhất để khắc phục vấn đề về kế hoạch là sử dụng truy vấn gợi ý để buộc một loại tham gia nhất định hoặc TỐI ƯU CHO.

Vì vậy, đơn giản là bạn không thể biết được thông tin mà cửa hàng xem liệu 2 cụm từ tìm kiếm có tương đối độc lập hay thường được tìm thấy cùng nhau hay không. Có lẽ bạn nên có 2 thủ tục riêng biệt cho các truy vấn từ đơn mà bạn cho phép trình tối ưu hóa làm công cụ của nó và một cho cụm từ tìm kiếm nhiều từ mà bạn buộc một kế hoạch "đủ tốt" (sys.dm_fts_index_keywords có thể trợ giúp nếu bạn muốn làm ước tính sơ bộ về bản thân của bản thân).

Nếu bạn gặp vấn đề với các truy vấn từ đơn, đoạn này từ bài viết được liên kết có thể áp dụng.

Trong SQL Server 2008 tìm kiếm toàn văn, chúng tôi có khả năng thay đổi kế hoạch là được tạo dựa trên ước tính thẻ của cụm từ tìm kiếm được sử dụng. Nếu kế hoạch truy vấn được cố định (vì nó nằm trong một truy vấn được tham số hóa bên trong một thủ tục được lưu trữ), bước này thực hiện không diễn ra. Do đó, kế hoạch được biên dịch luôn phân phối truy vấn này, ngay cả khi kế hoạch này không lý tưởng cho một cụm từ tìm kiếm nhất định.

Vì vậy, bạn có thể cần phải sử dụng tùy chọn RECOMPILE.

+0

Cảm ơn Marting vì câu trả lời phức tạp của bạn. Tuy nhiên, vấn đề của tôi không có nhiều từ. Thực tế, tìm kiếm trên toàn văn luôn cực kỳ nhanh chóng dù đó là một từ hay nhiều từ. Vấn đề đối với tôi là hiệu suất giảm đáng kể khi tìm kiếm toàn văn được kết hợp với các điều kiện khác trong mệnh đề where. Vì tôi sẽ vượt quá giới hạn cho phép đối với kích thước của nhận xét này, vui lòng xem nhận xét tiếp theo cho phần còn lại của câu trả lời ... – Bob

+0

@Bob Vẫn còn rất lạ khi bạn tham gia từ biến bảng của bạn để thực hiện điều tương tự của việc tham gia ID đến khóa mà nó hoạt động tốt. Làm thế nào để nó tham gia - Liệu nó có chọn một chỉ mục khác - hay một chiến lược kết nối khác? Ngoài ra khi bạn nhìn vào kế hoạch thực hiện là các hàng ước tính và thực tế hợp lý chính xác cho tất cả các phần của nó? –

12

tôi đã dành khá sometime về vấn đề này, và dựa trên chạy nhiều kịch bản, đây là những gì tôi đã tìm ra:

nếu bạn có Chứa hoặc CONTAINSTABLE bất cứ nơi nào trong truy vấn của bạn, đó là phần mà được thực hiện đầu tiên và khá độc lập. Có nghĩa là ngay cả khi phần còn lại của các điều kiện giới hạn tìm kiếm của bạn vào một bản ghi, không phải Chứa hoặc không có sự quan tâm không ổn định về điều đó. Vì vậy, điều này giống như một thực hiện song song.

Vì khi tìm kiếm toàn văn chỉ trả về trường khóa, nó sẽ tìm kiếm khóa ngay lập tức làm trường đầu tiên của các chỉ mục khác được chọn cho truy vấn. Vì vậy, đối với ví dụ trên, nó tìm kiếm chỉ mục bằng [key], field1, field2. Vấn đề là nó chọn một chỉ mục cho phần còn lại của truy vấn dựa trên các trường trong mệnh đề where. vì vậy, ví dụ ở trên nó chọn chỉ mục được bảo hiểm mà tôi có chỉ số như field1, field2, Id. (Id của bảng giống với [Key] được trả lại từ tìm kiếm toàn văn). Vì vậy, tóm tắt là:

  1. thực hiện CONTAINSTABLE
  2. thực hiện phần còn lại của các truy vấn và chọn một chỉ số dựa trên mệnh đề where của truy vấn
  3. Nó cố gắng hợp nhất hai này. Do đó, nếu chỉ mục mà nó chọn cho phần còn lại của truy vấn bắt đầu bằng trường [key], thì nó vẫn ổn. Tuy nhiên, nếu chỉ mục không có trường [key] làm khóa đầu tiên, nó sẽ bắt đầu thực hiện các vòng lặp. Nó thậm chí không làm một bảng quét, nếu không đi qua 5000 hồ sơ sẽ không được rằng chậm. Cách nó thực hiện vòng lặp là nó chạy vòng lặp cho tổng số kết quả từ FTS nhân với tổng số kết quả từ phần còn lại của truy vấn. Vì vậy, nếu FTS trả về 2000 bản ghi và phần còn lại của truy vấn trả về 3000, nó lặp 2000 * 3000 = 6.000.000. Tôi không hiểu tại sao.

Vì vậy, trong trường hợp của tôi, tìm kiếm văn bản đầy đủ, nó sẽ truy vấn phần còn lại kết quả nó vít lên. Nếu tôi thay đổi chỉ số được bảo hiểm của mình thành Id, field1, field2, mọi thứ sẽ rất nhanh.

Kỳ vọng của tôi là FTS trả về bó [key], phần còn lại của chuỗi trả về truy vấn của [Id] và sau đó Id phải được đối sánh với [key].

Tất nhiên, tôi đã cố gắng đơn giản hóa truy vấn của mình ở đây, nhưng truy vấn thực tế phức tạp hơn nhiều và tôi không thể thay đổi chỉ mục. Tôi cũng có các tình huống trong đó văn bản được truyền trong toàn văn trống và trong các tình huống đó, tôi không muốn tham gia bằng không ổn định. Trong những trường hợp đó, thay đổi chỉ mục được bảo hiểm của tôi thành trường id là trường đầu tiên, sẽ tạo ra thảm họa.

Dù sao, bây giờ tôi đã chọn giải pháp bảng tạm thời vì nó đang làm việc cho tôi. Tôi cũng giới hạn kết quả với một vài nghìn giúp với các vấn đề hiệu suất tiềm tàng của các biến bảng khi số lượng bản ghi quá cao.

nhờ

7

Thông thường nó hoạt động rất nhanh:

select t1.*, t2.Rank 
    from containstable(table1, field2, 'something') as t2 
     join table1 as t1 ON t1.id = t2.Key AND t1.field1=90 
    order by t2.Rank desc 

Có sự khác biệt lớn, nơi bạn đặt tiêu chí tìm kiếm của bạn: trong tham gia hoặc trong WHERE.

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