нужна помощь в оптимизации хранимых процедур - PullRequest
1 голос
/ 10 февраля 2012

У меня есть хранимая процедура, которая создает динамический SQL-запрос, а затем запускает его через exec (@sql).

Хранимая процедура объединяет около 12 таблиц. Как это было, он работал относительно быстро. Но тогда мне нужно было добавить в дополнительное поле. Для этого я создал скалярную функцию, которая выглядит следующим образом:

SELECT @weight = @weight +COUNT(*) FROM dbo.UserPDMedication WHERE UserID = @userid
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND HoehnYarhID IS NOT null
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND DateOfBirth IS NOT NULL
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND GenderID IS NOT NULL
SELECT @weight = @weight +COUNT(*) FROM dbo.[User] WHERE UserID = @userid AND DateDiagnosed IS NOT null

По сути, это просто функция, которая возвращает int в зависимости от того, сколько вопросов задал пользователь. Таким образом, для каждого пользователя в хранимой процедуре эта функция вызывается. Сохраненный процесс выглядит так:

    SELECT DISTINCT u.UserID, u.Healthy, u.DateOfBirth, u.City, st.StateCode AS State, u.GenderID, g.Gender, u.Latitude, u.Longitude, u.PDConditionID, u.Zip, u.Distance,
    (SELECT TOP 1 EmailID FROM Messages m WHERE TrialID = ' + @trialID + ' AND ToUserID = u.userid AND LocationID = ' + @locationID + ') AS MessageID, dbo.UserWeightedValue(u.UserID) as wt
FROM [User] u
    INNER JOIN aspnet_UsersInRoles uir ON u.AspnetUserID = uir.UserId
    INNER JOIN aspnet_Roles r ON uir.RoleId = r.RoleId
    FULL JOIN UserHealthCondition uhc ON u.UserID = uhc.UserID
    FULL JOIN UserMotorSymptom ums ON u.UserID = ums.UserID
    FULL JOIN UserNonMotorSymptom unms ON u.UserID = unms.UserID
    FULL JOIN UserPDMedication updm ON u.UserID = updm.UserID
    FULL JOIN UserPDTreatment updt ON u.UserID = updt.UserID
    FULL JOIN UserSupplement us ON u.UserID = us.UserID
    FULL JOIN UserPDGeneticMarker updgm ON u.UserID = updgm.UserID
    FULL JOIN UserFamilyMember ufm ON u.UserID = ufm.UserID
    FULL JOIN State st ON u.StateID = st.ID
    FULL JOIN Gender g ON u.GenderID = g.ID
WHERE u.UserID IS NOT NULL

(я удалил несколько кусков, чтобы попытаться сохранить это коротким). Этот get выполняется в виде динамической строки в хранимом процессе. Любые советы о том, как я могу оптимизировать это, чтобы ускорить процесс?

Спасибо

РЕДАКТИРОВАТЬ: я получил это работает, используя комбинацию предложений здесь. Я сохранил свою функцию как есть, хотя я объединил несколько операторов выбора в 2 оператора. Затем я взял исходный сохраненный процесс и изменил выбор на выбор в ## temp. А потом я запустил свою функцию на эту временную таблицу. Время выполнения сократилось до 3-4 секунд. Я думаю, что мне придется отдать должное гранту по этому вопросу, так как именно его указание отличило меня от правильного пути. Но спасибо всем.

Ответы [ 3 ]

1 голос
/ 10 февраля 2012

DISTINCT, безусловно, вызовет снижение производительности, так как агрегирует. Вам это действительно нужно? Часто, когда вы видите DISTINCT, это указывает на проблему с данными или структурой, которая скрывается за счет возможности устранения дубликатов, которые структура должна устранить самостоятельно.

После этого вместо коррелированного запроса в списке SELECT я хотел бы переместить его как JOIN. Это не верный выигрыш в огне, но часто оптимизатор может лучше воплотить это в план.

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

1 голос
/ 10 февраля 2012

Если UserID является первичным ключом таблицы User, тогда нет необходимости делать один SELECT для вопроса, заполненного пользователем, вы можете заключить его в один SELECT:

SELECT @weight = @weight + COUNT(HoehnYarhID) + COUNT(DateOfBirth) + COUNT(GenderID) + COUNT(DateDiagnosed)
FROM dbo.[User] 
WHERE UserID = @userid 
0 голосов
/ 10 февраля 2012

Преобразование скалярной функции в встроенную табличную функцию.

...