Почему скалярные функции SQL Server работают медленнее?

JavaScript не может отправлять электронную почту из веб-браузера. Однако, отступив от решения, которое вы уже пытались реализовать, вы можете сделать то, что соответствует исходному требованию:

отправить сообщение без обновления страницы

Вы можете использовать JavaScript для создания значений, которые будут нужны электронной почте, а затем сделать запрос AJAX к серверному ресурсу, который фактически отправит электронное письмо.

Если вы не знакомы с AJAX, быстрый поиск в Google даст вам информацию о том, какие серверные языки / технологии вы используете, так что ваша часть зависит от вас. много информации. Как правило, вы можете быстро запустить его и запустить с помощью функции $ .ajax () jQuery. Вам просто нужно иметь страницу на сервере, которая может быть вызвана в запросе.

16
задан Lukasz Szozda 7 November 2018 в 15:37
поделиться

6 ответов

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

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

В качестве побочного эффекта от встраивания, они не могут содержать процедурный код (no Declare @variable; set @variable =. .; возвращение). Однако они могут возвращать несколько строк и столбцов.

Вы можете переписать свои функции примерно так:

create function usf_GIS_GET_LAT(
    @City varchar (30),
    @State char (2)
)
returns table
as return (
  select top 1 lat
  from GIS_Location with (nolock) 
  where [State] = @State
    and [City] = @City
);

GO

create function usf_GIS_GET_LON (
    @City varchar (30),
    @State char (2)
)
returns table
as return (
  select top 1 LON
  from GIS_Location with (nolock)
  where [State] = @State
    and [City] = @City
);

Синтаксис их использования также немного отличается:

select
    Lat.Lat,
    Lon.Lon
from
    Address_Location with (nolock)
    cross apply dbo.usf_GIS_GET_LAT(City,[State]) AS Lat
    cross apply dbo.usf_GIS_GET_LON(City,[State]) AS Lon
WHERE
    ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)
28
ответ дан 30 November 2019 в 16:25
поделиться

Они этого не делают.

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

CREATE FUNCTION dbo.slow
(
    @ignore int
)
RETURNS INT 
AS
BEGIN
    DECLARE @slow INT
    SET @slow = (select count(*) from sysobjects a 
        cross join sysobjects b 
        cross join sysobjects c 
        cross join sysobjects d 
        cross join sysobjects e 
        cross join sysobjects f
    where a.id = @ignore) 

    RETURN @slow
END
go
SET STATISTICS TIME ON

select top 1 dbo.slow(id)
from sysobjects
go
select top 5 dbo.slow(id)
from sysobjects
go
select top 10 dbo.slow(id)
from sysobjects
go
select top 20 dbo.slow(id)
from sysobjects
go
select top 40 dbo.slow(id)
from sysobjects

SET STATISTICS TIME OFF

Выходные данные

SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 202 ms.


SQL Server Execution Times:
   CPU time = 889 ms,  elapsed time = 939 ms.

SQL Server Execution Times:
   CPU time = 1748 ms,  elapsed time = 1855 ms.

SQL Server Execution Times:
   CPU time = 3541 ms,  elapsed time = 3696 ms.


SQL Server Execution Times:
   CPU time = 7207 ms,  elapsed time = 7392 ms.

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

CREATE FUNCTION dbo.slow
(
    @ignore int
)
RETURNS INT 
AS
BEGIN
    DECLARE @slow INT
    SET @slow = (select count(*) from sysobjects a 
        cross join sysobjects b 
        cross join sysobjects c 
        cross join sysobjects d 
        cross join sysobjects e 
        cross join sysobjects f
    where a.id = @ignore) 

    RETURN @slow
END
go
SET STATISTICS TIME ON

select top 1 dbo.slow(id)
from sysobjects
go
select top 5 dbo.slow(id)
from sysobjects
go
select top 10 dbo.slow(id)
from sysobjects
go
select top 20 dbo.slow(id)
from sysobjects
go
select top 40 dbo.slow(id)
from sysobjects

SET STATISTICS TIME OFF

Выходные данные

SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 202 ms.


SQL Server Execution Times:
   CPU time = 889 ms,  elapsed time = 939 ms.

SQL Server Execution Times:
   CPU time = 1748 ms,  elapsed time = 1855 ms.

SQL Server Execution Times:
   CPU time = 3541 ms,  elapsed time = 3696 ms.


SQL Server Execution Times:
   CPU time = 7207 ms,  elapsed time = 7392 ms.

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

CREATE FUNCTION dbo.slow
(
    @ignore int
)
RETURNS INT 
AS
BEGIN
    DECLARE @slow INT
    SET @slow = (select count(*) from sysobjects a 
        cross join sysobjects b 
        cross join sysobjects c 
        cross join sysobjects d 
        cross join sysobjects e 
        cross join sysobjects f
    where a.id = @ignore) 

    RETURN @slow
END
go
SET STATISTICS TIME ON

select top 1 dbo.slow(id)
from sysobjects
go
select top 5 dbo.slow(id)
from sysobjects
go
select top 10 dbo.slow(id)
from sysobjects
go
select top 20 dbo.slow(id)
from sysobjects
go
select top 40 dbo.slow(id)
from sysobjects

SET STATISTICS TIME OFF

Выходные данные

SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 202 ms.


SQL Server Execution Times:
   CPU time = 889 ms,  elapsed time = 939 ms.

SQL Server Execution Times:
   CPU time = 1748 ms,  elapsed time = 1855 ms.

SQL Server Execution Times:
   CPU time = 3541 ms,  elapsed time = 3696 ms.


SQL Server Execution Times:
   CPU time = 7207 ms,  elapsed time = 7392 ms.

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

7
ответ дан 30 November 2019 в 16:25
поделиться

Simply put, because SQL expressions with user defined functions are less efficient than SQL expressions without them. The execution logic can't be optimized; and the function overhead (including calling protocols) must be incurred for every row.

KMike's advice is good. WHERE .. IN (SELECT something) is not likely to be an efficient pattern, and in this case can be easily replaced with a JOIN.

0
ответ дан 30 November 2019 в 16:25
поделиться

вы вызываете функцию два раза (два выбранных обращения к БД) для каждой строки в наборе результатов.

, чтобы ваш запрос быстрее соединялся с GIS_Location и пропускал функции:

SELECT
    g.Lat,
    g.Lon
FROM
    Address_Location        l WITH(NOLOCK)
    INNER JOIN GIS_Location g WITH(NOLOCK) WHERE l.State = g.State AND l.City = g.City
WHERE
    ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)

Я не уверен, почему NOLOCK, или пункт о сумасшедшем, я просто скопировал вопрос ...

2
ответ дан 30 November 2019 в 16:25
поделиться

See if this works better... Or maybe a distinct inner join?

select a.*,
(select top 1 g.Lat from GIS_Location g where g.City = a.City and g.State = a.State) as Lat,
(select top 1 g.Lon from GIS_Location g where g.City = a.City and g.State = a.State) as Lon
from Address_Location a
where a.ID in (select top 100 ID from Address_Location order by ID desc)

As for the scalar function performance, I'm not sure.

0
ответ дан 30 November 2019 в 16:25
поделиться

Вы можете обернуть свою функциональность во встроенный TVF, это будет намного быстрее:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/05/23/reuse -your-code-with-cross-apply.aspx

3
ответ дан 30 November 2019 в 16:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: