sql >> Databasteknik >  >> RDS >> Mysql

SQL UNION ALL för att eliminera dubbletter

Men i exemplet har den första frågan ett villkor i kolumn a , medan den andra frågan har ett villkor i kolumn b . Det här kom förmodligen från en fråga som är svår att optimera:

SELECT * FROM mytable WHERE a=X OR b=Y

Den här frågan är svår att optimera med enkel B-trädindexering. Söker motorn ett index på kolumn a ? Eller i kolumn b ? Hur som helst, sökning efter den andra termen kräver en tabellskanning.

Därav tricket att använda UNION för att dela upp i två frågor för en term vardera. Varje underfråga kan använda det bästa indexet för varje sökterm. Kombinera sedan resultaten med UNION.

Men de två delmängderna kan överlappa varandra, eftersom vissa rader är b=Y kan också ha a=X i vilket fall sådana rader förekommer i båda delmängderna. Därför måste du eliminera dubbletter, annars ser du några rader två gånger i slutresultatet.

SELECT * FROM mytable WHERE a=X 
UNION DISTINCT
SELECT * FROM mytable WHERE b=Y

UNION DISTINCT är dyrt eftersom typiska implementeringar sorterar raderna för att hitta dubbletter. Precis som om du använder SELECT DISTINCT ... .

Vi har också en uppfattning om att det är ännu mer "bortkastat" arbete om de två undergrupperna av rader som du sammanför har många rader som förekommer i båda undergrupperna. Det är många rader att eliminera.

Men det finns inget behov av att eliminera dubbletter om du kan garantera att de två uppsättningarna av rader redan är åtskilda. Det vill säga om du garanterar att det inte finns någon överlappning. Om du kan lita på det, skulle det alltid vara en no-op att eliminera dubbletter, och därför kan frågan hoppa över det steget och därför hoppa över den kostsamma sorteringen.

Om du ändrar frågorna så att de garanterat väljer icke-överlappande delmängder av rader, är det en vinst.

SELECT * FROM mytable WHERE a=X 
UNION ALL 
SELECT * FROM mytable WHERE b=Y AND a!=X

Dessa två set har garanterat ingen överlappning. Om den första uppsättningen har rader där a=X och den andra uppsättningen har rader där a!=X då kan det inte finnas någon rad som finns i båda uppsättningarna.

Den andra frågan fångar därför bara en del av raderna där b=Y , men vilken rad som helst där a=X AND b=Y ingår redan i den första uppsättningen.

Så frågan uppnår en optimerad sökning efter två OR termer, utan att producera dubbletter och som inte kräver någon UNION DISTINCT operation.



  1. Databasinsättningsprestanda

  2. Välj uttalande för att returnera förälder och oändliga barn

  3. Uppdatera alla rader i databasen med ett hashvärde

  4. Att hämta slumpmässiga data från en MySQL-databas men inte upprepa data