Blog JSystems - uwalniamy wiedzę!

Szukaj

Power BI - Wydajność modelu i raportu

Wolna miara DAX z FILTER na całej tabeli - prosty warunek w CALCULATE

W skrócie

  • Miara DAX z FILTER na całej tabeli faktów jest wolna, bo FILTER sprawdza warunek w każdym wierszu tabeli, a w modelu z milionami wierszy widać to w czasie zapytania DAX.
  • Prosty warunek na kolumnie silnik zamienia na tani filtr kolumny. Zmienia się jednak też wynik: prosty warunek podmienia filtr na tej kolumnie, a FILTER na tabeli zachowuje filtry, które już na niej są.
  • Warunek na jednej kolumnie zapisz wprost w CALCULATE, a gdy filtr ma zostać, owiń go w KEEPFILTERS. FILTER zostaw na warunki z miarą albo z kolumnami dwóch tabel, i to na małej tabeli wartości.

Wzorzec CALCULATE z FILTER na całej tabeli faktów łatwo przepisać z gotowego przykładu i powielić w kilkunastu miarach. Wolna miara z FILTER to wtedy tylko część kłopotu, bo w niektórych wizualizacjach taki zapis daje też inny wynik niż prosty warunek. Wyjaśniamy, dlaczego DAX FILTER jest wolny na całej tabeli i jak go zastąpić. Wszystkie warianty sprawdziliśmy na modelu Nordvelli.

Jak to wygląda w praktyce

W Analizatorze wydajności wizualizacja z taką miarą ma wysoki czas Zapytanie DAX, a nie wyświetlania. Na modelu Nordvelli ze 108 675 wierszami różnicy nie zobaczysz: w lekcji o wydajności cała tabela siedmiu miar, w tym obu wersji miary sprzedaży kartą, liczyła się 159 ms, z czego zapytanie DAX trwało 34 ms. Koszt pojawia się na tabelach z milionami wierszy i w macierzach, które wywołują miarę tysiące razy.

Drugi objaw to różne liczby. W tabeli z kolumną FormaPlatnosci na wierszach miara z FILTER pokazuje 187 035 097,78 zł tylko przy Karcie i pustkę przy BLIK, Gotówce, Przelewie i Ratach, a miara z prostym warunkiem pokazuje tę samą kwotę w każdym wierszu.

Tabela Power BI na stronie Wydajność miar: Sprzedaż karta z prostym warunkiem i z FILTER dla form płatności Nordvelli
Strona Wydajność miar z lekcji 18. Sprzedaż karta z prostym warunkiem pokazuje 187 035 098 zł w każdym wierszu, bo podmienia filtr formy płatności. Wersja z FILTER pokazuje kwotę tylko przy Karcie.

Dlaczego tak się dzieje

FILTER zwraca tabelę i według dokumentacji Microsoft sprawdza warunek dla każdego wiersza tabeli, którą dostaje. Gdy tą tabelą jest FaktSprzedaz, silnik przechodzi wszystkie wiersze faktów widoczne w bieżącym kontekście filtra, czyli zestawie warunków z wizualizacji. Prosty warunek, na przykład FaktSprzedaz[FormaPlatnosci] = "Karta", silnik traktuje jak filtr jednej kolumny, a tabele trybu Import to magazyny kolumnowe zoptymalizowane właśnie pod takie filtrowanie.

Wyniki różnią się z dwóch powodów. Prosty warunek podmienia filtr na swojej kolumnie, dlatego w wierszu BLIK liczy sprzedaż kartą. FILTER na tabeli zwraca tylko wiersze już widoczne w kontekście, więc filtr wiersza zostaje. Z tego samego powodu tabela z FILTER przenosi filtry z wymiarów. W mierze udziału sklepu w sprzedaży kartą z REMOVEFILTERS(DimSklepy) w tym samym CALCULATE wersja z FILTER dała 100% dla każdego sklepu, a wersja z prostym warunkiem poprawne udziały, na przykład 30,16% dla Nordvella Online i 7,58% dla Nordvella Warszawa Centrum. Więcej o mianownikach udziałów piszemy w poście o udziale procentowym w DAX.

Co zrobić krok po kroku

  1. Znajdź miary z FILTER. Otwórz Widok zapytań w języku DAX i uruchom zapytanie niżej. W modelu Nordvelli wypisuje sześć miar, między innymi Sprzedaż karta (wolno) i Sprzedaż premium. Nie każda jest błędem: FILTER na małej tabeli wartości albo z warunkiem na mierze bywa konieczny. Przepisujesz FILTER na całej tabeli faktów z warunkiem na jej kolumnie.
    EVALUATE
    SELECTCOLUMNS(
        FILTER(
            INFO.VIEW.MEASURES(),
            SEARCH("FILTER(", SUBSTITUTE([Expression], " ", ""), 1, 0) > 0
        ),
        "Tabela", [Table],
        "Miara", [Name]
    )
  2. Warunek na jednej kolumnie przepisz na prosty warunek. Gdy wizualizacja nie filtruje tej samej kolumny, obie wersje dają to samo: w tabeli kategorii Nordvelli obie miary pokazały na przykład 76 925 057,80 zł dla AGD/RTV i 42 915 101,44 zł dla Telefonów.
    Sprzedaż karta =
    CALCULATE(
        SUM(FaktSprzedaz[WartoscNetto]),
        FaktSprzedaz[FormaPlatnosci] = "Karta"
    )
  3. Gdy filtr na tej kolumnie ma zostać, owiń warunek w KEEPFILTERS, tak jak w przykładzie z dokumentacji Microsoft. Na modelu Nordvelli ta wersja dała w tabeli form płatności dokładnie to samo co FILTER: 187 035 097,78 zł przy Karcie i pustkę w pozostałych wierszach. KEEPFILTERS opisujemy szerzej w poście o CALCULATE, który nadpisuje wybór we fragmentatorze.
    Sprzedaż karta (zachowaj filtr) =
    CALCULATE(
        SUM(FaktSprzedaz[WartoscNetto]),
        KEEPFILTERS(FaktSprzedaz[FormaPlatnosci] = "Karta")
    )
  4. Warunek na dwóch kolumnach tej samej tabeli też zapiszesz wprost, na przykład FaktSprzedaz[MarzaNetto] > FaktSprzedaz[WartoscNetto] * 0.2. Na Nordvelli ten zapis i FILTER na całej tabeli dały tę samą kwotę, 180 940 188,59 zł. Kolumn z dwóch tabel w prostym warunku użyć nie można. Silnik odpowiada: „Wyrażenie zawiera kolumny z wielu tabel, ale w wyrażeniu logicznym (True/False), które jest używane jako wyrażenie filtru tabeli, można użyć kolumn tylko z jednej tabeli.” (w angielskiej wersji: „The expression contains columns from multiple tables, but only columns from a single table can be used in a True/False expression that is used as a table filter expression.”).
  5. Dla warunku na kolumnach z dwóch tabel podaj FILTER tylko te dwie kolumny, a nie całą tabelę faktów. CROSSJOIN pięciu form płatności i czterech kategorii ma na Nordvelli 20 par zamiast 108 675 wierszy. Sprzedaż kartą albo w kategorii Telefony wyszła 251 177 852,10 zł, tyle samo co w wersji z FILTER na FaktSprzedaz i RELATED, i zgadza się z rachunkiem: 187 035 097,78 + 107 057 855,76 - 42 915 101,44 zł.
    Karta lub telefony =
    CALCULATE(
        [Łączna sprzedaż],
        FILTER(
            CROSSJOIN(
                VALUES(FaktSprzedaz[FormaPlatnosci]),
                VALUES(DimProdukty[Kategoria])
            ),
            FaktSprzedaz[FormaPlatnosci] = "Karta"
                || DimProdukty[Kategoria] = "Telefony"
        )
    )
  6. Gdy warunek używa miary, prosty zapis zgłasza błąd, który opisujemy w poście o CALCULATE w wyrażeniu filtru. Wtedy FILTER jest potrzebny, ale na małej tabeli: FILTER(VALUES(DimProdukty[Nazwa]), [Marża %] > 0.2) sprawdza 30 wartości, po jednej na produkt, zamiast 108 675 transakcji. Na Nordvelli warunek spełnia 17 produktów, które dały 230 240 963,80 zł sprzedaży.

Jak sprawdzić, że problem zniknął

Przed usunięciem starej miary połóż obie wersje w jednej tabeli i sprawdź je na dwóch układach: z kolumną, której dotyczy warunek (tu FormaPlatnosci), i z inną, na przykład kategorią. W lekcji o wydajności robimy to na osobnej stronie Wydajność miar. Gdy liczby się zgadzają, zmierz wizualizację w Analizatorze wydajności, skopiuj zapytanie przyciskiem Kopiuj zapytanie i porównaj czas silnika formuł przed zmianą i po niej w DAX Studio, w widoku Server Timings.

Żeby wzorzec nie wracał, przyjmij w zespole jedną regułę zapisu: warunek na kolumnie zawsze wprost albo w KEEPFILTERS, a FILTER tylko na małej tabeli wartości i tylko wtedy, gdy warunek zawiera miarę albo kolumny z różnych tabel.

Źródła i sposób sprawdzenia

  • Microsoft Learn: Avoid using FILTER as a filter argument (DAX) (źródło)
  • Microsoft Learn: KEEPFILTERS function (DAX) (źródło)
  • Microsoft Learn: CALCULATE function (DAX) (źródło)
  • Sprawdzone zapytaniami DAX na modelu Nordvelli: FILTER, prosty warunek i KEEPFILTERS po formach płatności i kategoriach, udział z REMOVEFILTERS, warunki na dwóch kolumnach i dwóch tabelach.

Zachowanie programu sprawdziliśmy w Power BI Desktop 2.157 (wydanie z sierpnia 2026 r.) z polskim interfejsem, a przykłady na modelu sieci Nordvella z bezpłatnego kursu Power BI. Microsoft wydaje nową wersję Power BI Desktop co miesiąc, więc nazwy przycisków i limity usługi mogą się zmieniać. Aktualne wartości podaje dokumentacja Microsoft Learn.

Wróć do listy: 131 najczęstszych pytań i problemów związanych z Power BI

Najczęściej zadawane pytania

Dlaczego FILTER w CALCULATE działa wolno?
FILTER sprawdza warunek dla każdego wiersza tabeli, którą dostaje, więc FILTER na tabeli faktów przechodzi wszystkie jej widoczne wiersze. Prosty warunek na kolumnie silnik zamienia na filtr kolumny, który tabele w trybie Import obsługują wydajnie. Różnicę widać przy milionach wierszy, na 108 675 wierszach Nordvelli cała tabela miar liczyła się w 34 ms zapytania DAX.
Czym różni się FILTER od prostego warunku w CALCULATE?
Prosty warunek podmienia filtr na swojej kolumnie, a FILTER na tabeli zwraca tylko wiersze widoczne w bieżącym kontekście, więc istniejące filtry zostają. W tabeli form płatności Nordvelli prosty warunek pokazał 187 035 097,78 zł w każdym wierszu, a FILTER tylko przy Karcie. Ten sam wynik co FILTER, ale tańszym zapisem, daje KEEPFILTERS.
Kiedy w DAX trzeba użyć funkcji FILTER?
Gdy warunek zawiera miarę albo porównuje kolumny z różnych tabel, bo prosty warunek w CALCULATE tego nie przyjmie. Wtedy podaj FILTER możliwie małą tabelę, na przykład VALUES(DimProdukty[Nazwa]) z 30 wartościami albo CROSSJOIN dwóch kolumn z 20 parami, zamiast całej tabeli faktów.
Co zrobić, gdy warunek w CALCULATE dotyczy kolumn z dwóch tabel?
Prosty warunek zgłosi błąd, że w wyrażeniu logicznym można użyć kolumn tylko z jednej tabeli. Użyj FILTER na CROSSJOIN wartości obu kolumn, na przykład formy płatności i kategorii. Na modelu Nordvelli taki zapis dla sprzedaży kartą albo telefonów dał 251 177 852,10 zł, tyle samo co FILTER na całej tabeli z RELATED.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...