Найкращий спосіб здійснити відфільтрований пошук


17

Я хотів би запитати вас, вашу думку, коли йдеться про впровадження відфільтрованої форми пошуку. Давайте уявимо такий випадок:

  • 1 Велика таблиця з великою кількістю стовпців
  • Можливо, важливо сказати, що це SQL Server

Потрібно запровадити форму для пошуку даних у цій таблиці, і в цій формі у вас буде кілька прапорців, які дозволяють виконати ваші пошуки.

Тепер моє запитання полягає в тому, який із наведених нижче повинен бути найкращим способом здійснення пошуку?

  1. Створіть збережену процедуру із запитом всередині. Ця збережена процедура перевірятиме, чи параметри задані додатком, а у випадку, якщо їм не надано підстановку, буде розміщено у запиті.

  2. Створіть динамічний запит, який будується відповідно до того, що задано програмою.

Я запитую це тому, що мені відомо, що SQL Server створює план виконання, коли створена збережена процедура, щоб оптимізувати її продуктивність, однак, створивши динамічний запит всередині збереженої процедури, ми пожертвуємо оптимізацією, отриманою планом виконання?

Скажіть, будь ласка, який був би найкращий підхід у вашій думці.


Нижче ви заявляєте, що прагнете до динамічного рішення. Це здорово, просто переконайтеся, що ви перераховуєте можливі фільтри та індекси, що їх підтримують. Поки запити будуються послідовно, вони повинні бути ефективними.
Меттью Флінн

Відповіді:


10

Ви можете переглянути відповідь на подібне подібне запитання тут: /programming/11329823/add-where-clauses-to-sql-dynamically-programmatic

Ми виявили, що SPROC приймає купу додаткових параметрів та реалізує фільтр таким чином:

CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS 
...
SELECT field1, field2, ... FROM [Table]
WHERE 
  (@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
  AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)

буде кешувати перший план виконання, з яким він запускається (наприклад @optionalParam1 = 'Hello World', @optionalParam2 = NULL), але потім виконуватиме сумно, якщо ми передамо йому інший набір необов'язкових параметрів (наприклад @optionalParam1 = NULL, @optionalParam2 = 42). (І, очевидно, ми хочемо виконання кешованого плану, так що WITH RECOMPILEце поза)

Виняток тут полягає в тому, що якщо в запиті також є принаймні один ОБОВ'ЯЗКОВИЙ фільтр, який є ВІДВІЛЬНО вибірковим і правильно індексований, крім необов'язкових параметрів, то вищевказаний PROC виконає чудово.

Однак якщо ВСІ фільтри необов’язкові, досить жахлива правда полягає в тому, що параметризований динамічний sql насправді працює краще (якщо ви не пишете N! Різних статичних PROCS для кожної перестановки необов'язкових параметрів).

Динамічний SQL, як показано нижче, створить та кеширує різний план для кожної перестановки параметрів Запиту, але принаймні кожен план буде "підлаштований" під конкретний запит (не має значення, чи це PROC чи Adhoc SQL - як доки вони параметризовані запитами, вони будуть кешовані)

Тож звідси мої переваги:

DECLARE @SQL NVARCHAR(MAX)        

-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'

IF @OptionalParam1 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'    
    END        

IF @OptionalParam2 IS NOT NULL        
    BEGIN        
        SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'    
    END        

EXEC sp_executesql @SQL,        
    N'@optionalParam1 NVARCHAR(50), 
      @optionalParam2 INT'
    ,@optionalParam1 = @optionalParam1
    ,@optionalParam2 = @optionalParam2

тощо. Не має значення, якщо ми передаємо зайві параметри в sp_executesql - вони ігноруються. Варто зазначити, що ORM, як Linq2SQL і EF, використовують параметризований динамічний sql аналогічно.


1
Так, я вважав, що це був варіант, який я обираю. Просто хотів переконатися, що це гарний. Дякую за відповідь.
j0N45

"Якщо оператор SQL виконується без параметрів, SQL Server параметризує оператор внутрішньо, щоб збільшити можливість співвіднесення його з існуючим планом виконання. Цей процес називається простою параметризацією." Тому в основному програма може використовувати щось, на зразок "де filenumber =" + ім'я файлу. Звичайно, це відкриває банки з глистами, але це вже інша тема ;-)
Кодизм

5

Почніть з того, що, на вашу думку, легше здійснити (я думаю, варіант 2). Потім виміряйте ефективність для реальних даних. Почніть оптимізувати лише за потреби, а не заздалегідь.

До речі, залежно від того, наскільки складні ваші пошукові фільтри, ваше завдання може бути непросто вирішеним без динамічного SQL. Тож навіть якщо ви використовуєте збережену процедуру, це, швидше за все, не підвищить продуктивність, як ви вже підозрюєте. З іншого боку, якщо це допомагає, є кілька типів підказок (див. Http://www.simple-talk.com/sql/performance/controlling-execution-plans-with-hints/ ), які можна додати до SQL запит, динамічний чи ні, щоб допомогти серверу SQL оптимізувати його план виконання.


Ну, я вже реалізував варіант 2, і я вважаю, що це найкращий шлях, головним чином тому, що шаблони різко знизять продуктивність, проте я жертвую технічним обслуговуванням, оскільки це збільшить складність у коді. Мені просто хотілося знати, чи знає хтось кращий варіант для подібних ситуацій.
j0N45

Я б вам голосував, але репутації у мене немає.
j0N45
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.