SQL Server 2017 vs SQL Проблема производительности Server 2012 - PullRequest
0 голосов
/ 22 января 2020

У меня есть SQL код, который выполняется на SQL Server 2017 менее чем за 200 мс, но тот же код на SQL Server 2012 занимает более 3 секунд - может кто-нибудь сказать мне:

  1. почему это происходит
  2. как мне это решить
select count(*) from dbo.mConsultationQuestionsReplies = 1,300,000

Это мой код:

DECLARE @maxCount int;
DECLARE @ddlIds nvarchar(max);
SET @maxCount = 6;
SET @ddlIds = '4,8,840,779,10,813,3,18,7,918';


IF OBJECT_ID('tempdb..#rList') IS NOT NULL 
    DROP TABLE #rList

IF OBJECT_ID('tempdb..#docList') IS NOT NULL 
    DROP TABLE #docList

SELECT
    rd.UserID, 
    (CASE 
        WHEN ids1.value IS NULL
           THEN CAST(ids2.value AS int) 
           ELSE CAST(ids1.value AS int) 
     END) [cid] 
INTO
    #docList 
FROM
    mDJDoctors [rd] 
LEFT JOIN
    dbo.[mDJDoctorsSpeciality] [rs] ON rd.DoctorID = rs.doctorId
LEFT JOIN
    dbo.mDJSpecialtyCategory [rca] ON rca.SpecialtyId = rs.specialId
LEFT JOIN 
    STRING_SPLIT(@ddlIds, ',') [ids1] ON rca.CategoryId = ids1.value
LEFT JOIN 
    dbo.mDJDoctorsSpecialtyAbove [ars] ON ars.doctorId = rd.DoctorID
LEFT JOIN 
    dbo.mDJSpecialtyAboveCategory [arca] ON arca.AboveSpecialtyId = ars.SpecialtyAboveId
LEFT JOIN
    STRING_SPLIT(@ddlIds, ',') [ids2] ON [arca].CategoryId = ids2.value
WHERE
    [ids1].value IS NOT NULL
    OR [ids2].value IS NOT NULL

SELECT * 
INTO #rList 
FROM
    (SELECT 
         *, 
         ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber 
     FROM
         (SELECT DISTINCT r.ReplyUserID, r.ReplyDateInsert, d.cid
          FROM dbo.mConsultationQuestionsReplies[r] 
          JOIN #docList [d] ON r.ReplyUserID = d.UserID
          WHERE r.ReplyId IN (SELECT MAX(r.ReplyId)[id]
                              FROM dbo.mConsultationQuestionsReplies[r]
                              JOIN #docList [d] on r.ReplyUserID = d.UserID
                              GROUP BY d.cid, d.UserID)) [t]) [t] 
WHERE
    t.rowNumber <= @maxCount

SELECT 
    u.FirstName AS DoctorName,
    u.UserID AS DoctorUserId,
    sp.specialFaName AS DoctorSpecialty,
    ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
    md.DoctorGUID,
    md.DoctorID,
    cp.ProfileISOnline,
    p.ProfilePicture AS DoctorProfilePicture,
    p.ProfileDateInserted,
    r.ReplyDateInsert AS LastReplyDateInsert,
    r.cid
FROM 
    dbo.mDJDoctors AS md
INNER JOIN 
    dbo.Core_Users AS u ON md.UserID = u.UserID
INNER JOIN 
    dbo.Core_Profiles AS p ON u.UserID = p.UserID
INNER JOIN
    (SELECT * FROM #rList) [r] ON r.ReplyUserID = u.UserID
INNER JOIN 
    dbo.mConsultationDocterProfile AS cp ON cp.UserID = u.UserID
LEFT OUTER JOIN 
    dbo.mDJDoctorsSpeciality AS mdad ON md.DoctorID = mdad.doctorId
LEFT OUTER JOIN 
    dbo.mDJSpecialty AS sp ON mdad.specialId = sp.specialId
LEFT OUTER JOIN 
    dbo.mDJDoctorsSpecialtyAbove AS mdad2 ON md.DoctorID = mdad2.doctorId
LEFT OUTER JOIN 
    dbo.mDJSpecialtyAbove AS ab ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
WHERE 
    cp.ProfileISOnline = 1

обновление: основано на guid с марта c -s я удалил STRING_SPLIT, и новый результат

declare @maxCount int;
set @maxCount = 6;


IF OBJECT_ID('tempdb..#rList') IS NOT NULL DROP TABLE #rList
IF OBJECT_ID('tempdb..#docList') IS NOT NULL DROP TABLE #docList

select rd.UserID, (case when arca.CategoryId is null then cast(rca.CategoryId as int) else cast(arca.CategoryId as int) end)[cid] into #docList 
from mDJDoctors [rd]   WITH (NOLOCK)
left join dbo.[mDJDoctorsSpeciality] [rs]  WITH (NOLOCK) on rd.DoctorID = rs.doctorId
left join dbo.mDJSpecialtyCategory [rca]  WITH (NOLOCK) on rca.SpecialtyId = rs.specialId
left join dbo.mDJDoctorsSpecialtyAbove [ars]  WITH (NOLOCK) on ars.doctorId = rd.DoctorID
left join dbo.mDJSpecialtyAboveCategory [arca]  WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId
where arca.CategoryId in (4,8,840,779,10,813,3,18,7,918) or rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)


select  * into #rList from (
select * , ROW_NUMBER() OVER (PARTITION BY t.cid ORDER BY t.ReplyDateInsert DESC) AS rowNumber from (
select distinct r.ReplyUserID, r.ReplyDateInsert, d.cid
from dbo.mConsultationQuestionsReplies[r]  WITH (NOLOCK) 
join #docList [d] on r.ReplyUserID = d.UserID
where r.ReplyId in(
select max(r.ReplyId)[id]
  from dbo.mConsultationQuestionsReplies[r]  WITH (NOLOCK)
  join #docList [d] on r.ReplyUserID = d.UserID
group by d.cid,d.UserID
))[t])[t] where t.rowNumber <= @maxCount

    SELECT distinct
           u.FirstName AS DoctorName,
           u.UserID AS DoctorUserId,
           sp.specialFaName AS DoctorSpecialty,
           ab.SpecialtyAboveFaName AS DoctorAboveSpecialty,
           md.DoctorGUID,
           md.DoctorID,
           cp.ProfileISOnline,
           p.ProfilePicture AS DoctorProfilePicture,
           p.ProfileDateInserted,
           r.ReplyDateInsert AS LastReplyDateInsert,
           r.cid

    FROM dbo.mDJDoctors AS md  WITH (NOLOCK)
        INNER JOIN dbo.Core_Users AS u  WITH (NOLOCK)
            ON md.UserID = u.UserID
        INNER JOIN dbo.Core_Profiles AS p  WITH (NOLOCK)
            ON u.UserID = p.UserID
        INNER JOIN
        (
            select * from #rList
        ) [r] 
            ON r.ReplyUserID = u.UserID
        INNER JOIN dbo.mConsultationDocterProfile AS cp  WITH (NOLOCK)
            ON cp.UserID = u.UserID
        LEFT OUTER JOIN dbo.mDJDoctorsSpeciality AS mdad  WITH (NOLOCK)
            ON md.DoctorID = mdad.doctorId
        LEFT OUTER JOIN dbo.mDJSpecialty AS sp  WITH (NOLOCK)
            ON mdad.specialId = sp.specialId
        LEFT OUTER JOIN dbo.mDJDoctorsSpecialtyAbove AS mdad2  WITH (NOLOCK)
            ON md.DoctorID = mdad2.doctorId
        LEFT OUTER JOIN dbo.mDJSpecialtyAbove AS ab  WITH (NOLOCK)
            ON mdad2.SpecialtyAboveId = ab.SpecialtyAboveId
    WHERE cp.ProfileISOnline = 1
    order by cid, LastReplyDateInsert

занимает 200 мс в sql 2017 и 1038 мс в sql 2012

обновление 3: это мои планы выполнения xml на 2012 и 2017 годы

планы выполнения на 2012 и 2017 годы

обновление 4: конфигурация сервера

Ответы [ 2 ]

1 голос
/ 22 января 2020

В базе данных sql2012 отсутствует индекс (по сравнению с sql2017) для [dbo]. [Core_Profiles]

Для sql2012 нет индекса для [dbo]. [Core_Profiles] .Userid, и хотя запрос имеет только 52 различных идентификатора пользователя, он сканирует полную таблицу [Core_Profiles] (~ 0,5 млн строк), чтобы получить sh, сопоставить ее с 52 строками и вернуть: 52 строки (разница в масштабе значительна).

Для sql2017 есть [missing_index_9245_9243] (которое также включает ProfilePicture {?}). Вместо сканирования полмиллиона таблиц он выполняет объединение 52 строк / циклов. Для получения значения ProfileDateInserted для [Core_Profiles] все еще существует ключевой обзор.

Первое, что нужно попробовать, - это создать индекс для [dbo]. [Core_Profiles] .Userid. Если вы решите включить ProfilePicture, это не имеет отношения к конкретному запросу, так как поиск ключа выполняется в любом случае. Дополнительным предложением было бы создать индексы для таблиц #temp. Кроме того, извлечение mDJDoctorsSpeciality & mDJDoctorsSpecialtyAbove (набора из 4 внешних соединений таблицы) используется дважды в пакете. Разве первое выполнение не будет удовлетворять второму (возвращенный набор результатов?), Так почему бы не сохранить его и использовать таблицу #temp вместо повторного запроса таблиц (caveat: вообще не смотрел на логику / модель запроса, только на планы). Скорее всего, запросы могут быть вложенными (внутренними объединениями), что-то вроде:

from mDJDoctors [rd]   WITH (NOLOCK)
left join 
(
dbo.[mDJDoctorsSpeciality] [rs]  WITH (NOLOCK) 
join dbo.mDJSpecialtyCategory [rca]  WITH (NOLOCK) on rca.SpecialtyId = rs.specialId and rca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on rd.DoctorID = rs.doctorId
left join 
(
dbo.mDJDoctorsSpecialtyAbove [ars]  WITH (NOLOCK) 
join dbo.mDJSpecialtyAboveCategory [arca]  WITH (NOLOCK) on arca.AboveSpecialtyId = ars.SpecialtyAboveId and arca.CategoryId in (4,8,840,779,10,813,3,18,7,918)
) on ars.doctorId = rd.DoctorID
where rs.doctorId is not null or rd.DoctorID is not null

, если подумать, не является ли это объединением?

(
DoctorId from dbo.mDJSpecialtyCategory....
union
DoctorId from dbo.mDJSpecialtyAboveCategory....
) as X
join mDJDoctors [rd] on DoctorId....
0 голосов
/ 22 января 2020

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

Итак, взгляните на память каждому экземпляру назначены настройки (MAXDOP и CTP - хорошее начало), работают ли они на одной машине? Если нет, есть ли существенные различия HW? Есть ли больше (другие люди или приложения, выполняющие запросы) вашего SQL Server 2017, чем ваш SQL Server 2012? У вас одинаковый объем данных на обоих серверах? Ваши индексы одинаковы и поддерживаются в обоих экземплярах (возможно, у вас высокий уровень фрагментации на SQL Server 2017)? Кроме того, взгляните на планы выполнения, чтобы увидеть, идентичны ли они на обоих серверах.

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

...