Оптимизация запросов, используемых в PXSelect

У меня есть этот код, который заставляет мою сетку тайм-аут при попытке выполнить ее от одного конкретного пользователя в Acumatica в базе данных MSSQL Azure S2.

Для базы данных MSSQL Azure S3 тайм-аут не истекает.

  public class CTInquiriesCollecteur : PXGraph<CTInquiriesCollecteur>
    {
        [PXFilterable]
        public PXSelectJoin<POOrder,
            InnerJoin<Contact,
                On<Contact.bAccountID, Equal<POOrder.vendorID>>,
               InnerJoin<CROpportunity,
                   On<CROpportunity.opportunityID, Equal<POOrderExt.usrBSD>,Or<CROpportunityExt.usrEBDR,Equal<POOrderExt.usrBRD>>>>>,
            Where<Contact.userID, Equal<Current<AccessInfo.userID>>>> poCollecteur;
    }
}

Он работает с другими пользователями (но у них возвращено меньше записей, чем у той, которая вызвала его сбой) Когда я пытаюсь выполнить запрос с помощью своего диспетчера SQL, он работает нормально и возвращает 1743 строки, которые мне нужны:

Select * from POOrder inner Join Contact on Contact.BaCcountID=POOrder.VendorID Inner join CROpportunity
 on ( CROpportunity.opportunityID=POOrder.usrBSD or CROpportunity.opportunityID=POOrder.UsrBRD) 
 Where poorder.CompanyID=5 and Contact.companyID=5 and CROpportunity.CompanyID=5 and Contact.contactID=12688

Этот запрос, возвращающий все строки (без фильтрации по contactID), работает нормально (но он возвращает НАМНОГО больше строк, чем тот, который фильтрует по contactID):

 public class CTInquiriesEmployes : PXGraph<CTInquiriesEmployes>
    {
        [PXFilterable]
        public PXSelectReadonly2<POOrder, InnerJoin<CROpportunity, 
            On<CROpportunity.opportunityID, Equal<POOrderExt.usrBSD>,Or<CROpportunityExt.usrEBDR,Equal<POOrderExt.usrBRD>>>>> po;
    }

У вас есть какие-нибудь подсказки, как я могу оптимизировать этот запрос, чтобы мне не нужна была база данных S3 в Azure, и я мог бы придерживаться S2?

Редактировать :

Я посмотрел на план запроса, и мне кажется, что это запрос, сгенерированный образцом кода, и время ожидания моей базы данных:

(@P0 uniqueidentifier,@P1 char(1))SELECT TOP (20) [POOrder].[BranchID], [POOrder].[OrderType], [POOrder].[OrderNbr], [POOrder].[VendorID], [POOrder].[VendorLocationID], [POOrder].[OrderDate], [POOrder].[ExpectedDate], [POOrder].[ExpirationDate], [POOrder].[Status], [POOrder].[Hold], [POOrder].[Approved], [POOrder].[Cancelled], [POOrder].[Receipt], [POOrder].[IsTaxValid], [POOrder].[IsOpenTaxValid], [POOrder].[NoteID], (SELECT TOP (1) [Note_s18].[NoteText] FROM [dbo].[Note] [Note_s18] WHERE [Note_s18].CompanyID IN (1, 5) AND 2 = SUBSTRING([Note_s18].CompanyMask, 2, 1) & 2 AND [Note_s18].[NoteId] = [POOrder].[NoteID]), (SELECT TOP (1) COUNT(*) FROM [dbo].[NoteDoc] [NoteDoc_s20] WHERE [NoteDoc_s20].CompanyID IN (1, 5) AND 2 = SUBSTRING([NoteDoc_s20].CompanyMask, 2, 1) & 2 AND [NoteDoc_s20].[NoteId] = [POOrder].[NoteID]), NULL, [POOrder].[CuryID], [POOrder].[CuryInfoID], [POOrder].[LineCntr], [POOrder].[VendorRefNbr], [POOrder].[CuryOrderTotal], [POOrder].[OrderTotal], [POOrder].[CuryControlTotal], [POOrder].[ControlTotal], [POOrder].[OrderQty], [POOrder].[CuryLineTotal], [POOrder].[LineTotal], [POOrder].[DiscTot], [POOrder].[CuryDiscTot], [POOrder].[CuryTaxTotal], [POOrder].[TaxTotal], [POOrder].[CuryVatExemptTotal], [POOrder].[VatExemptTotal], [POOrder].[CuryVatTaxableTotal], [POOrder].[VatTaxableTotal], [POOrder].[TaxZoneID], [POOrder].[TermsID], [POOrder].[RemitAddressID], [POOrder].[RemitContactID], [POOrder].[SOOrderType], [POOrder].[SOOrderNbr], [POOrder].[BLType], [POOrder].[BLOrderNbr], [POOrder].[RQReqNbr], [POOrder].[OrderDesc], [POOrder].[tstamp], [POOrder].[CreatedByID], [POOrder].[CreatedByScreenID], [POOrder].[CreatedDateTime], [POOrder].[LastModifiedByID], [POOrder].[LastModifiedByScreenID], [POOrder].[LastModifiedDateTime], [POOrder].[ShipDestType], [POOrder].[SiteID], [POOrder].[ShipToBAccountID], [POOrder].[ShipToLocationID], [POOrder].[ShipAddressID], [POOrder].[ShipContactID], [POOrder].[CuryOpenOrderTotal], [POOrder].[OpenOrderTotal], [POOrder].[CuryOpenLineTotal], [POOrder].[OpenLineTotal], [POOrder].[CuryOpenTaxTotal], [POOrder].[OpenTaxTotal], [POOrder].[OpenOrderQty], [POOrder].[EmployeeID], [POOrder].[OwnerWorkgroupID], [POOrder].[DontPrint], [POOrder].[Printed], [POOrder].[DontEmail], [POOrder].[Emailed], [POOrder].[FOBPoint], [POOrder].[ShipVia], [POOrder].[OrderWeight], [POOrder].[OrderVolume], [POOrder].[PrepaymentDocType], [POOrder].[PrepaymentRefNbr], [POOrder].[UsrObservation], [POOrder].[UsrBSD], [POOrder].[UsrBRD], [POOrder].[UsrTypePO], [POOrder].[UsrPAV], [POOrder].[UsrLicenseExport], [POOrder].[UsrCodeMouvement], [POOrder].[UsrNumeroContainer], [POOrder].[UsrDepartBateauDate], [POOrder].[UsrFiliere], [Contact].[DisplayName], [Contact].[ContactID], [Contact].[RevisionID], [Contact].[DefAddressID], [Contact].[Title], [Contact].[FirstName], [Contact].[MidName], [Contact].[LastName], [Contact].[Salutation], [Contact].[BAccountID], [Contact].[FullName], [Contact].[ParentBAccountID], [Contact].[EMail], [Contact].[WebSite], [Contact].[Fax], [Contact].[FaxType], [Contact].[Phone1], [Contact].[Phone1Type], [Contact].[Phone2], [Contact].[Phone2Type], [Contact].[Phone3], [Contact].[Phone3Type], [Contact].[DateOfBirth], [Contact].[NoteID], NULL, NULL, NULL, [Contact].[IsActive], [Contact].[NoFax], [Contact].[NoMail], [Contact].[NoMarketing], [Contact].[NoCall], [Contact].[NoEMail], [Contact].[NoMassMail], [Contact].[Gender], [Contact].[MaritalStatus], [Contact].[Anniversary], [Contact].[Spouse], [Contact].[Img], [Contact].[Synchronize], [Contact].[ContactType], CASE WHEN  ( [Contact].[ContactType] = 'AP') THEN  -10 WHEN  ( ( [Contact].[ContactType] = 'SP')) THEN  -5 WHEN  ( ( [Contact].[ContactType] = 'EP')) THEN  -1 WHEN  ( ( [Contact].[ContactType] = 'PN')) THEN  0 WHEN  ( ( [Contact].[ContactType] = 'LD')) THEN  10 END, [Contact].[DuplicateStatus], CASE WHEN  ( [Contact].[DuplicateStatus] = 'PD' AND 1 = 0 ) THEN  CONVERT(BIT, 1) ELSE  CONVERT(BIT, 0) END, [Contact].[MajorStatus], [Contact].[Status], [Contact].[Resolution], [Contact].[AssignDate], [Contact].[QualificationDate], [Contact].[ClassID], [Contact].[Source], [Contact].[WorkgroupID], [Contact].[OwnerID], [Contact].[UserID], [Contact].[CampaignID], [Contact].[Method], [Contact].[IsConvertable], [Contact].[GrammValidationDateTime], [Contact].[ConvertedBy], [Contact].[CreatedByID], [Contact].[CreatedByScreenID], [Contact].[CreatedDateTime], [Contact].[LastModifiedByID], [Contact].[LastModifiedByScreenID], [Contact].[LastModifiedDateTime], '"' +  ( [Contact].[DisplayName] +  ( '"' +  ( ' ' +  ( '(' +  ( [Contact].[EMail] +  ')'))))), [Contact].[ExtRefNbr], [Contact].[tstamp], [Contact].[DeletedDatabaseRecord], [CROpportunity].[OpportunityNumber], [CROpportunity].[OpportunityID], [CROpportunity].[BranchID], [CROpportunity].[OpportunityAddressID], [CROpportunity].[OpportunityContactID], [CROpportunity].[AllowOverrideContactAddress], [CROpportunity].[BAccountID], [CROpportunity].[LocationID], [CROpportunity].[ContactID], [CROpportunity].[ConvertedLeadID], [CROpportunity].[CROpportunityClassID], [CROpportunity].[OpportunityName], [CROpportunity].[Description], [CROpportunity].[ParentBAccountID], [CROpportunity].[ProjectID], [CROpportunity].[CloseDate], [CROpportunity].[StageID], [CROpportunity].[StageChangedDate], [CROpportunity].[CampaignSourceID], [CROpportunity].[MajorStatus], [CROpportunity].[Status], [CROpportunity].[Resolution], [CROpportunity].[AssignDate], [CROpportunity].[ClosingDate], [CROpportunity].[WorkgroupID], [CROpportunity].[OwnerID], [CROpportunity].[CuryID], [CROpportunity].[CuryInfoID], [CROpportunity].[LineTotal], [CROpportunity].[CuryLineTotal], [CROpportunity].[IsTaxValid], [CROpportunity].[TaxTotal], [CROpportunity].[CuryTaxTotal], [CROpportunity].[ManualTotalEntry], [CROpportunity].[Amount], CASE WHEN  ( [CROpportunity].[ManualTotalEntry] = CONVERT(BIT, 1)) THEN  [CROpportunity].[Amount] ELSE  [CROpportunity].[LineTotal] END, [CROpportunity].[CuryAmount], [CROpportunity].[DiscTot], [CROpportunity].[CuryDiscTot], [CROpportunity].[ProductsAmount], [CROpportunity].[CuryProductsAmount], [CROpportunity].[CuryVatExemptTotal], [CROpportunity].[VatExemptTotal], [CROpportunity].[CuryVatTaxableTotal], [CROpportunity].[VatTaxableTotal], [CROpportunity].[TaxZoneID], [CROpportunity].[ARRefNbr], [CROpportunity].[OrderType], [CROpportunity].[OrderNbr], [CROpportunity].[NoteID], NULL, NULL, NULL, (SELECT TOP (1) CASE WHEN  ( [CRActivityStatistics_s217].[LastIncomingActivityDate] IS NOT NULL AND [CRActivityStatistics_s217].[LastOutgoingActivityDate] IS NULL) THEN  [CRActivityStatistics_s217].[LastIncomingActivityDate] WHEN  ( [CRActivityStatistics_s217].[LastOutgoingActivityDate] IS NOT NULL AND [CRActivityStatistics_s217].[LastIncomingActivityDate] IS NULL) THEN  [CRActivityStatistics_s217].[LastOutgoingActivityDate] WHEN  ( [CRActivityStatistics_s217].[LastIncomingActivityDate] > [CRActivityStatistics_s217].[LastOutgoingActivityDate]) THEN  [CRActivityStatistics_s217].[LastIncomingActivityDate] ELSE  [CRActivityStatistics_s217].[LastOutgoingActivityDate] END FROM [CRActivityStatistics] [CRActivityStatistics_s217] WHERE [CRActivityStatistics_s217].CompanyID = 5 AND [CRActivityStatistics_s217].[NoteID] = [CROpportunity].[NoteID] ORDER BY CASE WHEN  ( [CRActivityStatistics_s217].[LastIncomingActivityDate] IS NOT NULL AND [CRActivityStatistics_s217].[LastOutgoingActivityDate] IS NULL) THEN  [CRActivityStatistics_s217].[LastIncomingActivityDate] WHEN  ( [CRActivityStatistics_s217].[LastOutgoingActivityDate] IS NOT NULL AND [CRActivityStatistics_s217].[LastIncomingActivityDate] IS NULL) THEN  [CRActivityStatistics_s217].[LastOutgoingActivityDate] WHEN  ( [CRActivityStatistics_s217].[LastIncomingActivityDate] > [CRActivityStatistics_s217].[LastOutgoingActivityDate]) THEN  [CRActivityStatistics_s217].[LastIncomingActivityDate] ELSE  [CRActivityStatistics_s217].[LastOutgoingActivityDate] END), [CROpportunity].[Source], [CROpportunity].[tstamp], [CROpportunity].[CreatedByScreenID], [CROpportunity].[CreatedByID], [CROpportunity].[CreatedDateTime], [CROpportunity].[LastModifiedByID], [CROpportunity].[LastModifiedByScreenID], [CROpportunity].[LastModifiedDateTime], [CROpportunity].[ProductCntr], [CROpportunity].[UsrObservation], [CROpportunity].[UsrDateCollecte], [CROpportunity].[UsrDateReprise], [CROpportunity].[UsrCollecteur], [CROpportunity].[UsrTraiteur], [CROpportunity].[UsrEBDR], CASE WHEN [POOrder].[OrderType] = 'RO' THEN 'Normal' END AS orderby_case_s232
FROM [POOrder] [POOrder]
INNER JOIN [Contact] [Contact] ON [Contact].CompanyID = 5 AND [Contact].[DeletedDatabaseRecord] = 0 AND [Contact].[BAccountID] = [POOrder].[VendorID]
INNER JOIN [CROpportunity] [CROpportunity] ON [CROpportunity].CompanyID = 5 AND ([CROpportunity].BranchID IS NULL OR [CROpportunity].BranchID = 25) AND ([CROpportunity].[OpportunityID] = [POOrder].[UsrBSD] OR [CROpportunity].[UsrEBDR] = [POOrder].[UsrBRD])
WHERE [POOrder].CompanyID = 5 AND ([POOrder].BranchID IS NULL OR [POOrder].BranchID = 25) AND [Contact].[UserID] = @P0 AND [POOrder].[Status] = @P1
ORDER BY [POOrder].[OrderNbr], orderby_case_s232 OPTION(OPTIMIZE FOR UNKNOWN)

Изменить 2:

Заглянув в БД для таблицы POOrder, у меня уже есть несколько индексов, один по первичным ключам, один по поставщику, один по NoteID и вот этот странный:

CREATE NONCLUSTERED INDEX [nci_wi_POOrder_35EBA31CDEA74D944FD7F833E2CF9116] ON [dbo].[POOrder]
(
    [BranchID] ASC,
    [CompanyID] ASC,
    [UsrBSD] ASC
)
INCLUDE (   [Approved],
    [BLOrderNbr],
    [BLType],
    [Cancelled],
    [ControlTotal],
    [CreatedByID],
    [CreatedByScreenID],
    [CreatedDateTime],
    [CuryControlTotal],
    [CuryDiscTot],
    [CuryID],
    [CuryInfoID],
    [CuryLineTotal],
    [CuryOpenLineTotal],
    [CuryOpenOrderTotal],
    [CuryOpenTaxTotal],
    [CuryOrderTotal],
    [CuryTaxTotal],
    [CuryVatExemptTotal],
    [CuryVatTaxableTotal],
    [DiscTot],
    [DontEmail],
    [DontPrint],
    [Emailed],
    [EmployeeID],
    [ExpectedDate],
    [ExpirationDate],
    [FOBPoint],
    [Hold],
    [IsOpenTaxValid],
    [IsTaxValid],
    [LastModifiedByID],
    [LastModifiedByScreenID],
    [LastModifiedDateTime],
    [LineCntr],
    [LineTotal],
    [NoteID],
    [OpenLineTotal],
    [OpenOrderQty],
    [OpenOrderTotal],
    [OpenTaxTotal],
    [OrderDate],
    [OrderDesc],
    [OrderQty],
    [OrderTotal],
    [OrderVolume],
    [OrderWeight],
    [OwnerWorkGroupID],
    [PrepaymentDocType],
    [PrepaymentRefNbr],
    [Printed],
    [Receipt],
    [RemitAddressID],
    [RemitContactID],
    [RQReqNbr],
    [ShipAddressID],
    [ShipContactID],
    [ShipDestType],
    [ShipToBAccountID],
    [ShipToLocationID],
    [ShipVia],
    [SiteID],
    [soordernbr],
    [soordertype],
    [Status],
    [TaxTotal],
    [TaxZoneID],
    [TermsID],
    [tstamp],
    [UsrBRD],
    [UsrCodeMouvement],
    [UsrDepartBateauDate],
    [UsrFiliere],
    [UsrLicenseExport],
    [UsrNumeroContainer],
    [UsrObservation],
    [UsrPAV],
    [UsrTypePO],
    [VatExemptTotal],
    [VatTaxableTotal],
    [VendorID],
    [VendorLocationID],
    [VendorRefNbr]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

Я думаю, что это был автоматически сгенерированный индекс (может быть, в Azure? Я не могу найти его в истории автоматической настройки), но я не знаю, почему и следует ли мне сохранить его и просто проиндексировать на UsrBSD и UserBRD?

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

RuslanDev 08.08.2018 18:43

@RuslanDev Спасибо за ответ, как вы пользуетесь пейджингом? Я искал руководство по Acumatica Framework и не смог найти, где упоминается активация или дезактивация подкачки. С Уважением

Maxime 08.08.2018 18:50

@Maxime вы посмотрели план запроса? Я думаю, вам может потребоваться добавить индекс в поле usrBSD и еще один в usrEBDR для лучшей производительности - во всех случаях вы должны просмотреть сгенерированный план ... docs.microsoft.com/en-us/azure/sql-database/…

Gabriel 08.08.2018 21:34

@RuslanDev Я взглянул на план запроса, но не смог его использовать, Azure не дает мне много советов по созданию индексов, несмотря на то, что заказчик использовал эту базу в течение последних двух лет.

Maxime 09.08.2018 12:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
151
1

Ответы 1

Чтобы включить разбиение на страницы для PXGrid, в Aspx вы должны, по крайней мере, установить для его свойства AllowPaging значение Истинный или установить свойство SkinID на одну из обложек, для которых для AllowPaging установлено значение Истинный (например, Первичный). В случае, если для представления данных poCollecteur определен делегат, вы также должны следовать подходу, показанному ниже, чтобы сохранить разбиение на страницы и не извлекать все записи из базы данных каждый раз, когда данные выбираются из представления данных poCollecteur.

public class AccountByPeriodEnq_Extension : PXGraphExtension<AccountByPeriodEnq>
{
    [PXFilterable]
    public PXSelectOrderBy<GLTranR,
        OrderBy<Asc<GLTranR.tranDate,
            Asc<GLTranR.refNbr,
            Asc<GLTranR.batchNbr,
            Asc<GLTranR.module,
            Asc<GLTranR.lineNbr>>>>>>> GLTranEnq;

    protected IEnumerable glTranEnq()
    {
        int startRow = PXView.StartRow;
        int totalRows = 0;

        var result = Base.GLTranEnq.View.Select(PXView.Currents,
            PXView.Parameters, PXView.Searches, PXView.SortColumns,
            PXView.Descendings, PXView.Filters, ref startRow,
            PXView.MaximumRows, ref totalRows);

        PXView.StartRow = 0;
        return result;
    }
}

Спасибо за ответ, после проверки для allowpaging уже установлено значение true, и нет делегата для pocollector, это просто представление для отображения данных, никакой логики нет. Я попробую индексы :).

Maxime 09.08.2018 12:08

На самом деле уже есть индекс с обоими этими полями в БД (и множеством других полей, поэтому я не знаю, действительно ли это полезный индекс). (Я отредактировал свой вопрос)

Maxime 09.08.2018 13:37

Другие вопросы по теме