Delen via


Problemen met een trage query in een toegewezen SQL-pool oplossen

Van toepassing op: Azure Synapse Analytics

Dit artikel helpt u bij het identificeren van de redenen en het toepassen van oplossingen voor veelvoorkomende prestatieproblemen met query's in een toegewezen SQL-pool van Azure Synapse Analytics.

Volg de stappen om het probleem op te lossen of voer de stappen in het notebook uit via Azure Data Studio. De eerste drie stappen helpen u bij het verzamelen van telemetrie, waarin de levenscyclus van een query wordt beschreven. De verwijzingen aan het einde van het artikel helpen u bij het analyseren van mogelijke kansen in de verzamelde gegevens.

Notitie

Voordat u dit notebook probeert te openen, moet u ervoor zorgen dat Azure Data Studio is geïnstalleerd op uw lokale computer. Als u deze wilt installeren, gaat u naar Meer informatie over het installeren van Azure Data Studio.

Belangrijk

De meeste gerapporteerde prestatieproblemen worden veroorzaakt door:

  • Verouderde statistieken
  • Beschadigde geclusterde columnstore-indexen (CCI's)

Als u tijd wilt besparen voor het oplossen van problemen, moet u ervoor zorgen dat de statistieken zijn gemaakt en up-to-date zijn en CCIS's opnieuw zijn opgebouwd.

Stap 1: de request_id (ook wel QID genoemd) identificeren

De request_id trage query is vereist om mogelijke redenen voor een trage query te onderzoeken. Gebruik het volgende script als uitgangspunt voor het identificeren van de query die u wilt oplossen. Zodra de trage query is geïdentificeerd, noteert u de request_id waarde.

-- Monitor active queries
SELECT *
FROM sys.dm_pdw_exec_requests
WHERE [status] NOT IN ('Completed','Failed','Cancelled')
AND session_id <> session_id()
-- AND [label] = '<YourLabel>'
-- AND resource_allocation_percentage is not NULL
ORDER BY submit_time DESC;

-- Find top 10 longest running queries
SELECT TOP 10 *
FROM sys.dm_pdw_exec_requests
ORDER BY total_elapsed_time DESC;

Gebruik de volgende tips wanneer u het script uitvoert om de trage query's beter te richten:

  • Sorteer op of submit_time DESC total_elapsed_time DESC laat de langst lopende query's boven aan de resultatenset staan.

  • Gebruik OPTION(LABEL='<YourLabel>') deze in uw query's en filter de label kolom om deze te identificeren.

  • U kunt eventueel QID's filteren waarvoor geen waarde resource_allocation_percentage is opgegeven wanneer u weet dat de doelinstructie in een batch is opgenomen.

    Opmerking: Wees voorzichtig met dit filter, omdat het mogelijk ook bepaalde query's filtert die worden geblokkeerd door andere sessies.

Stap 2: bepalen waar de query tijd in beslag neemt

Voer het volgende script uit om de stap te vinden die het prestatieprobleem van de query kan veroorzaken. Werk de variabelen in het script bij met de waarden die in de volgende tabel worden beschreven. Wijzig de @ShowActiveOnly waarde in 0 om de volledige afbeelding van het gedistribueerde plan te krijgen. Noteer de StepIndex, Phaseen Description waarden van de langzame stap die is geïdentificeerd uit de resultatenset.

Parameter Description
@QID De request_id waarde die is verkregen in stap 1
@ShowActiveOnly 0 - Alle stappen voor de query weergeven
1 - Alleen de huidige actieve stap weergeven
DECLARE @QID VARCHAR(16) = '<request_id>', @ShowActiveOnly BIT = 1; 
-- Retrieve session_id of QID
DECLARE @session_id VARCHAR(16) = (SELECT session_id FROM sys.dm_pdw_exec_requests WHERE request_id = @QID);
-- Blocked by Compilation or Resource Allocation (Concurrency)
SELECT @session_id AS session_id, @QID AS request_id, -1 AS [StepIndex], 'Compilation' AS [Phase],
   'Blocked waiting on '
       + MAX(CASE WHEN waiting.type = 'CompilationConcurrencyResourceType' THEN 'Compilation Concurrency'
                  WHEN waiting.type LIKE 'Shared-%' THEN ''
                  ELSE 'Resource Allocation (Concurrency)' END)
       + MAX(CASE WHEN waiting.type LIKE 'Shared-%' THEN ' for ' + REPLACE(waiting.type, 'Shared-', '')
             ELSE '' END) AS [Description],
   MAX(waiting.request_time) AS [StartTime], GETDATE() AS [EndTime],
   DATEDIFF(ms, MAX(waiting.request_time), GETDATE())/1000.0 AS [Duration],
   NULL AS [Status], NULL AS [EstimatedRowCount], NULL AS [ActualRowCount], NULL AS [TSQL]
FROM sys.dm_pdw_waits waiting
WHERE waiting.session_id = @session_id
   AND ([type] LIKE 'Shared-%' OR
      [type] in ('ConcurrencyResourceType', 'UserConcurrencyResourceType', 'CompilationConcurrencyResourceType'))
   AND [state] = 'Queued'
GROUP BY session_id 
-- Blocked by another query
UNION ALL
SELECT @session_id AS session_id, @QID AS request_id, -1 AS [StepIndex], 'Compilation' AS [Phase],
   'Blocked by ' + blocking.session_id + ':' + blocking.request_id + ' when requesting ' + waiting.type + ' on '
   + QUOTENAME(waiting.object_type) + waiting.object_name AS [Description],
   waiting.request_time AS [StartTime], GETDATE() AS [EndTime],
   DATEDIFF(ms, waiting.request_time, GETDATE())/1000.0 AS [Duration],
   NULL AS [Status], NULL AS [EstimatedRowCount], NULL AS [ActualRowCount],
   COALESCE(blocking_exec_request.command, blocking_exec_request.command2) AS [TSQL]
FROM sys.dm_pdw_waits waiting
   INNER JOIN sys.dm_pdw_waits blocking
      ON waiting.object_type = blocking.object_type
      AND waiting.object_name = blocking.object_name
   INNER JOIN sys.dm_pdw_exec_requests blocking_exec_request
      ON blocking.request_id = blocking_exec_request.request_id
WHERE waiting.session_id = @session_id AND waiting.state = 'Queued'
   AND blocking.state = 'Granted' AND waiting.type != 'Shared' 
-- Request Steps
UNION ALL
SELECT @session_id AS session_id, @QID AS request_id, step_index AS [StepIndex],
       'Execution' AS [Phase], operation_type + ' (' + location_type + ')' AS [Description],
       start_time AS [StartTime], end_time AS [EndTime],
       total_elapsed_time/1000.0 AS [Duration], [status] AS [Status],
       CASE WHEN estimated_rows > -1 THEN estimated_rows END AS [EstimatedRowCount],
       CASE WHEN row_count > -1 THEN row_count END AS [ActualRowCount],
       command AS [TSQL]
FROM sys.dm_pdw_request_steps
WHERE request_id = @QID
   AND [status] = CASE @ShowActiveOnly WHEN 1 THEN 'Running' ELSE [status] END
ORDER BY StepIndex;

Stap 3: Details van stap bekijken

Voer het volgende script uit om de details te bekijken van de stap die in de vorige stap is geïdentificeerd. Werk de variabelen in het script bij met de waarden die in de volgende tabel worden beschreven. Wijzig de @ShowActiveOnly waarde in 0 om alle distributietijdsinstellingen te vergelijken. Noteer de wait_type waarde voor de distributie die het prestatieprobleem kan veroorzaken.

Parameter Description
@QID De request_id waarde die is verkregen in stap 1
@StepIndex De StepIndex waarde die is geïdentificeerd in stap 2
@ShowActiveOnly 0 - Alle distributies voor de opgegeven StepIndex waarde weergeven
1 - Alleen de huidige actieve distributies voor de opgegeven StepIndex waarde weergeven
DECLARE @QID VARCHAR(16) = '<request_id>', @StepIndex INT = <StepIndex>, @ShowActiveOnly BIT = 1;
WITH dists
AS (SELECT request_id, step_index, 'sys.dm_pdw_sql_requests' AS source_dmv,
       distribution_id, pdw_node_id, spid, 'NativeSQL' AS [type], [status],
       start_time, end_time, total_elapsed_time, row_count
    FROM sys.dm_pdw_sql_requests
    WHERE request_id = @QID AND step_index = @StepIndex
    UNION ALL
    SELECT request_id, step_index, 'sys.dm_pdw_dms_workers' AS source_dmv,
       distribution_id, pdw_node_id, sql_spid AS spid, [type],
       [status], start_time, end_time, total_elapsed_time, rows_processed as row_count
    FROM sys.dm_pdw_dms_workers
    WHERE request_id = @QID AND step_index = @StepIndex
   )
SELECT sr.step_index, sr.distribution_id, sr.pdw_node_id, sr.spid,
       sr.type, sr.status, sr.start_time, sr.end_time,
       sr.total_elapsed_time, sr.row_count, owt.wait_type, owt.wait_time
FROM dists sr
   LEFT JOIN sys.dm_pdw_nodes_exec_requests owt
      ON sr.pdw_node_id = owt.pdw_node_id
         AND sr.spid = owt.session_id
         AND ((sr.source_dmv = 'sys.dm_pdw_sql_requests'
                 AND sr.status = 'Running') -- sys.dm_pdw_sql_requests status
              OR (sr.source_dmv = 'sys.dm_pdw_dms_requests'
                     AND sr.status not LIKE 'Step[CE]%')) -- sys.dm_pdw_dms_workers final statuses
WHERE sr.request_id = @QID
      AND ((sr.source_dmv = 'sys.dm_pdw_sql_requests' AND sr.status =
               CASE WHEN @ShowActiveOnly = 1 THEN 'Running' ELSE sr.status END)
           OR (sr.source_dmv = 'sys.dm_pdw_dms_workers' AND sr.status NOT LIKE
                  CASE WHEN @ShowActiveOnly = 1 THEN 'Step[CE]%' ELSE '' END))
      AND sr.step_index = @StepIndex
ORDER BY distribution_id

Stap 4: Diagnose stellen en beperken

Problemen met compilatiefase

Geblokkeerd: Gelijktijdigheid van compilatie

Compilatieblokken voor gelijktijdigheid treden zelden op. Als u echter dit type blok tegenkomt, wordt aangegeven dat er binnen korte tijd een groot aantal query's is verzonden en in de wachtrij is geplaatst om de compilatie te starten.

Oplossingen

Verminder het aantal query's dat gelijktijdig wordt ingediend.


Geblokkeerd: resourcetoewijzing

Wordt geblokkeerd voor resourcetoewijzing betekent dat uw query wacht op uitvoering op basis van:

  • De hoeveelheid geheugen die wordt verleend op basis van de resourceklasse of workloadgroeptoewijzing die aan de gebruiker is gekoppeld.
  • De hoeveelheid beschikbaar geheugen in het systeem of de workloadgroep.
  • (Optioneel) Het belang van de workloadgroep/classificatie.

Oplossingen

Complexe query of oudere JOIN-syntaxis

U kunt een situatie tegenkomen waarbij de standaardmethoden voor het optimaliseren van query's ineffectief zijn omdat de compilatiefase lang duurt. Dit kan gebeuren als de query:

  • Omvat een groot aantal joins en/of subquery's (complexe query).
  • Maakt gebruik van joiners in de FROM component (geen ANSI-92 style joins).

Hoewel deze scenario's atypisch zijn, hebt u opties om het standaardgedrag te overschrijven om de tijd te verminderen die nodig is voor de queryoptimalisatie om een plan te kiezen.

Oplossingen

  • Gebruik ANSI-92 style joins.
  • Voeg queryhints toe: OPTION(FORCE ORDER, USE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION')). Zie FORCE ORDER and Cardinality Estimation (SQL Server) voor meer informatie.
  • Verbreek de query in meerdere, minder complexe stappen.
LANGLOPENDE DROP TABLE OF TRUNCATE TABLE

Voor efficiëntie van de uitvoeringstijd worden opslagopruiming door de DROP TABLE instructies TRUNCATE TABLE uitgesteld tot een achtergrondproces. Als uw workload echter een groot aantal DROP/TRUNCATE TABLE instructies in een korte periode uitvoert, is het mogelijk dat metagegevens vol raken en ervoor zorgen dat volgende DROP/TRUNCATE TABLE instructies langzaam worden uitgevoerd.

Oplossingen

Identificeer een onderhoudsvenster, stop alle workloads en voer DBCC SHRINKDATABASE uit om onmiddellijk opschonen van eerder verwijderde of afgekapte tabellen af te dwingen.


Slechte CCIS's (over het algemeen)

Voor een slechte CCI-status (geclusterde columnstore index) zijn extra metagegevens vereist, waardoor de queryoptimalisatie meer tijd nodig heeft om een optimaal plan te bepalen. Om deze situatie te voorkomen, moet u ervoor zorgen dat al uw CC's in goede gezondheid zijn.

Oplossingen

Evalueer en corrigeer de geclusterde columnstore-indexstatus in een toegewezen SQL-pool.


Vertraging van statistieken voor automatisch maken

De optieAUTO_CREATE_STATISTICS voor het automatisch maken van statistieken is ON standaard bedoeld om ervoor te zorgen dat de queryoptimalisatie goede beslissingen kan nemen over gedistribueerde plannen. Het proces voor automatisch maken kan echter langer duren dan de volgende uitvoeringen van dezelfde query.

Oplossingen

Als voor de eerste uitvoering van de query consistent statistieken moeten worden gemaakt, moet u handmatig statistieken maken voordat de query wordt uitgevoerd.


Time-outs voor statistieken automatisch maken

De optieAUTO_CREATE_STATISTICS voor het automatisch maken van statistieken is ON standaard bedoeld om ervoor te zorgen dat de queryoptimalisatie goede beslissingen kan nemen over gedistribueerde plannen. Het automatisch maken van statistieken vindt plaats als reactie op een SELECT-instructie en heeft een drempelwaarde van 5 minuten om te voltooien. Als de grootte van gegevens en/of het aantal te maken statistieken langer duurt dan de drempelwaarde van 5 minuten, wordt het automatisch maken van statistieken afgelaten, zodat de query kan doorgaan met de uitvoering. De fout bij het maken van de statistieken kan een negatieve invloed hebben op de mogelijkheid van de optimalisatie van query's om een efficiënt gedistribueerd uitvoeringsplan te genereren, wat resulteert in slechte queryprestaties.

Oplossingen

Maak de statistieken handmatig in plaats van te vertrouwen op de functie voor automatisch maken voor de geïdentificeerde tabellen/kolommen.

Problemen met de uitvoeringsfase

  • Gebruik de volgende tabel om de resultatenset in stap 2 te analyseren. Bepaal uw scenario en controleer de veelvoorkomende oorzaak voor gedetailleerde informatie en de mogelijke risicobeperkingsstappen.

    Scenario Veelvoorkomende oorzaak
    EstimatedRowCount/ActualRowCount< 25% Onnauwkeurige schattingen
    De Description waarde geeft aan BroadcastMoveOperation en de query verwijst naar een gerepliceerde tabel. Gerepliceerde tabellen zonder cache
    1. @ShowActiveOnly = 0
    2. Hoog of onverwacht aantal stappen (step_index) wordt waargenomen.
    3. Gegevenstypen van joinerkolommen zijn niet identiek tussen tabellen.
    Niet-overeenkomend gegevenstype/-grootte
    1. De Description waarde geeft HadoopBroadcastOperationaan, HadoopRoundRobinOperation of HadoopShuffleOperation.
    2. De total_elapsed_time waarde van een gegeven step_index is inconsistent tussen uitvoeringen.
    Ad hoc externe tabelquery's
  • Controleer de total_elapsed_time waarde die u hebt verkregen in stap 3. Als het in een bepaalde stap aanzienlijk hoger is in een aantal distributies, voert u de volgende stappen uit:

    1. Controleer de gegevensdistributie voor elke tabel waarnaar in het TSQL veld step_id wordt verwezen door de volgende opdracht uit te voeren op elke tabel:

      DBCC PDW_SHOWSPACEUSED(<table>);
      
    2. Als <de minimumwaarde> voor rijen/<maximumrijen>> 0,1 is, gaat u naar Gegevens scheeftrekken (opgeslagen).

    3. Anders gaat u naar de scheeftrekken van gegevens in vlucht.

Onnauwkeurige schattingen

Zorg ervoor dat uw statistieken up-to-date zijn om ervoor te zorgen dat de queryoptimalisatie een optimaal plan genereert. Wanneer het geschatte aantal rijen aanzienlijk kleiner is dan de werkelijke aantallen, moeten de statistieken worden gehandhaafd.

Oplossingen

Statistieken maken/bijwerken.


Gerepliceerde tabellen zonder cache

Als u gerepliceerde tabellen hebt gemaakt en u de gerepliceerde tabelcache niet goed kunt warmen, worden onverwachte slechte prestaties veroorzaakt door extra gegevensverplaatsingen of het maken van een suboptimaal gedistribueerd plan.

Oplossingen

  • Warm de gerepliceerde cache op na DML-bewerkingen.
  • Als er frequente DML-bewerkingen zijn, wijzigt u de distributie van de tabel in ROUND_ROBIN.
Niet-overeenkomend gegevenstype/-grootte

Zorg er bij het samenvoegen van tabellen voor dat het gegevenstype en de grootte van de samenvoegingskolommen overeenkomen. Anders leidt dit tot onnodige gegevensverplaatsingen die de beschikbaarheid van CPU-, IO- en netwerkverkeer naar de rest van de workload verminderen.

Oplossingen

Bouw de tabellen opnieuw om de gerelateerde tabelkolommen te corrigeren die geen identiek gegevenstype en -grootte hebben.


Ad hoc externe tabelquery's

Query's op externe tabellen zijn ontworpen met de bedoeling gegevens bulksgewijs te laden in de toegewezen SQL-pool. Ad-hocquery's voor externe tabellen kunnen variabele duur hebben vanwege externe factoren, zoals gelijktijdige opslagcontaineractiviteiten.

Oplossingen

Laad eerst gegevens in de toegewezen SQL-pool en voer vervolgens een query uit op de geladen gegevens.


Scheeftrekken van gegevens (opgeslagen)

Scheeftrekken van gegevens betekent dat de gegevens niet gelijkmatig over de distributies worden verdeeld. Voor elke stap van het gedistribueerde plan moeten alle distributies worden voltooid voordat u naar de volgende stap gaat. Wanneer uw gegevens scheef zijn, kan het volledige potentieel van de verwerkingsresources, zoals CPU en IO, niet worden bereikt, wat resulteert in tragere uitvoeringstijden.

Oplossingen

Bekijk onze richtlijnen voor gedistribueerde tabellen om uw keuze te helpen bij een geschiktere distributiekolom.


Scheeftrekken van gegevens in vlucht

Scheeftrekken van gegevens in vlucht is een variant van het probleem met gegevens scheeftrekken (opgeslagen). Maar het is niet de distributie van gegevens op schijf die scheef is. De aard van het gedistribueerde plan voor bepaalde filters of gegroepeerde gegevens veroorzaakt een ShuffleMoveOperation typebewerking. Deze bewerking produceert een scheve uitvoer die downstream moet worden verbruikt.

Oplossingen

  • Zorg ervoor dat statistieken worden gemaakt en bijgewerkt.
  • Wijzig de volgorde van de GROUP BY kolommen om te leiden met een kolom met een hogere kardinaliteit.
  • Maak statistieken met meerdere kolommen als joins meerdere kolommen omvatten.
  • Voeg een queryhint OPTION(FORCE_ORDER) toe aan uw query.
  • De query herstructureren.

Problemen met wachttype

Als geen van de bovenstaande veelvoorkomende problemen van toepassing is op uw query, bieden de gegevens van stap 3 de mogelijkheid om te bepalen welke wachttypen (in wait_type en wait_time) de verwerking van query's verstoren voor de langst lopende stap. Er zijn een groot aantal wachttypen en ze zijn gegroepeerd in gerelateerde categorieën vanwege vergelijkbare oplossingen. Volg deze stappen om de wachtcategorie van de querystap te vinden:

  1. Identificeer de wait_type in stap 3 die de meeste tijd in beslag neemt.
  2. Zoek het wachttype in de toewijzingstabel met wachtcategorieën en identificeer de wachtcategorie waarin deze is opgenomen.
  3. Vouw de sectie met betrekking tot de wachtcategorie uit de volgende lijst uit voor aanbevolen oplossingen.
Verzamelwerk

Volg deze stappen om wachttypeproblemen van de categorie Compilatie te beperken:

  1. Bouw indexen opnieuw op voor alle objecten die betrokken zijn bij de problematische query.
  2. Werk statistieken bij over alle objecten die betrokken zijn bij de problematische query.
  3. Test de problematische query opnieuw om te controleren of het probleem zich blijft voordoen.

Als het probleem zich blijft voordoen, gaat u als volgende te werk:

  1. Maak een .sql-bestand met:

    SET QUERY_DIAGNOSTICS ON; <Your_SQL>; SET QUERY_DIAGNOSTICS OFF;
    
  2. Open een opdrachtpromptvenster en voer de volgende opdracht uit:

    sqlcmd −S <servername>.database.windows.net −d <databasename> −U <username> −G −I −i .\<sql_file_name>.sql −y0 −o .\<output_file_name>.txt
    
  3. Open <output_file_name>.txt in een teksteditor. Plak de uitvoeringsplannen op distributieniveau (regels die beginnen met<ShowPlanXML>) uit de langstlopende stap die in stap 2 is geïdentificeerd, in afzonderlijke tekstbestanden met de extensie .sqlplan.

    Opmerking: Elke stap van het gedistribueerde plan heeft doorgaans 60 uitvoeringsplannen op distributieniveau vastgelegd. Zorg ervoor dat u uitvoeringsplannen voorbereidt en vergelijkt met dezelfde gedistribueerde planstap.

  4. In de stap 3-query worden vaak enkele distributies weergegeven die veel langer duren dan andere. Vergelijk in SQL Server Management Studio de uitvoeringsplannen op distributieniveau (van de sqlplan-bestanden die zijn gemaakt) van een langlopende distributie naar een snelle distributie om mogelijke oorzaken voor verschillen te analyseren.

Vergrendelen, werkrolthread
  • Overweeg om tabellen te wijzigen die regelmatig kleine wijzigingen ondergaan om een rijarchiefindex te gebruiken in plaats van CCI.
  • Batcheer uw wijzigingen en werk het doel bij met meer rijen op een minder frequente basis.
Buffer-IO, andere schijf-IO, Tran Log IO

Onjuiste CCIS's

Slechte CCIS's dragen bij aan een verhoogde I/O-, CPU- en geheugentoewijzing, wat op zijn beurt een negatieve invloed heeft op de queryprestaties. Probeer een van de volgende methoden om dit probleem te verhelpen:

Verouderde statistieken

Verouderde statistieken kunnen leiden tot het genereren van een niet-geoptimaliseerd gedistribueerd plan, waarbij meer gegevens worden verplaatst dan nodig is. Onnodige gegevensverplaatsing verhoogt niet alleen de werkbelasting op uw data-at-rest, maar ook op de tempdb. Omdat I/O een gedeelde resource is voor alle query's, zijn de gevolgen voor de prestaties merkbaar in de gehele workload.

Om deze situatie te verhelpen, moet u ervoor zorgen dat alle statistieken up-to-date zijn en dat er een onderhoudsplan is om ze bijgewerkt te houden voor gebruikersworkloads.

Zware IO-workloads

Uw totale workload kan grote hoeveelheden gegevens lezen. Toegewezen Synapse SQL-pools schalen resources in overeenstemming met de DWU. Overweeg een of beide om betere prestaties te bereiken:

CPU, parallellisme
Scenario Oplossing
Slechte CCI-status De status van de geclusterde columnstore-index in een toegewezen SQL-pool beoordelen en corrigeren
Gebruikersquery's bevatten transformaties Verplaats alle opmaak- en andere transformatielogica naar ETL-processen, zodat de opgemaakte versies worden opgeslagen
Workload is niet goed geprioriteerd Isolatie van werkbelastingen implementeren
Onvoldoende DWU voor workload Overweeg het verhogen van rekenresources

Netwerk-IO

Als het probleem optreedt tijdens een RETURN bewerking in stap 2,

  • Verminder het aantal gelijktijdige parallelle processen.
  • Schaal het meest beïnvloede proces uit naar een andere client.

Voor alle andere bewerkingen voor gegevensverplaatsing is het waarschijnlijk dat de netwerkproblemen intern lijken te zijn voor de toegewezen SQL-pool. Voer de volgende stappen uit om dit probleem snel te verhelpen:

  1. Uw toegewezen SQL-pool uit te breiden naar DW100c
  2. Terugschalen naar het gewenste DWU-niveau
SQL CLR

Vermijd frequent gebruik van de FORMAT() functie door een alternatieve manier te implementeren om de gegevens te transformeren (bijvoorbeeld CONVERT() met stijl).