С какого количества возвращенных записей я должен начать ожидать проблем с производительностью? - PullRequest
2 голосов
/ 27 января 2010

У меня есть запрос, который я настраивал в течение некоторого времени, но я не могу сильно сократить время выполнения. В плане выполнения все выглядит так, как будто оно делает то, что должно, без больших затрат, связанных с какой-либо конкретной частью запроса, все использует поиск по индексу там, где это предполагается. Когда я выполняю тот же запрос к другому клиенту, он выполняется довольно быстро, но возвращает только 150 тыс. Записей. Когда я запускаю его для своего крупнейшего клиента, он возвращает 600 000 записей и занимает более десяти минут.

Может быть, моя проблема в том, что при количестве возвращаемых записей будет трудно добиться хорошей производительности, или то, что я описал выше, похоже на возможности SQL Server?

Ответы [ 10 ]

6 голосов
/ 27 января 2010

Это могут быть строки. Но более вероятно, что клиент, сгенерировавший в 4 раза больше данных, также имеет в 4 раза большую активность в базе данных в других областях. Это означает в 4 раза больше использования памяти, в 4 раза больше дискового ввода-вывода и в 4 раза больше блокировок. Убедитесь, что оборудование выделено правильно.

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

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

3 голосов
/ 27 января 2010

Помимо количества записей, что еще отличается между двумя системами:

  • ОЗУ доступно для SQL
  • ядер процессора
  • Конфигурация ввода-вывода (количество шпинделей в RAID, тип RAID, конфигурация LUN)
  • Путь ввода-вывода (расположение логических и физических дисков, расположение базы данных mdf / ndf / ldf файлов)
  • фрагментация индекса
  • загрузка на SQL Server
  • загрузка на хост-машине

При сравнении двух мест для SET STATISTICS IO ON:

  • 600К делает примерно в 4 раза больше операций ввода-вывода по сравнению с местоположением 150К? Тогда разница во времени может быть полностью связана с различиями в оборудовании.
  • Является ли количество логических операций ввода-вывода в строках х4 раза, но физическое число операций ввода-вывода сильно отличается? Тогда у вас есть проблемы с оперативной памятью (недостаточно для кэширования базы данных в памяти).
  • Является ли количество физических операций ввода-вывода близким к ожидаемому в 4 раза, но время сильно отличается? Тогда вы, вероятно, имеете дело с фрагментацией.
  • Значительно ли количество операций ввода-вывода отличается от ожидаемого в 4 раза? Тогда у вас будет другой план, который, вероятно, будет зависеть от очень разных показателей и оценок.

Это, конечно, дикие снимки в темноте без надлежащих данных для их резервного копирования. Считайте их догадкой, а не авторитетным решением.

1 голос
/ 28 января 2010

Глядя на вашу статистику ввода-вывода:

Table 'RefStuExitCatg'. Scan count 1, logical reads 22810 ...
Table 'RefEngLangArtsTestProfcy'. Scan count 1, logical reads 22810 ... 
Table 'RefEngLangAcqstnStatSt'. Scan count 1, logical reads 22810 ...

против

Table 'RefStuExitCatg'. Scan count 1, logical reads 1514532, ...  
Table 'RefEngLangArtsTestProfcy'. Scan count 1, logical reads 1514532,...
Table 'RefEngLangAcqstnStatSt'. Scan count 1, logical reads 1514532, ...

быстрый запрос должен прочитать 22810 страниц во всех этих таблицах 'Ref ...'. Для сравнения медленный запрос должен прочитать 1514532 страницы. Это 1.5M против 22k, что в 66 раз больше. Таким образом, ваша медленная база данных имеет гораздо большую разницу в размерах данных, чем те строки, которые вы знаете, - 150 000 или 600 000. Я бы сказал, что это довольно хорошее объяснение разницы.

1 голос
/ 27 января 2010

С какого количества возвращенных записей я должен начать ожидать проблем с производительностью?

В час.

Этот запрос:

SELECT  COUNT(*)
FROM    myreallybigtable 

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

Клиент-сервер I/O (который, вероятно, единственная вещь, от которой зависит и только от количество и размер возвращаемых записей) обычно является одним из наименее важных факторов.

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

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

1 голос
/ 27 января 2010

Сначала необходимо определить, сколько времени занимает фактический запрос, а затем вы можете определить, сколько времени потребуется, чтобы вернуть клиенту целые 600Кб строки (что, вероятно, не следует делать). Предполагая, что каждая строка данных, скажем, 100 байтов, вы возвращаете клиенту 60 МБ. Это будет больно.

0 голосов
/ 01 февраля 2010

Рассматривали ли вы физический дизайн базы данных на обоих сайтах?Возможно, что клиент с большой БД хранит «более старые» данные на более медленных дисках, и это может быть причиной медленного выполнения запроса.

0 голосов
/ 27 января 2010

Вот статистика ввода-вывода для запроса, который завершается в разумные сроки:

Table '#tmpProgramSet_0000000017E2'. Scan count 11405, logical reads 36450, physical reads 0, read-ahead reads 61, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefStuExitCatg'. Scan count 1, logical reads 22810, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefEngLangArtsTestProfcy'. Scan count 1, logical reads 22810, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefEngLangAcqstnStatSt'. Scan count 1, logical reads 22810, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table '#TempRace_0000000017E1'. Scan count 1, logical reads 11405, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table '#TempSchool_0000000017E0'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'stu'. Scan count 10939, logical reads 47465, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table '#68CACE20'. Scan count 1, logical reads 13814, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefEductlSrvcInstn'. Scan count 1, logical reads 448, physical reads 0, read-ahead reads 372, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefEnrlmtStat'. Scan count 1, logical reads 27628, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'StuEnrlmt'. Scan count 2, logical reads 141994, physical reads 60, read-ahead reads 200, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefGrdLvl'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table '#4D22B3AB'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefGndr'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefCntryCode'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefRace'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'RefFedEnctyRaceCatg'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

и из моего длинного запроса

Table '#tmpProgramSet_0000000017F5'. Scan count 757266, logical reads 2418742, physical reads 0, read-ahead reads 158, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefStuExitCatg'. Scan count 1, logical reads 1514532, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefEngLangArtsTestProfcy'. Scan count 1, logical reads 1514532, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefEngLangAcqstnStatSt'. Scan count 1, logical reads 1514532, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#TempRace__0000000017F4'. Scan count 1, logical reads 757266, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#TempSchool__0000000017F3'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'stu'. Scan count 586229, logical reads 2711554, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#065B3107'. Scan count 1, logical reads 637919, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefEductlSrvcInstn'. Scan count 1, logical reads 448, physical reads 0, read-ahead reads 332, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefEnrlmtStat'. Scan count 1, logical reads 1276828, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StuEnrlmt'. Scan count 2, logical reads 2692331, physical reads 1386, read-ahead reads 97737, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefGrdLvl'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#780D11B0'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefGndr'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefCntryCode'. Scan count 1, logical reads 4, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefRace'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'RefFedEnctyRaceCatg'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
0 голосов
/ 27 января 2010

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

0 голосов
/ 27 января 2010

Хорошо, готовься .... Это оригинальный сохраненный процесс, который я унаследовал. Дайте мне знать, если вы хотите увидеть изменения, которые я сделал.

В разделе с комментарием "- ТУТ" начинаются проблемы с реальной производительностью.

ALTER PROCEDURE [dbo].MyProc
@LEAESIID int,
@AcademicYear varchar(10),
@ReportType varchar(16),
@SchoolESIID varchar(max),
-- 
@Grade varchar(8000),
@Gender varchar(8000),
@Race varchar(8000),
--
@AsOfDate datetime,
--
@UserID int
AS

create table #TempSchool
(
    SchoolESIID int
)
Create table #TempRace
(
    Race varchar(60)
)

declare @CALPADSSnpshtKey int
select @CALPADSSnpshtKey = 
    CALPADSSnpshtKey 
    from vwCertSnpshtRptngSnpsht cs2
    Where 
    -- Filter to correct snapshot
        rtrim(ltrim(cs2.AcdmcYearCode)) = rtrim(ltrim(@AcademicYear)) AND
        rtrim(ltrim(cs2.LEARptngEsiId)) in (select rtrim(ltrim(ParsedValue)) from dbo.tfnParseStringIntoTable(@LEAESIID, ',')) AND
        rtrim(ltrim(cs2.RptngTypeCode)) = rtrim(ltrim(@ReportType)) 

Insert into #TempSchool
select ParsedValue from dbo.tfnParseStringIntoTable(@SchoolESIID, ',')  
Insert into #TempRace
select ParsedValue from dbo.tfnParseStringIntoTable(@Race, ',') 

/*
Select query to pull back data from the reporting views.
Since this report is based around enrollment information, the primary table will be StuEnrlmt.
*/
declare 
    @UserLevel nVarchar(10),
    @ESILEAList nvarchar(max),
    @ESISchoolList nvarchar(max)

-- added by jackson chan 090109
-- program
    create table #tmpProgramSet (
        StuKey int
        , CALPADSSnpshtKey int
        , TitleIPartCMigrantFlag char(1)
        , SocioEconomicallyDisadvantagedFlag char(1)
        , SpecialEducationFlag char(1)
        , GiftedAndTalentedFlag char(1)
    )

    insert into #tmpProgramSet
    select se.StuKey,
        se.CALPADSSnpshtKey ,
        max(isnull(case sp.EduPgmCode
            when '135' then 'Y'
            else 'N'
        end, 'N')) as TitleIPartCMigrantFlag,
        max(case
            when 
                isnull(sp.EduPgmCode, 000) = 175 OR
                isnull(s.HighstEduLvlCode, 0) = 14
            then 'Y' 
            else 'N'
        end ) as SocioEconomicallyDisadvantagedFlag,
        max(isnull(case sp.EduPgmCode
            when '144' then 'Y'
            else 'N'
        end, 'N')) as SpecialEducationFlag,
        max(isnull(case sp.EduPgmCode
            when '127' then 'Y'
            else 'N'
        end, 'N')) as GiftedAndTalentedFlag
    from    dbo.vwStuEnrlmtRptngSnpsht se inner join 
            dbo.vwStuRptngSnpsht s on 
                se.StuKey = s.StuKey and
                se.CALPADSSnpshtKey = s.CALPADSSnpshtKey 
                inner join #TempSchool schl2 on 
                se.SchlAtndncEsiID = schl2.SchoolESIID   and
                se.LEARptngESIID = @LEAESIID left outer join
            dbo.vwStuPgmRptngSnpsht sp on 
                se.StuKey = sp.StuKey and
                se.CALPADSSnpshtKey = sp.CALPADSSnpshtKey
        group by se.StuKey, se.CALPADSSnpshtKey 
        order by se.StuKey;

--HERE
    Select distinct
        se.LEARptngEsiID,
        se.SchlAtndncEsiID  as SchlAtndncEsiID,
        se.SchlAtndncCDSCode as SchlAtndncCode,
        se.SchlAtndncName as SchlAtndncName,
        se.SchlAtndncType as SchlAtndncType,
        se.StuKey,
        s.StuIDStwdCal,
        isnull(s.StuLastOrSrnmLgl,'') + ', ' + isnull(s.StuFstNameLgl,'') + ' ' + isnull(s.StuMdlNameLgl,'') as StudentName,
        se.StuIDLcl,
        s.GndrCode,
        isnull(case
                when s.StuHspncEnctyIndctr = 'Y' then 'Hispanic'
                when s.StuEnctyMsngIndctr = 'Y' or s.StuRaceMsngIndctr = 'Y' then 'Missing'
                when s.EthnicityRaceCode2 is not null then 'Multiple' -- if a second race is populated,then Multiple
                else s.EthnicityRaceCode1
        end, 'Missing') as RaceEnthnicity,
        se.GrdLvlCode,
        isnull(
            case s.EngLangAcqstnStatStCode
                when 'EL' then 'Y'
                else 'N'
            end, 'N') as EnglishLearner,
        isnull(
            case
            when 
                -- if a value is null, set it to any value that will evaluate to false in the expression
                -- only students with valid information should be counted as Title III Eligible Immigrants
            -- disabled by jackson chan 12/08/09. Per defect 1605, Student Birth Country Special Circumstance Indicator is not a required field anymore
                --isnull(s.StuIneligSnorImgrntIndctr, 'Y') = 'N' AND
                isnull(s.StuEnrldUSSchlLessThanThreCumltvYrsIndctr, 'N') = 'Y' AND
                isnull(s.CntryCode, 'US') != 'US' AND
                isnull(se.EnrlmtStatCode, '0') = '10' AND
                -- Calculate age from birth date
                isnull(case 
                when datepart(month, s.StuBirDate) < datepart(month, getdate())
                    then datediff(year, s.StuBirDate, getdate())
                when datepart(month, s.StuBirDate) = datepart(month, getdate()) and datepart(day, s.StuBirDate) <= datepart(day, getdate()) 
                    then datediff(year, s.StuBirDate, getdate())
                else datediff(year, s.StuBirDate, getdate()) -1
                end , 0) between 3 and 21 AND
                isnull(se.GrdLvlCode, 'AD') != 'AD'
            then 'Y'
            else 'N'
            end, 'N') as TitleIIIEligibleImmigrantFlag,
        sp.SocioEconomicallyDisadvantagedFlag,
        isnull(case when s.EngLangAcqstnStatStCode in ('EL', 'RFEP')  AND s.EngLangArtsTestProfcyCode = 'N' then 'Y'
            else 'N'
        end, 'N') as LimitedEnglishProficientFlag,
        sp.TitleIPartCMigrantFlag,
        sp.SpecialEducationFlag,
        sp.GiftedAndTalentedFlag
    From 
        dbo.vwStuEnrlmtRptngSnpsht se
        inner join dbo.vwStuRptngSnpsht s on 
            se.StuKey = s.StuKey and
            se.CALPADSSnpshtKey = s.CALPADSSnpshtKey
        left join #tmpProgramSet sp on 
            se.StuKey = sp.StuKey and
            se.CALPADSSnpshtKey = sp.CALPADSSnpshtKey
        inner join #TempSchool schl on 
            se.SchlAtndncEsiID = schl.SchoolESIID   and
            se.LEARptngESIID = @LEAESIID
        inner join #TempRace r on 
            isnull(case
                when s.StuHspncEnctyIndctr = 'Y' then 'Hispanic'
                when s.StuEnctyMsngIndctr = 'Y' or s.StuRaceMsngIndctr = 'Y' then 'Missing'
                when s.EthnicityRaceCode2 is not null then 'Multiple' -- if a second race is populated,then Multiple
                else s.EthnicityRaceCode1
            end, 'Missing') = r.Race 
    Where
        -- Enrollments
        se.StuEsiRltnspExpctdSchlStartDate <= @AsOfDate AND (se.WithdrlDate is null OR se.WithdrlDate >= @AsOfDate) AND
        se.EnrlmtStatCode = '10' AND
        se.StuExitCatgCode != 'N470' AND -- no shows are not considered in active enrollment numbers
        -- Filter to correct snapshot
        se.CALPADSSnpshtKey = @CALPADSSnpshtKey AND
        -- User selection filters
        rtrim(ltrim(se.GrdLvlCode))                       in (select rtrim(ltrim(ParsedValue)) from dbo.tfnParseStringIntoTable(@Grade, ',')) AND
        rtrim(ltrim(s.GndrCode))                              in (select rtrim(ltrim(ParsedValue)) from dbo.tfnParseStringIntoTable(@Gender, ',')) 
0 голосов
/ 27 января 2010

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

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

Мы выполняем запросы в нашей системе отчетов, которые обычно возвращают 300 000 записей, объединяющих 20 таблиц со многими взаимосвязанными подзапросами, и получают время отклика менее секунды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...