Почему UDF настолько медленнее, чем подзапрос?

Вы возвращаете массив и помещаете его в имеющийся массив $ test, поэтому он стал многомерным массивом. Вы можете изменить имя функции, но просто сделайте это:

$test = [];
getTest($test, 'test_key');

function getTest(&$array,$key){
    $array[$key] = 'test_value';
}
12
задан Peter Mortensen 22 October 2011 в 16:16
поделиться

4 ответа

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

Одна из многих статей о проблеме является "Скалярными функциями, встраиванием и производительностью: интересный заголовок для скучного сообщения".

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

То, что Вы действительно хотите, является этим:

SELECT
   uc.id AS creator,
   uu.id AS updater,
   uo.id AS owner,
   a.[name]
FROM
    asset a
    JOIN
    user uc ON uc.user_pk = a.created_by
    JOIN
    user uu ON uu.user_pk = a.updated_by
    JOIN
    user uo ON uo.user_pk = a.owned_by

Февраль 2019 обновления

SQL Server 2019 начинает решать эту проблему.

32
ответ дан 2 December 2019 в 03:18
поделиться

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

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

CREATE FUNCTION dbo.get_user_inline (@user_pk INT)
RETURNS TABLE AS
RETURN
(
    SELECT TOP 1 id
    FROM ice.dbo.[user]
    WHERE user_pk = @user_pk
        -- AND active = 1
)

Ваш исходный запрос затем стал бы чем-то как:

SELECT
    (SELECT TOP 1 id FROM dbo.get_user_inline(created_by)) AS creator,
    (SELECT TOP 1 id FROM dbo.get_user_inline(updated_by)) AS updater,
    (SELECT TOP 1 id FROM dbo.get_user_inline(owned_by)) AS owner,
    [name]
FROM asset

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

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

12
ответ дан 2 December 2019 в 03:18
поделиться

Получить тот же результат (ПУСТОЙ УКАЗАТЕЛЬ, если пользователь удален или не активный).

 select 
    u1.id as creator,
    u2.id as updater,
    u3.id as owner,
    [a.name]
 FROM asset a
        LEFT JOIN user u1 ON (u1.user_pk = a.created_by AND u1.active=1) 
        LEFT JOIN user u2 ON (u2.user_pk = a.created_by AND u2.active=1) 
        LEFT JOIN user u3 ON (u3.user_pk = a.created_by AND u3.active=1) 
2
ответ дан 2 December 2019 в 03:18
поделиться

Я пропускаю что-то? Почему это не может работать? Вы только выбираете идентификатор, который Вы уже имеете в таблице:

select created_by as creator, updated_by as updater, 
owned_by as owner, [name]
from asset

Между прочим, в разработке Вас действительно должен избежать ключевых слов, как name, как имена полей.

0
ответ дан 2 December 2019 в 03:18
поделиться
Другие вопросы по тегам:

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