У меня есть этот код, который заставляет мою сетку тайм-аут при попытке выполнить ее от одного конкретного пользователя в 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?
@RuslanDev Спасибо за ответ, как вы пользуетесь пейджингом? Я искал руководство по Acumatica Framework и не смог найти, где упоминается активация или дезактивация подкачки. С Уважением
@Maxime вы посмотрели план запроса? Я думаю, вам может потребоваться добавить индекс в поле usrBSD и еще один в usrEBDR для лучшей производительности - во всех случаях вы должны просмотреть сгенерированный план ... docs.microsoft.com/en-us/azure/sql-database/…
@RuslanDev Я взглянул на план запроса, но не смог его использовать, Azure не дает мне много советов по созданию индексов, несмотря на то, что заказчик использовал эту базу в течение последних двух лет.
Чтобы включить разбиение на страницы для 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, это просто представление для отображения данных, никакой логики нет. Я попробую индексы :).
На самом деле уже есть индекс с обоими этими полями в БД (и множеством других полей, поэтому я не знаю, действительно ли это полезный индекс). (Я отредактировал свой вопрос)
Включено ли разбиение по страницам в PXGrid в пользовательском интерфейсе, чтобы уменьшить количество записей, запрашиваемых с SQL-сервера? При отключенном разбиении на страницы PXGrid всегда запрашивает все записи из базы данных. Еще одно предложение - проанализировать план выполнения вашего первого запроса в SSMS и, при необходимости, создать один или несколько индексов для ускорения выполнения этого запроса.