Problemen met scheeftrekken van gegevens in Azure Data Lake Analytics oplossen met behulp van Azure Data Lake Tools voor Visual Studio

Belangrijk

Azure Data Lake Analytics is op 29 februari 2024 buiten gebruik gesteld. Meer informatie vindt u in deze aankondiging.

Voor gegevensanalyse kan uw organisatie gebruikmaken van Azure Synapse Analytics- of Microsoft Fabric-.

Wat is scheeftrekken van gegevens?

Kort gezegd is gegevensscheefheid een oververtegenwoordigde waarde. Stel dat u 50 tax examiners hebt toegewezen om belastingaangiften te controleren, één onderzoeker voor elke Amerikaanse staat. De Wyoming-onderzoeker, omdat de populatie klein is, heeft weinig te doen. In Californië heeft de examinator het echter druk vanwege het grote bevolkingsaantal van de staat.

Een voorbeeldkolomdiagram waarin het merendeel van de gegevens wordt gegroepeerd in twee kolommen, in plaats van gelijkmatig over categorieën te worden verdeeld.

In ons scenario zijn de gegevens ongelijk verdeeld over alle belastinginspecteurs, wat betekent dat sommige inspecteurs meer moeten werken dan anderen. In uw eigen werk komt u vaak situaties tegen zoals het voorbeeld van de belastinginspecteur hier. In meer technische termen krijgt één hoekpunt veel meer gegevens dan de peers, een situatie waardoor het hoekpunt meer werkt dan de andere en dat uiteindelijk een hele taak vertraagt. Wat erger is, de taak kan mislukken, omdat hoekpunten bijvoorbeeld een runtimebeperking van 5 uur en een geheugenbeperking van 6 GB hebben.

Problemen met scheeftrekken van gegevens oplossen

Met Azure Data Lake Tools voor Visual Studio en Visual Studio Code kunt u detecteren of uw taak een probleem met gegevensverschil heeft.

Als er een probleem bestaat, kunt u dit oplossen door de oplossingen in deze sectie uit te proberen.

Oplossing 1: Tabelpartitionering verbeteren

Optie 1: De scheefgetrokken sleutelwaarde van tevoren filteren

Als dit geen invloed heeft op uw bedrijfslogica, kunt u de waarden met een hogere frequentie van tevoren filteren. Als er bijvoorbeeld veel 000-000-000-000 in kolom-GUID zijn, wilt u die waarde mogelijk niet aggregeren. Voordat u samenvoegt, kunt u 'WHERE GUID != '000-000-000' schrijven om de waarde met hoge frequentie te filteren.

Optie 2: Kies een andere partitie of distributiesleutel

Als u in het voorgaande voorbeeld alleen de belastingcontroleworkload in het hele land/de regio wilt controleren, kunt u de gegevensdistributie verbeteren door het id-nummer als uw sleutel te selecteren. Het kiezen van een andere partitie- of distributiesleutel kan de gegevens soms gelijkmatiger verdelen, maar u moet ervoor zorgen dat deze keuze geen invloed heeft op uw bedrijfslogica. Als u bijvoorbeeld de belastingsom voor elke staat wilt berekenen, kunt u de status als partitiesleutel aanwijzen. Als u dit probleem blijft ondervinden, kunt u optie 3 gebruiken.

Optie 3: Meer partitie- of distributiesleutels toevoegen

In plaats van alleen State als partitiesleutel te gebruiken, kunt u meer dan één sleutel gebruiken voor partitionering. U kunt bijvoorbeeld postcode toevoegen als een andere partitiesleutel om de grootte van de gegevenspartitie te verminderen en de gegevens gelijkmatiger te distribueren.

Optie 4: Round robin-distributie gebruiken

Als u geen geschikte sleutel voor partitie en distributie kunt vinden, kunt u proberen round robin-distributie te gebruiken. Round robin-distributie behandelt alle rijen gelijkmatig en plaatst ze willekeurig in bijbehorende buckets. De gegevens worden gelijkmatig gedistribueerd, maar verliezen lokaliteitsgegevens, een nadeel dat ook de prestaties van taken voor sommige bewerkingen kan verminderen. Daarnaast, als u toch aggregatie uitvoert voor de scheve sleutel, zal het probleem met gegevensscheefheid blijven bestaan. Zie de sectie U-SQL-tabeldistributies in CREATE TABLE (U-SQL): Een tabel maken met schema voor meer informatie over round robin-distributie.

Oplossing 2: Het queryplan verbeteren

Optie 1: de instructie CREATE STATISTICS gebruiken

U-SQL biedt de instructie CREATE STATISTICS voor tabellen. Deze instructie geeft meer informatie aan de optimalisatiefunctie voor query's over de gegevenskenmerken (bijvoorbeeld waardedistributie) die zijn opgeslagen in een tabel. Voor de meeste query's genereert de queryoptimalisatie al de benodigde statistieken voor een queryplan van hoge kwaliteit. Soms moet u de queryprestaties verbeteren door meer statistieken te maken met CREATE STATISTICS of door het queryontwerp te wijzigen. Zie de pagina CREATE STATISTICS (U-SQL) voor meer informatie.

Codevoorbeeld:

CREATE STATISTICS IF NOT EXISTS stats_SampleTable_date ON SampleDB.dbo.SampleTable(date) WITH FULLSCAN;

Notitie

Statistiekengegevens worden niet automatisch bijgewerkt. Als u de gegevens in een tabel bijwerkt zonder de statistieken opnieuw te maken, kunnen de queryprestaties afnemen.

Optie 2: Gebruik scheefheidsfactor

Als u de belasting voor elke staat wilt optellen, moet u GROUP BY-status gebruiken, een benadering die het probleem met gegevens scheeftrekken niet voorkomt. U kunt echter een gegevenshint in uw query opgeven om scheeftrekken van gegevens in sleutels te identificeren, zodat de optimizer een uitvoeringsplan voor u kan voorbereiden.

Meestal kunt u de parameter instellen op 0,5 en 1, waarbij 0,5 staat voor weinig scheefheid en 1 voor zware scheefheid. Omdat de hint van invloed is op optimalisatie van het uitvoeringsplan voor de huidige instructie en alle downstream-instructies, moet u de hint toevoegen vóór de mogelijke scheefgetrokken sleutelgewijze aggregatie.

SKEWFACTOR (columns) = x

Geeft een hint dat de opgegeven kolommen een scheefheidsfactor x hebben van 0 (geen scheefheid) tot en met 1 (zware scheefheid).

Codevoorbeeld:

//Add a SKEWFACTOR hint.
@Impressions =
    SELECT * FROM
    searchDM.SML.PageView(@start, @end) AS PageView
    OPTION(SKEWFACTOR(Query)=0.5)
    ;
//Query 1 for key: Query, ClientId
@Sessions =
    SELECT
        ClientId,
        Query,
        SUM(PageClicks) AS Clicks
    FROM
        @Impressions
    GROUP BY
        Query, ClientId
    ;
//Query 2 for Key: Query
@Display =
    SELECT * FROM @Sessions
        INNER JOIN @Campaigns
            ON @Sessions.Query == @Campaigns.Query
    ;

Optie 3: ROWCOUNT gebruiken

Naast SCHEEFHEIDSFACTOR kunt u de optimizer vertellen om een ROWCOUNT-hint toe te voegen in de U-SQL-instructie voordat JOIN wordt uitgevoerd, als u weet dat de andere gekoppelde rijset klein is voor specifieke joincases met scheve sleutels. Op deze manier kan optimizer een strategie voor broadcastdeelname kiezen om de prestaties te verbeteren. Houd er rekening mee dat ROWCOUNT het probleem met gegevensverschil niet oplost, maar dat dit extra hulp kan bieden.

OPTION(ROWCOUNT = n)

Identificeer een kleine rijset voor JOIN door een geschat totaal aantal rijen op te geven.

Codevoorbeeld:

//Unstructured (24-hour daily log impressions)
@Huge   = EXTRACT ClientId int, ...
            FROM @"wasb://ads@wcentralus/2015/10/30/{*}.nif"
            ;
//Small subset (that is, ForgetMe opt out)
@Small  = SELECT * FROM @Huge
            WHERE Bing.ForgetMe(x,y,z)
            OPTION(ROWCOUNT=500)
            ;
//Result (not enough information to determine simple broadcast JOIN)
@Remove = SELECT * FROM Bing.Sessions
            INNER JOIN @Small ON Sessions.Client == @Small.Client
            ;

Oplossing 3: de door de gebruiker gedefinieerde reducer en combinatie verbeteren

Soms kunt u een door de gebruiker gedefinieerde operator schrijven om complexe proceslogica af te handelen, en een goed geschreven reducer en combinatie kunnen in sommige gevallen een probleem met gegevensverschil beperken.

Optie 1: Gebruik indien mogelijk een recursieve reducer

Standaard wordt een gebruikersgedefinieerde reducer uitgevoerd in niet-recursieve stand, wat betekent dat het reduceren van werk voor een sleutel wordt verdeeld over één vertex. Maar als uw gegevens scheef verdeeld zijn, kunnen de grote datasets in een enkele verwerkingsknoop worden verwerkt en lange tijd duren.

Om de prestaties te verbeteren, kunt u een kenmerk in uw code toevoegen om reducer te definiëren die in recursieve modus moet worden uitgevoerd. Vervolgens kunnen de enorme gegevenssets worden gedistribueerd naar meerdere hoekpunten en parallel worden uitgevoerd, waardoor uw taak sneller wordt.

Als u een niet-recursieve reducer wilt wijzigen in recursief, moet u ervoor zorgen dat uw algoritme associatief is. De som is bijvoorbeeld associatief en de mediaan niet. U moet er ook voor zorgen dat de invoer en uitvoer voor reducer hetzelfde schema behouden.

Kenmerk van recursieve reducer:

[SqlUserDefinedReducer(IsRecursive = true)]

Codevoorbeeld:

[SqlUserDefinedReducer(IsRecursive = true)]
public class TopNReducer : IReducer
{
    public override IEnumerable<IRow>
        Reduce(IRowset input, IUpdatableRow output)
    {
        //Your reducer code goes here.
    }
}

Optie 2: Combinatiemodus op rijniveau inschakelen, indien mogelijk

Net als bij de ROWCOUNT-hint voor specifieke scheefsleutel-joingevallen, probeert de combinatiemodus enorme scheefsleutelwaardeverzamelingen te distribueren naar meerdere knooppunten, zodat het werk gelijktijdig kan worden uitgevoerd. De combinatiemodus kan problemen met gegevens scheeftrekken niet oplossen, maar het kan wel extra hulp bieden voor enorme sets met scheve sleutelwaarden.

Standaard is de combinatiemodus Volledig, wat betekent dat de linkerrijset en de rechterrijset niet kunnen worden gescheiden. Als u de modus instelt op Links/Rechts/Inner, wordt een join op rijniveau ingeschakeld. Het systeem scheidt de bijbehorende rijensets en distribueert deze in meerdere hoekpunten die parallel worden uitgevoerd. Voordat u de combinatiemodus configureert, moet u er echter voor zorgen dat de bijbehorende rijenets kunnen worden gescheiden.

In het volgende voorbeeld ziet u een gescheiden linkerrijset. Elke uitvoerrij is afhankelijk van één invoerrij aan de linkerkant en is mogelijk afhankelijk van alle rijen van rechts met dezelfde sleutelwaarde. Als u de combinatie-instelling op links zet, verdeelt het systeem de grote set van linkerrijen in kleine delen en wijst deze toe aan meerdere hoekpunten.

Twee kolommen met rijen die gegevenssets links en rechts vertegenwoordigen, met enkele rijen van de rechtergegevensset die worden verplaatst naar de eerste groep van de linkergegevensset.

Notitie

Als u de verkeerde combinatiemodus instelt, is de combinatie minder efficiënt en zijn de resultaten mogelijk onjuist.

Kenmerken van combinatiemodus:

  • SqlUserDefinedCombiner(Mode=CombinerMode.Full): elke uitvoerrij is mogelijk afhankelijk van alle invoerrijen van links en rechts met dezelfde sleutelwaarde.

  • SqlUserDefinedCombiner(Mode=CombinerMode.Left): elke uitvoerrij is afhankelijk van één invoerrij aan de linkerkant (en mogelijk alle rijen van rechts met dezelfde sleutelwaarde).

  • qlUserDefinedCombiner(Mode=CombinerMode.Right): Elke uitvoerrij is afhankelijk van één invoerrij van rechts (en mogelijk alle rijen van links met dezelfde sleutelwaarde).

  • SqlUserDefinedCombiner(Mode=CombinerMode.Inner): elke uitvoerrij is afhankelijk van één invoerrij van links en rechts met dezelfde waarde.

Codevoorbeeld:

[SqlUserDefinedCombiner(Mode = CombinerMode.Right)]
public class WatsonDedupCombiner : ICombiner
{
    public override IEnumerable<IRow>
        Combine(IRowset left, IRowset right, IUpdatableRow output)
    {
    //Your combiner code goes here.
    }
}