다음을 통해 공유


코드 최적화

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

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

Power Fx 수식 최적화

이 섹션에서는 Power Fx 수식을 최적화하기 위한 모범 사례를 제공합니다.

With 함수

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

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

Concurrent 함수

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

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

Coalesce 함수

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

이 예제에서는 value1value2이 두 번 평가되어야 합니다.

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

이 함수는 다음과 같이 축소될 수 있습니다.

Coalesce(value1, value2)

IsMatch 함수

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

예를 들어 이 수식은 United States 주민등록번호와 일치합니다.

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 수식으로 마이그레이션하여 함수를 간소화합니다. 명명된 수식, 특히 앱 수명 주기 초기에 구성된 수식이 유리합니다. 이러한 수식은 데이터 호출을 기반으로 변수 초기화를 처리하여 코드에 더 깔끔하고 체계적인 구조를 제공합니다. 크고 복잡한 캔버스 앱 빌드에서 자세히 알아보세요.

참고

속성은 OnStart 필수입니다. 첫 번째 화면이 나타나기 전에 수행해야 하는 순서가 지정된 작업 목록입니다. 수행해야 하는 작업 뿐만 아니라 순서에 따라 작업을 수행해야 하는 경우에도 고유하기 때문에 그렇지 않은 경우 수행할 수 있는 최적화의 순서 변경 및 지연을 제한합니다.

시작 화면

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

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

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

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)

추가 정보: App.StartScreen: App.OnStart에서 탐색을 위한 선언적 대안입니다.

경고

StartScreenOnStart 사이의 종속성을 피하십시오. 명명된 수식을 참조하면 그 수식이 전역 변수를 다시 참조할 때 경합 상태가 발생할 수 있으며, 이로 인해 StartScreen이 적절히 적용되지 않을 수 있습니다.

사이에 StartScreenOnStart종속성을 만들지 마세요. 앱에서 전역 변수 StartScreen참조를 차단하는 동안 명명된 수식을 참조할 수 있으며, 이 수식은 전역 변수를 참조합니다. 이 방법을 사용하면 경합 상태가 발생하여 StartScreen이 올바르게 적용되지 않을 수 있습니다.

이름이 지정된 수식

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

명명된 수식은 앱 테마를 선언할 때도 도움이 됩니다. 엔터프라이즈 앱을 빌드할 때 앱에 일관된 모양과 사용자 환경을 제공하는 공통 테마가 있는 경우가 많습니다. 테마를 만들려면 .에서 App.OnStart수십~수백 개의 변수를 선언해야 합니다. 이 선언은 코드 길이와 앱의 초기화 시간을 증가합니다.

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

예를 들어 다음 코드를 App.OnStartApp.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 사용자 정보를 가져오기 위해 Lookup 수식에서 변경이 필요합니다. 모든 위치에서 코드를 변경하지 않고 한 곳에서만 변경하면 됩니다.

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 Users 테이블에서 Office 365 커넥터로 전환하도록 확장됩니다.

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

varListItems = CountRows(SampleList)

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

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

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

사용자 정의 함수

Power Apps Studio의 사용자 정의 함수 사용자 지정 함수를 만들 수 있습니다.

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

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

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

  • FunctionName 함수를 호출합니다.

  • Parameter는 입력값의 이름입니다. 하나 이상의 입력을 포함할 수 있습니다.

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

  • OutputDataType 는 함수 출력의 데이터 형식입니다.

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

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

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

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

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 앱에서 데이터를 저장하고 조작하는 데 사용하는 임시 데이터 storage 구조입니다. 그러나 컬렉션은 성능 오버헤드를 일으킬 수 있습니다. 컬렉션 사용을 제한하고 필요한 경우에만 사용합니다.

// 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 및 이름)이 있는 데이터 세트의 스크린샷

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

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

컬렉션은 단일 데이터 항목이 아닌 데이터의 행과 열을 저장하는 테이블 변수입니다. 컬렉션은 데이터를 데이터 원본으로 보내기 전에 집계하고 빈번한 쿼리를 방지하기 위해 정보를 캐싱하는 두 가지 주요 이유로 유용합니다. 컬렉션은 데이터 원본 및 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 화면 및 컨트롤을 최적화하려면 다음 모범 사례를 고려하세요.

컨트롤 상호 참조를 피하십시오

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

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

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

Power Apps Studio의 스크린샷이며, 상호 참조된 컨트롤을 보여 줍니다.

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

화면 3에서 명명 Label 3 된 컨트롤을 참조하는 첫 번째 화면과 같이 아직 로드되지 않은 컨트롤을 참조하는 경우 앱은 해당 화면을 메모리에 로드합니다.

텍스트 컨트롤에 DelayOutput 활성화

DelayOutput 설정은 true로 설정하면 반초 지연 후에 사용자 입력을 등록합니다. 이 지연은 입력이 다른 수식에서 사용되는 경우 필터링과 같이 사용자가 텍스트 입력을 완료할 때까지 비용이 많이 드는 작업을 연기하는 데 유용합니다.

예를 들어 사용자가 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가 누락된 열을 유지하도록 하려면 컬렉션 참조 뒤 또는 컨트롤에서 Power Fx 식 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 문제가 발생할 수 있습니다. 이 문제는 일반적으로 갤러리에 표시된 각 항목에 대해 더 많은 쿼리가 수행될 때 발생하며 이로 인해 성능 병목 현상이 발생합니다.

SQL Server View 개체를 사용하여 N+1 쿼리 문제를 방지하거나 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 일괄 업데이트할 수 있습니다. 그러나 ForAllPatch의 순서를 사용할 때 주의해야 합니다.

다음 함수는 더 나은 방법입니다. 예를 들면 다음과 같습니다.

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

반면, 다음 방법은 효율성이 떨어집니다.

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

다음 단계: