다음을 통해 공유


코드 최적화

캔버스 앱이 다양한 비즈니스 요구 사항을 충족하도록 발전함에 따라 최적의 성능을 유지하는 것이 중요합니다. 데이터 처리, 사용자 인터페이스 디자인 및 앱 기능은 모두 코드 최적화에 대한 신중한 접근 방식이 필요합니다.

캔버스 앱이 더 복잡해지면 데이터 검색, 수식 복잡성 및 렌더링 속도에 문제가 발생할 수 있습니다. 강력한 기능과 반응성이 뛰어난 사용자 인터페이스의 균형을 맞추려면 코드 최적화에 대한 체계적인 접근 방식이 필요합니다.

Power Fx 수식 최적화

With 함수

With 함수는 단일 레코드의 수식을 계산합니다. 수식은 값을 계산하거나 데이터 수정이나 연결 작업 등의 작업을 수행할 수 있습니다. With를 사용하면 복잡한 수식을 더 작고 이름이 지정된 하위 수식으로 나누어서 읽기 쉽게 만들 수 있습니다. 이러한 명명된 값은 With의 범위로 제한된 간단한 지역 변수처럼 작동합니다. With는 자체적으로 포함되고, 이해하기 쉽고, 모든 선언적 수식 컨텍스트에서 작동하기 때문 컨텍스트나 전역 변수를 사용하는 것보다 좋습니다. 함수에 대해 With.

With 함수를 사용하는 Power Fx 수식의 스크린샷.

Concurrent 함수

Concurrent 함수를 사용하면 동일한 속성의 여러 수식에 커넥터 또는 Dataverse 호출이 있는 경우 동시에 평가할 수 있습니다. 일반적으로 ;(세미콜론) 연산자를 사용하여 여러 수식을 연결하면 해당 수식이 동시에 평가됩니다. Concurrent를 사용하면 앱이 ; 연산자를 사용한 후에도 속성의 모든 수식을 동시에 평가합니다. 이 동시 실행은 사용자가 결과를 기다리는 횟수가 줄어든다는 것을 의미합니다. 이전 호출이 완료될 때까지 데이터 호출이 시작되지 않는 경우 앱은 모든 요청 시간의 합계를 대기합니다. 데이터 호출이 동시에 시작되면 앱은 가장 긴 요청 시간 동안만 기다립니다. 함수에 대해 Concurrent.

Concurrent(
    ClearCollect(colAccounts1, Accounts),
    ClearCollect(colUsers1, Users),
    ClearCollect(colEnvDef1, 'Environment Variable Definitions'),
    ClearCollect(colEnvVal1, 'Environment Variable Values')
);

Coalesce 함수

Coalesce 함수는 인수를 순서대로 평가하고 공백이나 빈 문자열이 아닌 첫 번째 값을 반환합니다. 이 함수를 사용하면 공백 값이나 빈 문자열을 다른 값으로 교체하지만 공백이 아닌 값과 비어 있지 않은 문자열 값은 변경하지 않습니다. 모든 인수가 공백이거나 빈 문자열이면 함수는 공백을 반환합니다. Coalesce는 빈 문자열을 빈 값으로 변환하는 좋은 방법입니다.

예:

If(Not IsBlank(value1), value1, Not IsBlank(value2), value2)

값 1과 값 2를 두 번 평가해야 합니다. 이 함수는 다음과 같이 축소될 수 있습니다.

Coalesce(value1, value2)

IsMatch 함수

IsMatch 함수는 텍스트 문자열이 일반 문자, 미리 정의된 패턴 또는 정규식으로 구성된 패턴과 일치하는지 테스트합니다. 함수에 대해 IsMatch.

예를 들어 다음 수식은 미국 사회 보장 번호와 일치합니다.

IsMatch(TextInput1.Text, "\d{3}-\d{2}-\d{4}")

정규식 설명:

\\d 숫자(0-9)와 매칭합니다.

{3} 앞의 숫자 패턴(\d)이 정확히 세 번 발생하도록 지정합니다.

- 하이픈 문자와 매칭합니다.

{2} 앞의 숫자 패턴(\d)이 정확히 두 번 발생하도록 지정합니다.

{4} 앞의 숫자 패턴(\d)이 정확히 네 번 발생하도록 지정합니다.

IsMatch의 추가 예:

IsMatch(TextInput1.Text, "Hello World")
IsMatch(TextInput1\_2.Text, "(?!^\[0-9\]\\\*$)(?!^\[a-zA-Z\]\\\*$)(\[a-zA-Z0-9\]{8,10})")

앱 OnStart 최적화

캔버스 앱의 OnStart 속성은 앱이 시작될 때 발생하는 작업을 정의하는 데 중요한 역할을 합니다. 이 속성을 통해 앱 개발자는 전역 초기화 작업을 실행하고, 변수를 설정하고, 앱 시작 프로세스 중에 한 번만 발생해야 하는 작업을 수행할 수 있습니다. OnStart 속성을 이해하고 효과적으로 활용하는 것은 반응이 빠르고 효율적인 캔버스 앱을 만드는 데 필수적입니다.

권장되는 방법은 변수 설정을 명명된 수식으로 마이그레이션하여 App.OnStart 함수를 간소화하는 것입니다. 명명된 수식, 특히 앱 수명 주기 초기에 구성된 수식은 유리한 것으로 입증되었습니다. 이러한 수식은 데이터 호출을 기반으로 변수 초기화를 처리하여 코드에 더 깔끔하고 체계적인 구조를 제공합니다. 자세한 내용은 크고 복잡한 캔버스 앱 구축 - Power Apps | Microsoft Learn을 참고하세요.

참고

OnStart 속성은 필수적.입니다. 첫 번째 화면이 표시되기 전에 수행해야 하는 순서가 지정된 목록입니다. 무엇을 수행해야 하는지 뿐만 아니라 언제 작업을 순서에 따라 수행해야 하는지에 대해서도 매우 구체적이기 때문에 그렇지 않은 경우 수행할 수 있는 재정렬 및 최적화 연기가 제한됩니다.

시작 화면

App.OnStartNavigate 함수 호출이 포함되어 있으면 If 함수에 있고 거의 호출되지 않더라도 앱의 실행을 완료해야 합니다. OnStart 앱의 첫 번째 화면을 표시하기 전에.  App.StartScreen은 어떤 화면이 먼저 표시되어야 하는지를 나타내는 새로운 선언적 방법으로, 최적화를 차단하지 않습니다.

StartScreen 속성을 설정하면 App.OnStart가 완료되기 전의 첫 번째 화면이 표시됩니다. App.StartScreen declares는 전처리 없이 먼저 표시할 화면 개체입니다.

다음과 같은 코드를 작성하는 대신:

App.OnStart = Collect(OrdersCache, Orders);
If(Param("AdminMode") = "1", Navigate(AdminScreen), Navigate(HomeScreen))

코드를 다음과 같이 변경합니다.

App.OnStart = Collect(OrdersCache, Orders);
App.StartScreen = If(Param("AdminMode") = "1", AdminScreen, HomeScreen)

자세한 내용은 <https://Power Apps.microsoft.com/en-us/blog/app-startscreen-a-new-declarative-alternative-to-navigate-in-app-onstart/>를 참조하세요.

경고

StartScreenOnStart 사이의 종속성을 피하십시오. 전역 변수를 참조하는 명명된 수식을 참조하면 StartScreen이 올바르게 적용되지 않는 경쟁 조건이 발생할 수 있습니다. 참고: StartScreen과 OnStart 사이에 종속성이 없어야 합니다. StartScreen에서 전역 변수 참조를 차단하지만 명명된 수식을 참조할 수 있으며, 이 수식은 전역 변수를 참조하므로 StartScreen이 올바르게 적용되지 않는 경합 상태가 발생할 수 있습니다.

이름이 지정된 수식

명명된 수식은 App.Formulas 섹션에서 정의할 수 있는 정적 또는 상수입니다. App.Formulas에 선언되면 앱 어디에서나 사용할 수 있으며 해당 값은 항상 최신 상태로 유지됩니다. Power Apps의 명명된 공식을 사용하면 플랫폼에서 자동으로 관리 및 업데이트되는 값 또는 값 집합을 정의할 수 있습니다. 이 함수는 값 계산 및 유지 관리의 책임을 개발자에서 Power Apps로 이전하여 개발 프로세스를 간소화합니다. Power Apps의 명명된 수식은 앱 성능과 유지 관리성을 크게 향상시킬 수 있는 강력한 기능입니다.

명명된 수식은 앱 테마 선언을 처리할 수도 있습니다. 엔터프라이즈 앱이 구축되는 많은 경우, 우리는 일관된 모양과 사용자 경험을 제공하기 위해 앱이 공통 테마를 갖기를 원합니다. 테마를 생성하려면 App OnStart에서 선언해야 하는 변수가 10~100개 있습니다. 이로 인해 코드 길이와 앱 초기화 시간이 늘어났습니다.

최신 컨트롤은 테마 설정에 큰 도움이 되며 테마 처리를 위해 고객이 작성한 논리를 줄이는 데도 도움이 됩니다. 최신 컨트롤은 현재 프리뷰 상태입니다.

예를 들어, App.OnStart의 다음 코드를 App.Formulas로 이동하여 전역 변수 선언의 시작 시간을 줄일 수 있습니다.

Set(BoardDark, RGBA(181,136,99, 1));
Set(BoardSelect, RGBA(34,177,76,1));
Set(BoardRowWidth, 10);                      // expected 8 plus two guard characters for regular expressions.
Set(BoardMetadata, 8 \* BoardRowWidth + 1);   // which player is next, have pieces moved for castling rules, etc.
Set(BoardBlank, "----------------------------------------------------------------\_00000000000000");
Set(BoardClassic, "RNBQKBNR\_\_PPPPPPPP------------------------\_--------\_\_pppppppp\_\_rnbqkbnr\_\_0000000000");

코드는 다음과 같이 App.Formulas로 이동할 수 있습니다.

BoardSize = 70;
BoardLight = RGBA(240,217,181, 1);
BoardDark = RGBA(181,136,99, 1);
BoardSelect = RGBA(34,177,76,1);
BoardRowWidth = 10;                      // expected 8 plus two guard characters for regular expressions
BoardMetadata = 8 \* BoardRowWidth + 1;   // which player is next, have pieces moved for castling rules, etc.
BoardBlank = "----------------------------------------------------------------\_00000000000000";
BoardClassic = "RNBQKBNR\_\_PPPPPPPP------------------------\_--------\_\_pppppppp\_\_rnbqkbnr\_\_0000000000";

또 다른 예는 Lookups 설정입니다. 여기서 Dataverse 대신 Office 365에서 사용자 정보를 가져오려면 조회 수식을 변경해야 합니다. 모든 곳에서 코드를 변경하지 않고 변경이 필요한 곳은 단 한 곳뿐입니다.

UserEmail = User().Email;
UserInfo = LookUp(Users, 'Primary Email' = User().Email);
UserTitle = UserInfo.Title;
UserPhone = Switch(UserInfo.'Preferred Phone', 'Preferred Phone (Users)'.'Mobile Phone', UserInfo.'Mobile Phone',
UserInfo.'Main Phone');

이 공식은 계산의 본질을 구현합니다. 다른 값을 기반으로 UserEmail, UserInfo, UserTitleUserPhone을 결정하는 프로세스를 설명합니다. 이 논리는 캡슐화되어 앱 전체에서 광범위하게 활용될 수 있으며 단일 위치에서 수정될 수 있습니다. 적응성은 앱 전체에 흩어져 있는 수식을 변경할 필요 없이 Dataverse 사용자 테이블에서 Office 365 커넥터로 전환하도록 확장됩니다.

또 다른 방법은 countRows를 최적화하는 것입니다.

varListItems = CountRows(SampleList)

Set 함수를 사용하면 변수 varListItems가 샘플 목록의 초기 행 수로 초기화되고 목록 항목이 추가되거나 제거된 후 다시 설정되어야 합니다. 명명된 수식을 사용하면 데이터가 변경되면 varListitems 변수가 자동으로 업데이트됩니다.

App.Formulas 속성의 명명된 수식은 앱 전체에서 값과 계산을 관리하기 위한 보다 유연하고 선언적인 접근 방식을 제공하며, App.OnStart에만 의존하는 것에 비해 타이밍 독립성, 자동 업데이트, 유지 관리 용이성 및 변경할 수 없는 정의 측면에서 이점을 제공합니다.

측면 명명된 수식(App.Formulas) App.OnStart
타이밍 독립성 수식은 즉시 사용할 수 있으며 순서에 관계없이 계산할 수 있습니다. 변수로 인해 타이밍 종속성이 발생하여 가용성에 영향을 미칠 수 있습니다.
자동 업데이트 종속성이 변경되면 수식이 자동으로 업데이트됩니다. 변수는 시작 중에 한 번 설정됩니다. 수동 업데이트가 필요할 수 있습니다.
유지 관리 한 위치에 집중된 공식은 유지 관리성을 향상시킵니다. 분산형 변수는 여러 위치에서 찾아서 업데이트해야 할 수도 있습니다.
불변의 정의 App.Formulas의 수식 정의는 변경할 수 없습니다. 변수 값은 실수로 변경될 수 있습니다.

사용자 정의 함수

Power Apps Authoring Studio의 사용자 정의 함수를 사용하면 사용자가 자신의 사용자 지정 함수를 만들 수 있습니다.

이 기능을 사용하려면 미리보기 설정에서 사용자 정의 함수(UDF)를 켭니다. 프리뷰 기능은 프로덕션에서 사용해서는 안 되므로 기본적으로 사용하지 않도록 설정되어 있지만 곧 일반 공급될 예정입니다.

App.Formulas에서 다음과 같이 수식을 정의합니다.

FunctionName(Parameter1:DataType1, Parameter2:DataType2):OutputDataType = Formula

코드는 다음과 같이 작동합니다.

  • FunctionName은 함수를 호출하는 데 사용됩니다.

  • Parameter는 입력값의 이름입니다. 하나 이상의 입력이 허용됨

  • DataType은 함수에 전달된 인수로, 이 데이터 형식과 일치해야 합니다. 사용 가능한 데이터 유형에는 부울, 색상, 날짜, 날짜/시간, 동적, GUID, 하이퍼링크, 텍스트 및 시간이 포함됩니다

  • OutputDataType은 함수의 출력이 포함될 데이터 형식입니다

  • Formula는 함수의 출력값입니다

// Function to calculate the area of a circle based on the radius
calcAreaOfCircle(radius: Number): Number = 
    IfError(Pi() * radius * radius, 0);

IfError를 사용하여 정의된 함수 내에서 오류 처리를 구현합니다.

텍스트/레이블 컨트롤에서 정의된 함수를 호출합니다.

calcAreaOfCircle(Int(*TextInput1*.Text))

참고

이는 실험적 기능이며 변경될 수 있습니다. 레코드 및 필터와 같은 일부 데이터 형식은 아직 지원되지 않습니다.

변수 최적화

변수는 앱 전체에서 사용하는 로컬 및 전역 값을 정의하고 설정합니다. 편리하기는 하지만 너무 많은 변수를 사용하면 앱의 효율성이 떨어질 수 있습니다.

다음 예제에서는 객체의 각 속성에 대한 변수를 설정하는 방법을 보여줍니다. 이를 위해서는 모든 속성에 대해 Set를 사용해야 합니다.

Set(varEmpName, Office365Users.MyProfile().DisplayName);
Set(varEmpCity, Office365Users.MyProfile().City);
Set(varEmpPhone, Office365Users.MyProfile().BusinessPhones);
Set(varEmpUPN, Office365Users.MyProfile().UserPrincipalName);
Set(varEmpMgrName, Office365Users.ManagerV2(varEmpUPN).DisplayName);

보다 효율적인 방법은 필요할 때만 속성을 사용하는 것입니다.

Set(varEmployee, Office365Users.MyProfile())
"Welcome " & varEmployee.DisplayName

컨텍스트 변수와 전역 변수를 현명하게 사용하십시오. 변수의 범위가 단일 화면을 벗어나는 경우 컨텍스트 변수 대신 전역 변수를 사용합니다.

사용하지 않는 변수가 너무 많으면 메모리 사용량이 증가하고 앱 초기화 속도가 느려질 수 있습니다. 이러한 변수를 사용하지 않더라도 리소스가 할당됩니다. 사용하지 않는 변수도 앱의 논리에 복잡성을 더합니다. 영향이 심각하지 않더라도 더 나은 성능과 더 쉬운 개발을 위해 Power App을 깔끔하고 체계적으로 유지하는 것이 좋습니다.

컬렉션 최적화

컬렉션은 Power Apps 앱에서 데이터를 저장하고 조작하는 데 사용하는 임시 데이터 저장소 구조입니다. 그러나 컬렉션을 너무 많이 사용하면 성능 오버헤드가 발생할 수 있습니다. 컬렉션 사용을 제한하고 필요한 경우에만 사용합니다.

// Use this pattern
ClearCollect(colErrors, {Text: gblErrorText, Code: gblErrorCode});

// Do not use this pattern
Clear(colErrors);
Collect(colErrors, {Text: gblErrorText, Code: gblErrorCode});

로컬 컬렉션의 레코드 수를 계산하려면 CountIf 대신 Count(Filter())를 사용합니다.

컬렉션 작업 시 다음 지침을 고려하세요.

컬렉션의 크기와 수를 제한하세요. 컬렉션은 앱에 로컬이기 때문에 모바일 장치 메모리에 저장됩니다. 데이터 컬렉션이 많거나 컬렉션을 많이 사용할수록 성능이 저하됩니다. 이 ShowColumns 함수를 사용하여 특정 열만 가져옵니다. 관련 데이터만 가져오려면 Filter 함수를 추가합니다.

다음 예제 함수는 전체 데이터 세트를 반환합니다.

ClearCollect(colDemoAccount, Accounts);

이를 특정 레코드와 열만 반환하는 다음 코드와 비교합니다.

ClearCollect(colAcc,
              ShowColumns(
                Filter(Accounts, !IsBlank('Address 1: City')),
                "name","address1_city"))

이 예제에서는 다음 데이터 집합을 반환합니다.

colAcc라는 테이블과 두 개의 열(address1_city 및 name)이 있는 데이터 집합의 스크린샷.

데이터 원본 새로 고침 빈도를 설정합니다. 컬렉션에 새 레코드를 추가하는 경우 컬렉션을 새로 고치거나 컬렉션에 수집하여 새 레코드 또는 변경된 레코드를 가져옵니다. 여러 사용자가 데이터 원본을 업데이트하는 경우 컬렉션을 새로 고쳐 새 레코드 또는 변경된 레코드를 가져옵니다. 새로 고침 호출이 많을수록 서버와의 상호 작용이 늘어납니다.

컬렉션 및 변수의 캐시 데이터

컬렉션은 단일 데이터 항목이 아닌 데이터의 행과 열을 저장하는 테이블 변수입니다. 컬렉션은 데이터를 데이터 원본으로 보내기 전에 집계하고 빈번한 쿼리를 방지하기 위해 정보를 캐싱하는 두 가지 주요 이유로 유용합니다. 컬렉션은 데이터 원본과 Power Apps의 테이블 형식 구조와 일치하므로 오프라인일 때도 효율적으로 데이터와 상호 작용할 수 있습니다.

// Clear the contents of EmployeeCollection, it already contains data
ClearCollect(
    colEmployee,
    {
        Id: "1",
        Name: "John",
        Department: "IT"
    },
    {
        Id: "2",
        Name: "Nestor",
        Department: "IT"
    }
)

사용하지 않는 변수 및 미디어 제거

사용하지 않는 미디어와 변수는 앱 성능에 큰 영향을 미치지 않을 수 있지만 사용하지 않는 미디어나 변수를 삭제하여 앱을 정리하는 것이 중요합니다.

  • 사용하지 않는 미디어 파일은 앱 크기를 증가시켜 앱 로드 시간을 늦출 수 있습니다.

  • 사용하지 않는 변수는 메모리 사용량을 늘리고 앱 초기화 속도를 약간 늦출 수 있습니다. 리소스는 사용되지 않더라도 이러한 변수에 할당됩니다. 사용하지 않는 변수가 너무 많으면 앱의 논리가 더 복잡해질 수도 있습니다.

  • 앱 검사기를 사용하여 사용하지 않는 미디어 및 변수를 검토하세요.

화면 및 컨트롤 최적화

컨트롤 상호 참조 방지

다른 화면의 컨트롤을 참조하는 컨트롤은 앱 로드 및 탐색 속도를 저하시킬 수 있습니다. 이렇게 하면 앱이 사용자가 해당 화면으로 이동할 때까지 기다리지 않고 즉시 다른 화면을 로드하도록 할 수 있습니다. 이 문제를 해결하려면 대신 변수, 컬렉션 및 탐색 컨텍스트를 사용하여 화면 전체에서 상태를 공유합니다.

Power Apps Studio의 앱 검사기는 상호 참조된 컨트롤을 표시합니다. 앱 검사기를 정기적으로 검토하여 이 문제를 해결하세요.

다음은 상호 참조된 컨트롤의 예입니다. 아래 이미지에서 갤러리 1 컨트롤은 화면 2, 레이블 2 컨트롤에서 상호 참조됩니다.

상호 참조된 컨트롤을 보여주는 Power Apps Studio의 스크린샷.

두 번째 화면에서 앱의 첫 번째 화면에 있는 컨트롤을 참조하는 경우 첫 번째 화면이 이미 로드되어 있기 때문에 성능 저하가 발생하지 않습니다. 이것은 앱이 변수를 사용하는 대신 선언적이기 때문에 실제로 좋은 일이 될 수 있습니다.

아직 로드되지 않은 컨트롤을 참조하는 경우(예: 첫 번째 화면이 화면 3의 Label 3이라는 컨트롤을 참조하는 경우) 앱은 해당 화면을 메모리에 로드합니다.

텍스트 컨트롤에 DelayOutput 활성화

DelayOutput 설정을 true로 설정하면 0.5초 지연 후에 사용자 입력이 등록됩니다. 이 기능은 사용자가 텍스트 입력을 마칠 때까지 비용이 많이 드는 작업을 지연하는 데 유용합니다. 예를 들어 다른 수식에서 입력 내용이 사용될 때 필터링하는 데 유용합니다.

예를 들어, 사용자가 TextInput 컨트롤에 입력하는 내용에 따라 항목이 필터링되는 갤러리의 경우:

  • DelayOutput을 기본값인 false로 설정하면 텍스트가 입력되는 즉시 갤러리가 필터링됩니다. 항목이 많은 갤러리가 있는 경우 변경 내용이 포함된 갤러리를 즉시 다시 로드하면 성능이 저하됩니다. 조금 기다리는 것이 좋습니다. 이는 검색 문자열에 TextInput을 사용할 때 실용적입니다(검색 또는 새로운 StartsWith 함수 참조).

  • DelayOutput을 true로 설정하면 변경 내용이 검색되기 전에 약간의 지연이 있습니다. 이렇게 하면 입력을 마칠 수 있는 시간이 생깁니다. 지연은 TextInput.OnChange 속성과 함께 사용할 수 있습니다. 변경 사항과 연결된 작업이 있는 경우 필드에 입력을 마칠 때까지 해당 작업이 트리거되지 않도록 합니다.

위임 및 서버 측 처리

위임

Power Apps의 위임은 앱이 Power Apps 자체에서 작업을 처리하는 대신 특정 작업을 기본 데이터 원본으로 오프로드하는 기능을 나타내는 개념입니다. Power Apps에서 위임을 사용하면 개발자는 대규모 데이터 세트가 포함된 시나리오에서도 잘 작동하는 보다 효율적이고 확장 가능한 애플리케이션을 만들 수 있습니다. 특정 데이터 원본 및 작업에 대한 위임 제한 사항을 인식하고 그에 따라 앱을 설계하여 최적의 성능을 달성하는 것이 중요합니다.

![참고] 모든 기능을 위임할 수 있는 것은 아닙니다. 위임에 대한 자세한 내용은 위임 이해를 참조하세요.

위임에는 쿼리 최적화와 같은 여러 가지 장점이 있으며 대규모 데이터 세트에 대한 지원을 추가합니다. 또한 원본 데이터가 자주 변경되는 경우 위임을 통해 데이터를 최신 상태로 유지하는 데 도움이 됩니다.

데이터 원본에 대한 API 호출 줄이기

때로는 캔버스 앱 내에서 조인을 수행하여 컬렉션을 만드는 것이 편리해 보일 수 있습니다. 예를 들어 다음과 같습니다.

이 예에는 운전자와 트럭이라는 두 개의 테이블이 있습니다. 이 코드는 운전자 및 트럭 세부 정보 컬렉션을 만들고 각 트럭에 대해 트럭을 소유한 운전자를 호출합니다.

// Bad code
ClearCollect(vartruckdata, AddColumns('Truck Details',
    "CITY",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],City),
        "FIRSTNAME",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],'Driver First Name'),
    "LASTNAME",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],'Driver Last Name'),
        "STATE",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],State)));

캔버스 앱에서 이러한 조인을 수행하면 데이터 원본에 대한 많은 호출이 생성되어 로드 시간이 느려질 수 있습니다.

더 나은 접근 방식은 다음과 같습니다.

// Good code
Set(
    varTruckData,
    LookUp(
        Drivers,
        'Dummy ID' = ThisRecord.'Dummy ID',
        'Driver First Name'
    ) & LookUp(
        Drivers,
        'Dummy ID' = ThisRecord.'Dummy ID',
        'Driver Last Name'
        )
);

Set(
    varTruckData,
    With(
        {
            vDriver: LookUp(
                Drivers,
                'Dummy ID' = ThisRecord.'Dummy ID'
            )
        },
        vDriver.'Driver First Name' & vDriver.'Driver Last Name'
    )
)

실시간 시나리오에서는 원본에서 데이터를 수정하여 로딩 시간을 5분에서 10초 미만으로 줄일 수 있습니다.

서버 측 처리

SQL 및 Dataverse와 같은 다양한 데이터 원본을 사용하면 필터 및 조회와 같은 데이터 처리를 데이터 원본에 위임할 수 있습니다. SQL Server에서는 쿼리로 정의된 뷰를 만들 수 있습니다. Dataverse에서 로우코드 플러그인을 만들어 서버의 데이터를 처리하고 최종 결과만 캔버스 앱에 반환할 수 있습니다.

데이터 처리를 서버에 위임하면 성능이 향상되고, 클라이언트 쪽 코드가 줄어들고, 앱을 더 쉽게 유지 관리할 수 있습니다.

Dataverse의 플러그인에 대해 자세히 알아보세요.

쿼리 데이터 패턴 최적화

명시적 열 선택 사용

ECS(Explicit Column Selection) 기능은 모든 새 앱에 대해 기본적으로 켜져 있습니다. 앱에서 해당 기능이 켜져 있지 않으면 켜십시오. ECS는 검색되는 열 수를 앱에서 사용되는 열로만 자동으로 줄입니다. ECS가 켜져 있지 않으면 필요한 것보다 더 많은 데이터를 얻을 수 있으며, 이는 성능에 영향을 줄 수 있습니다. 경우에 따라 앱이 컬렉션을 통해 데이터를 가져올 때 열의 원래 원본이 손실될 수 있습니다. ECS는 사용 여부를 알 수 없는 경우 열을 삭제합니다. ECS가 누락된 열을 유지하도록 하려면 컬렉션 참조 뒤나 컨트롤에서 PowerFx 표현식 ShowColumns를 사용합니다.

컬렉션을 채우는 데 Power Automate 호출 방지

일반적인 방법은 Power Automate을 사용하여 Power Apps에서 컬렉션을 가져오고 채우는 것입니다. 이 접근 방식은 유효하지만 가장 효율적인 선택이 아닐 수도 있는 상황이 있습니다. Power Automate를 호출하면 네트워크 대기 시간의 오버헤드가 발생하고 Power Automate 흐름을 인스턴스화하는 데 0.6초의 성능 비용이 추가됩니다.

Power Automate 흐름을 과도하게 사용하면 실행 한도 및 제한이 발생할 수도 있습니다. 따라서 항상 네트워크 대기 시간과 성능 비용 간의 균형을 평가하십시오.

N+1 문제 제거

N+1 문제는 단일 쿼리에서 필요한 모든 데이터를 가져오는 대신 관련 데이터를 검색하기 위해 여러 개의 추가 쿼리가 수행되는 데이터베이스 쿼리의 일반적인 문제입니다. 각 추가 쿼리로 인해 오버헤드가 발생하므로 성능 문제가 발생할 수 있습니다.

컬렉션을 로드하기 위한 이와 같은 간단한 호출은 데이터 원본에 대한 N+1 호출을 생성할 수 있습니다.

ClearCollect(MyCollection, OrdersList,
    {
        LookUp(CustomersList,CustomerID = OrdersList[@CustomerID])
    }
)

캔버스 앱 및 갤러리의 맥락에서 관련 레코드를 표시하는 데이터 원본 및 갤러리로 작업할 때 N+1 문제가 발생할 수 있습니다. 이 문제는 일반적으로 갤러리에 표시된 각 항목에 대해 더 많은 쿼리가 수행될 때 발생하며 이로 인해 성능 병목 현상이 발생합니다.

N+1 쿼리 문제를 방지하려면 SQL Server의 View 개체를 사용하거나 N+1 시나리오가 트리거되지 않도록 사용자 인터페이스를 변경하세요.

Dataverse는 관련 테이블의 필수 데이터를 자동으로 가져오고 관련 테이블에서 열을 선택할 수 있습니다.

ThisItem.Account.'Account Name'

RelatedDataSource` 크기가 작은 경우(<500 레코드) 이를 컬렉션에 캐시하고 컬렉션을 사용하여 조회(N+1) 쿼리 시나리오를 구동할 수 있습니다.

패키지 크기 제한

Power Apps는 앱 로드를 최적화하기 위해 많은 작업을 수행하지만 앱의 공간을 줄이기 위한 조치를 취할 수 있습니다. 공간을 줄이는 것은 구형 장치 사용자나 대기 시간이 길거나 대역폭이 감소하는 지역의 사용자에게 특히 중요합니다.

  • 앱에 포함된 미디어를 평가합니다. 사용되지 않는 항목이 있으면 삭제하세요.

  • 삽입된 이미지가 너무 클 수 있습니다. PNG 파일 대신 SVG 이미지를 사용할 수 있는지 확인하세요. 하지만 SVG 이미지에 텍스트를 사용할 때는 주의하세요. 사용되는 글꼴은 클라이언트에 설치되어야 하기 때문입니다. 텍스트를 표시해야 할 때 가장 좋은 해결 방법은 이미지 위에 텍스트 레이블을 겹쳐 놓는 것입니다.

  • 폼 팩터에 대한 해상도가 적절한지 평가합니다. 모바일 앱의 해상도는 데스크톱 앱의 해상도만큼 높을 필요는 없습니다. 이미지 품질과 크기의 적절한 균형을 얻으려면 실험을 해보세요.

  • 사용하지 않는 화면이 있으면 삭제하세요. 앱 제작자나 관리자만 사용하는 숨겨진 화면을 삭제하지 않도록 주의하세요.

  • 하나의 앱에 너무 많은 워크플로를 맞추려고 하는지 평가해 보세요. 예를 들어, 동일한 앱에 관리 화면과 클라이언트 화면이 모두 있나요? 그렇다면 개별 앱으로 나누는 것을 고려해 보세요. 또한 이 접근 방식을 사용하면 여러 사람이 동시에 앱 작업을 더 쉽게 수행할 수 있으며, 앱 변경에 전체 테스트 통과가 필요한 경우 "폭발 반경"(테스트 양)이 제한됩니다.

ForAll 최적화

Power Apps의 ForAll 함수는 레코드 테이블을 반복하고 각 레코드에 수식 또는 수식 집합을 적용하는 데 사용됩니다. 함수 자체는 다목적이지만 ForAll 기능을 부적절하게 사용하면 앱 성능이 빠르게 저하될 수 있습니다.

ForAll 함수는 동시 함수가 아닌 단일 순차 함수입니다. 따라서 한 번에 하나의 레코드만 보고 결과를 얻은 다음 해당 범위의 모든 레코드를 검토할 때까지 다음 레코드를 계속 진행합니다.

절대 ForAll 중첩을 하지 마세요. 이로 인해 기하급수적인 반복이 발생하고 성능에 큰 영향을 미칠 수 있습니다.

ClearCollect(FollowUpMeetingAttendees.ForAll(ForAll(Distinct(AttendeesList.EmailAddress.Address).Lookup(Attendees))))

데이터베이스 일괄 업데이트

ForAll + Patch는 데이터베이스를 일괄 업데이트하는 한 가지 접근 방식일 수 있습니다. 단, For All과 Patch의 순서를 사용할 때에는 주의하시기 바랍니다.

다음 함수:

Patch(SampleFoodSalesData, ForAll(colSampleFoodSales,
    {
        demoName:"fromCanvas2"
    })
);

다음보다 성능이 우수합니다.

ForAll(colSampleFoodSales, Patch(SampleFoodSalesData,
    {
        demoName:"test"
    })
);

다음 단계: