Lösa problem med datasnedvridning i Azure Data Lake Analytics med hjälp av Azure Data Lake Tools för Visual Studio

Viktigt!

Azure Data Lake Analytics drogs tillbaka den 29 februari 2024. Lär dig mer med det här tillkännagivandet.

För dataanalys kan din organisation använda Azure Synapse Analytics eller Microsoft Fabric.

Vad är dataförskjutning?

Kort sagt är datasnedvridning ett överrepresenterat värde. Anta att du har tilldelat 50 skattekontrollanter till granskning av skattedeklarationer, en granskare för varje amerikansk stat. Wyoming-examinatorn, eftersom befolkningen där är liten, har lite att göra. I Kalifornien hålls dock examinatorn upptagen på grund av delstatens stora befolkning.

Ett exempelkolumndiagram som visar majoriteten av data som grupperas i två kolumner i stället för att vara jämnt fördelade över kategorier.

I vårt scenario är data ojämnt fördelade över alla skattekontrollanter, vilket innebär att vissa granskare måste arbeta mer än andra. I ditt eget jobb upplever du ofta situationer som skatteprövarexemplet här. I mer tekniska termer får en nod mycket mer data än sina andra noder, en situation som gör att noden arbetar mer än de andra och som så småningom saktar ner ett helt uppdrag. Vad värre är kan jobbet misslyckas eftersom hörn kan ha till exempel en begränsning på 5 timmar och en minnesbegränsning på 6 GB.

Lösa problem med dataskevhet

Azure Data Lake Tools för Visual Studio och Visual Studio Code kan hjälpa dig att identifiera om ditt arbete har ett dataskevproblem.

Om det finns ett problem kan du lösa det genom att prova lösningarna i det här avsnittet.

Lösning 1: Förbättra tabellpartitioneringen

Alternativ 1: Filtrera det skeva nyckelvärdet i förväg

Om det inte påverkar din affärslogik kan du filtrera värdena med högre frekvens i förväg. Om det till exempel finns många 000-000-000 i kolumn-GUID kanske du inte vill aggregera det värdet. Innan du aggregerar kan du skriva "WHERE GUID != "000-000-000" för att filtrera högfrekvensvärdet.

Alternativ 2: Välj en annan partition eller distributionsnyckel

Om du bara vill kontrollera skattegranskningsarbetsbelastningen i hela landet/regionen i föregående exempel kan du förbättra datafördelningen genom att välja ID-numret som din nyckel. Att välja en annan partition eller distributionsnyckel kan ibland fördela data jämnare, men du måste se till att det här valet inte påverkar din affärslogik. Om du till exempel vill beräkna skattesumman för varje stat kanske du vill ange Stat som partitionsnyckel. Om problemet kvarstår kan du prova att använda alternativ 3.

Alternativ 3: Lägg till fler partitions- eller distributionsnycklar

I stället för att bara använda Tillstånd som en partitionsnyckel kan du använda mer än en nyckel för partitionering. Överväg till exempel att lägga till postnummer som en annan partitionsnyckel för att minska storleken på datapartitionen och distribuera data jämnare.

Alternativ 4: Använd rundgångsfördelning

Om du inte hittar en lämplig nyckel för partition och distribution kan du försöka använda rundgångsfördelning. Round-robin-distribution behandlar alla rader lika och placerar dem slumpmässigt i motsvarande grupper. Data distribueras jämnt, men den förlorar lokal information, en nackdel som också kan minska jobbprestanda för vissa åtgärder. Om du utför aggregering för den skeva nyckeln ändå kvarstår problemet med datasnedvridning. För att lära dig mer om round-robin distribution, se avsnittet U-SQL Table Distributions i CREATE TABLE (U-SQL): Skapa en tabell med schema.

Lösning 2: Förbättra frågeplanen

Alternativ 1: Använd instruktionen CREATE STATISTICS

U-SQL tillhandahåller instruktionen CREATE STATISTICS i tabeller. Den här instruktionen ger mer information till frågeoptimeraren om de dataegenskaper (till exempel värdedistribution) som lagras i en tabell. För de flesta frågor genererar frågeoptimeraren redan nödvändig statistik för en frågeplan av hög kvalitet. Ibland kan du behöva förbättra frågeprestanda genom att skapa mer statistik med CREATE STATISTICS eller genom att ändra frågedesignen. Mer information finns på sidan SKAPA STATISTIK (U-SQL).

Kodexempel:

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

Anmärkning

Statistikinformation uppdateras inte automatiskt. Om du uppdaterar data i en tabell utan att återskapa statistiken kan frågeprestandan försämras.

Alternativ 2: Använd SKEWFACTOR

Om du vill summera skatten för varje stat måste du använda GROUP BY-tillstånd, en metod som inte undviker problemet med datasnedvridning. Du kan dock ange en dataindikator i din fråga för att identifiera dataskew i nycklar så att optimeraren kan förbereda en utförandeplan åt dig.

Vanligtvis kan du ange parametern som 0,5 och 1, med 0,5 som inte betyder mycket skevhet och en som betyder kraftig skevhet. Eftersom anvisningen påverkar körningsplanens optimering för den aktuella instruktionen och alla efterföljande instruktioner, måste du lägga till anvisningen innan den potentiella snedfördelade nyckelvisa aggregeringen.

SKEWFACTOR (columns) = x

Ger ett tips om att de angivna kolumnerna har en skev faktor x från 0 (ingen skevhet) till 1 (kraftig skevhet).

Kodexempel:

//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
    ;

Alternativ 3: Använd ROWCOUNT

Förutom SKEWFACTOR kan du, om du vet att den andra kopplade raduppsättningen är liten, berätta för optimeraren genom att lägga till ett ROWCOUNT-tips i U-SQL-instruktionen före JOIN. På så sätt kan optimeraren välja en strategi för sändningskoppling för att förbättra prestandan. Tänk på att ROWCOUNT inte löser problemet med datasnedvridning, men det kan ge lite extra hjälp.

OPTION(ROWCOUNT = n)

Identifiera en liten raduppsättning före JOIN genom att ange ett uppskattat antal heltalsrader.

Kodexempel:

//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
            ;

Lösning 3: Förbättra den användardefinierade reducern och kombinatorn

Ibland kan du skriva en användardefinierad operator för att hantera komplicerad processlogik, och en välskriven reducer och kombinator kan i vissa fall minska ett problem med datasnedställning.

Alternativ 1: Använd en rekursiv reducer, om möjligt

Som standard körs en användardefinierad reducer i icke-rekursivt läge, vilket innebär att minskningsarbetet för en nyckel distribueras till en enda nod. Men om dina data är skeva kan de enorma datauppsättningarna bearbetas i en enda nod och köras under lång tid.

För att förbättra prestandan kan du lägga till ett attribut i koden för att definiera reducer som ska köras i rekursivt läge. Sedan kan de enorma datauppsättningarna distribueras till flera hörn och köras parallellt, vilket påskyndar ditt jobb.

Om du vill ändra en icke-rekursiv reducer till rekursiv måste du se till att algoritmen är associativ. Summan är till exempel associativ och medianvärdet är inte det. Du måste också se till att indata och utdata för reducer behåller samma schema.

Attribut för rekursiv reducer:

[SqlUserDefinedReducer(IsRecursive = true)]

Kodexempel:

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

Alternativ 2: Använd kombinerarläge på radnivå, om möjligt

På samma sätt som ROWCOUNT-tipset för specifika kopplingsfall med skev nyckel försöker kombinationsläget distribuera enorma värdeuppsättningar med skev nyckel till flera hörn så att arbetet kan köras samtidigt. Kombineringsläge kan inte lösa problem med dataskevhet, men det kan ge lite extra hjälp för enorma uppsättningar av skeva nyckelvärden.

Som standard är kombinationsläget Fullt, vilket innebär att den vänstra raduppsättningen och den högra raduppsättningen inte kan separeras. Om du ställer in läget som Vänster/Höger/Inre aktiveras koppling på radnivå. Systemet separerar motsvarande raduppsättningar och distribuerar dem till flera noder som körs parallellt. Innan du konfigurerar kombinationsläget bör du dock vara noga med att se till att motsvarande raduppsättningar kan separeras.

Följande exempel visar en avgränsad vänsterradsuppsättning. Varje utdatarad beror på en enda indatarad från vänster, och den kan bero på alla rader från höger med samma nyckelvärde. Om du ställer in kombinationsläget till vänster separerar systemet den enorma vänstra raduppsättningen i små och tilldelar dem till flera hörn.

Två kolumner med rader som representerar datauppsättningar till vänster och höger, som visar några rader i den högra datauppsättningen som flyttas till den första gruppen i den vänstra datauppsättningen.

Anmärkning

Om du anger fel kombinationsläge är kombinationen mindre effektiv och resultatet kan vara fel.

Attribut för kombinationsläge:

  • SqlUserDefinedCombiner(Mode=CombinerMode.Full): Varje utdatarad är potentiellt beroende av alla indatarader från vänster och höger med samma nyckelvärde.

  • SqlUserDefinedCombiner(Mode=CombinerMode.Left): Varje utdatarad beror på en enskild indatarad från vänster (och eventuellt alla rader från höger med samma nyckelvärde).

  • qlUserDefinedCombiner(Mode=CombinerMode.Right): Varje utdatarad beror på en enskild indatarad från höger (och eventuellt alla rader från vänster med samma nyckelvärde).

  • SqlUserDefinedCombiner(Mode=CombinerMode.Inner): Varje utdatarad beror på en enskild indatarad från vänster och höger med samma värde.

Kodexempel:

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