Могу ли я получить количество строк перед выполнением хранимой процедуры?

StackOverflow https://stackoverflow.com/questions/253938

Вопрос

У меня есть несколько сложных хранимых процедур, которые могут возвращать многие тысячи строк, и для их завершения требуется много времени.

Есть ли способ узнать, сколько строк будет возвращено до того, как запрос будет выполнен и извлечет данные?

Это с Visual Studio 2005, приложением Winforms и SQL Server 2005.

Это было полезно?

Решение

Решением вашей проблемы может быть переписать хранимую процедуру, чтобы она ограничивала результирующий набор некоторым числом, например:

SELECT TOP 1000 * FROM tblWHATEVER

в SQL Server или

SELECT * FROM tblWHATEVER WHERE ROWNUM <= 1000

в Oracle. Или внедрите решение для пейджинга, чтобы набор результатов каждого вызова был приемлемо небольшим.

Другие советы

Вы упомянули, что ваши хранимые процедуры занимают много времени. Затрачивается ли большая часть времени в процессе выбора строк из базы данных или возврата строк вызывающей стороне?

Если это последнее, возможно, вы можете создать зеркальную версию вашего SP, которая просто получает счетчик вместо фактических строк. Если это первое, ну, на самом деле, вы ничего не можете сделать, так как это медленный поиск подходящих строк.

создайте сохраненный процесс, чтобы сначала подсчитать строки.

ВЫБЕРИТЕ СЧЕТЧИК (*) ИЗ таблицы

Если только в вашей бизнес-логике нет какого-то аспекта, который позволяет это вычислить, нет. База данных, которую он собирается сделать, где и где объединяйте логику, чтобы выяснить, как строки строк, и это подавляющее большинство времени проводят в SP.

Вы не можете получить количество строк процедуры без ее выполнения.

Вы можете создать другую процедуру, которая принимает те же параметры, цель которой - сообщить вам, сколько строк должна вернуть другая процедура. Однако шаги, требуемые этой процедурой, обычно бывают такими же, как и в основной процедуре, так что это займет примерно столько же времени, сколько и простое выполнение основной процедуры.

Вам нужно написать другую версию хранимой процедуры, чтобы получить количество строк. Это, вероятно, будет намного быстрее, потому что вы можете исключить объединение таблиц, по которым вы не фильтруете, убрать упорядочение и т. Д. Например, если ваш сохраненный процесс выполнил sql, например:

select firstname, lastname, email, orderdate  from 
customer inner join productorder on customer.customerid=productorder.productorderid
where orderdate>@orderdate order by lastname, firstname;

Ваша версия для подсчета будет выглядеть примерно так:

select count(*) from productorder where orderdate>@orderdate;

Не в общем.

Благодаря знанию о работе хранимой процедуры вы сможете получить либо приблизительный, либо точный подсчет (например, если «базовая» или «базовая» таблица запроса может быть быстрой). рассчитывается, но это сложные соединения и / или сводки, которые увеличивают время).

Но вам придется сначала вызвать подсчет SP, а затем SP данных, или вы можете использовать SP с множеством результатов.

Получение количества строк может занять столько же времени, сколько и фактических данных, поэтому я не рекомендовал бы выполнять подсчет в большинстве случаев.

Некоторые возможности:

1) Предоставляет ли SQL Server свои результаты оптимизации запросов каким-либо образом? то есть вы можете проанализировать запрос и затем получить оценку количества строк? (Я не знаю SQL Server).

2) Возможно, основываясь на критериях, которые дает пользователь, вы можете выполнить некоторые собственные оценки. Например, если пользователь вводит «S%» в поле фамилии клиента для запроса заказов, вы можете определить, что это соответствует 7% (скажем) записей клиента, и экстраполировать, что запрос может вернуть о 7% записей заказов.

Исходя из того, что сказал Тони Эндрюс в своем ответе, вы можете получить приблизительный план запроса на ваш запрос с помощью:

SET showplan_text OFF
GO
SET showplan_all on
GO
--Replace with call you your stored procedure
select * from MyTable
GO 
SET showplan_all ofF
GO

Это должно вернуть таблицу или множество таблиц, которые позволят вам получить приблизительное количество строк вашего запроса.

Вам необходимо проанализировать возвращенный набор данных, чтобы определить логический (значимый) первичный ключ для возвращаемого набора результатов. В общем случае это будет намного быстрее, чем полная процедура, потому что сервер не создает набор результатов из данных во всех столбцах каждой строки каждой таблицы, он просто считает строки ... В общем, это может даже не произойти. для этого нужно прочитать фактические строки таблицы с диска, может потребоваться просто подсчитать индексные узлы ...

Затем напишите другой оператор SQL, который включает в себя только таблицы, необходимые для генерации этих ключевых столбцов (надеюсь, это подмножество таблиц в основном SQL-запросе), и тот же оператор where с теми же значениями предикатов фильтрации ...

Затем добавьте еще один необязательный параметр в Stored Proc, называемый, скажем, @CountsOnly, со значением по умолчанию false (0), так что ...

Alter Procedure <storedProcName>
@param1 Type, 
-- Other current params
@CountsOnly TinyInt = 0
As
Set NoCount On

   If @CountsOnly = 1
       Select Count(*) 
       From TableA A 
          Join TableB B On   etc. etc...
       Where < here put all Filtering predicates >

   Else
      <Here put old SQL That returns complete resultset with all data>

  Return 0

Затем вы можете просто вызвать тот же хранимый процесс с @CountsOnly, установленным равным 1, чтобы просто получить количество записей. Старый код, который вызывает proc, будет по-прежнему функционировать так, как раньше, так как значение параметра по умолчанию установлено в false (0), если оно не включено

По крайней мере технически возможно запустить процедуру, которая помещает набор результатов во временную таблицу. Затем вы можете узнать количество строк перед тем, как переносить данные с сервера на приложение, и это избавит вас от необходимости создавать набор результатов дважды.

Но я сомневаюсь, что это стоит того, если создание результирующего набора занимает очень много времени, и в этом случае оно может быть достаточно большим, чтобы временная таблица была проблемой. Почти наверняка время для перемещения большого стола по сети будет во много раз больше, чем необходимо для его создания.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top