sql >> Database teknologi >  >> RDS >> SQLite

SQLite-indstilling af ydeevne

SQLite er en populær relationel database, som du integrerer i din applikation. Med en stigende mængde data i din database, skal du anvende SQLite-ydelsesjustering. Denne artikel diskuterer indekser og dets faldgruber, brugen af ​​forespørgselsplanlæggeren, journaltilstanden Write-Ahead-Logging (WAL) og forøgelse af cachestørrelsen. Den uddyber også vigtigheden af ​​at måle effekten af ​​dine tweaks ved hjælp af automatiserede tests.

Introduktion

SQLite er et populært relationsdatabasesystem (DB) . I modsætning til dets større, klient-serverbaserede brødre, såsom MySQL, kan SQLite indlejres i din applikation som et bibliotek . SQLite har et meget lignende funktionssæt og kan også håndtere millioner af rækker, givet at du kender et par tips og tricks om performance tuning. Som de følgende afsnit vil vise, er der mere at vide om SQLite-ydelsesjustering end blot at oprette indekser.

Opret indekser, men med forsigtighed

Den grundlæggende idé med et indeks er at fremskynde læsningen af specifikke data , dvs. SELECT udsagn med en WHERE klausul. Indekser fremskynder også sortering data (ORDER BY ), eller JOIN ing tabeller. Desværre er indekser et tveægget sværd, fordi de bruger ekstra diskplads, og de forsinker datamanipulation (INSERT , UPDATE , DELETE ).

Det generelle råd er at oprette så få indekser som muligt, men så mange som nødvendigt . Indekser giver også kun mening for større databaser med tusinder eller millioner af rækker.

Brug forespørgselsplanlæggeren til at analysere dine forespørgsler

Måden indeks bruges internt af SQLite er dokumenteret, men ikke særlig let at forstå. Som yderligere uddybet i denne artikel, er det en god idé at analysere en forespørgsel ved at sætte den foran med EXPLAIN QUERY PLAN . Tag et kig på hver outputlinje, hvoraf der er tre grundlæggende varianter:

  • SEARCH table ... linjer er et godt tegn – SQLite bruger et af dine indekser!
  • SCAN table ... USING INDEX er et dårligt tegn,
  • SCAN table ... er endnu værre!

Prøv at undgå SCAN table [using index] poster i outputtet af EXPLAIN QUERY PLAN når det er muligt, fordi du vil løbe ind i ydeevneproblemer på større databaser. Brug EXPLAIN QUERY PLAN til iterativ tilføj eller rediger dine indekser, indtil der ikke er mere SCAN table poster vises.

Optimer forespørgsler, der involverer IS NOT

Søger efter IS NOT ... er dyrt fordi SQLite bliver nødt til at scanne alle rækker i tabellen, selvom den berørte kolonne har et indeks . Indeks er kun nyttige, hvis du leder efter specifikke værdier, dvs. sammenligninger, der involverer < (mindre), > (større), eller = (lige), men de ansøger ikke om !=(ulige).

Et smart lille trick er, at du kan erstatte WHERE column != value med WHERE column > value OR column < value . Dette vil bruge kolonnens indeks og effektivt påvirke alle rækker, hvis værdi ikke er lig med value . Tilsvarende en WHERE stringColumn != '' kan erstattes af WHERE stringColumn > '' , fordi strenge er sorterbare. Når du anvender dette trick, skal du dog sikre dig, hvordan SQLite håndterer NULL sammenligninger. For eksempel evaluerer SQLite NULL > '' som FALSE .

Hvis du bruger et sådant sammenligningstrick, er der en anden advarsel, hvis din forespørgsel indeholder WHERE og ORDER BY , hver med en anden kolonne:dette vil gøre forespørgslen ineffektiv igen. Hvis det er muligt, skal du bruge samme kolonne i WHERE og ORDER BY , eller opbyg et dækkende indeks der involverer både WHERE og ORDER BY kolonne.

Forbedre skrivehastigheden med Write-Ahead-Log

Write-Ahead-Logging (WAL) journaltilstand forbedrer skrive-/opdateringsydelsen markant , sammenlignet med standard tilbageføring journaltilstand. Men som dokumenteret her er der nogle få forbehold . For eksempel er WAL-tilstand ikke tilgængelig på visse operativsystemer. Der er også reducerede datakonsistensgarantier i tilfælde af hardwarefejl . Sørg for at læse de første par sider for at forstå, hvad du laver.

Jeg fandt ud af, at kommandoen PRAGMA synchronous = NORMAL giver en 3-4x speedup. Indstilling af journal_mode til WAL forbedrer derefter ydeevnen betydeligt igen (ca. 10x eller mere, afhængigt af operativsystemet).

Udover de forbehold, jeg allerede har nævnt, skal du også være opmærksom på følgende:

  • Ved brug af WAL-journaltilstand vil der være to yderligere filer ved siden af ​​databasefilen på dit filsystem, som har samme navn som databasen, men med suffikset "-shm" og "-wal". Normalt behøver du ikke være ligeglad, men hvis du skulle sende databasen til en anden maskine, mens din applikation kører, så glem ikke at inkludere disse to filer. SQLite vil komprimere disse to filer til hovedfilen, når du normalt lukker alle åbne databaseforbindelser.
  • Indsættelses- eller opdateringsydelsen vil af og til falde, når forespørgslen udløser sammenlægningen af ​​WAL-logfilens indhold i hoveddatabasefilen. Dette kaldes checkpointing , se her.
  • Jeg fandt den PRAGMA s, der ændrer journal_mode og synchronous ser ikke ud til at være konstant gemt i databasen. Derfor har jeg altid genudfør dem, hver gang jeg åbner en ny databaseforbindelse, i stedet for blot at udføre dem, når du opretter tabellerne for første gang.

Mål alt

Når du tilføjer ydeevnejusteringer, skal du sørge for at måle effekten. Automatiske (enheds)tests er en fantastisk tilgang til dette. De hjælper med at dokumentere dine resultater for dit team, og de vil afsløre afvigende adfærd over tid , for eksempel. når du opdaterer til en nyere SQLite-version. Eksempler på hvad du kan måle:

  • Hvad er effekten af ​​at bruge WAL journaltilstand over tilbageføringen mode? Hvad er effekten af ​​andre (angiveligt) præstationsfremmende PRAGMA s?
  • Når du tilføjer/ændrer/fjerner et indeks, hvor meget hurtigere går SELECT udsagn bliver? Hvor meget langsommere går INSERT/DELETE/UPDATE udsagn bliver?
  • Hvor meget ekstra diskplads bruger indekserne?

For enhver af disse tests skal du overveje at gentage dem med varierende databasestørrelser. For eksempel. køre dem på en tom database, og også på en database, der allerede indeholder tusindvis (eller millioner) af poster. Du bør også køre testene på forskellige enheder og operativsystemer, især hvis dit udviklings- og produktionsmiljø er væsentligt anderledes.

Juster cachestørrelsen

SQLite gemmer midlertidig information i en cache (i RAM), f.eks. mens du bygger resultaterne af en SELECT forespørgsel, eller ved manipulation af data, som endnu ikke er blevet begået. Som standard er denne størrelse sølle 2 MB . Moderne stationære maskiner kan spare meget mere. Kør PRAGMA cache_size = -kibibytes for at øge denne værdi (husk på minus tegn foran værdien!). Se her for yderligere information. Igen, mål hvilken indflydelse denne indstilling har på ydeevnen!

Brug REPLACE INTO til at oprette eller opdatere en række

Dette er måske ikke så meget en præstationsjustering, da det er et pænt lille trick. Antag, at du skal opdatere en række i tabel t , eller opret en række, hvis den ikke eksisterer endnu. I stedet for at bruge to forespørgsler (SELECT efterfulgt af INSERT eller UPDATE ), brug REPLACE INTO (officielle dokumenter).

For at dette skal virke, skal du tilføje en ekstra dummy-kolonne (f.eks. replacer ) til tabellen t , som har en UNIQUE begrænse. Kolonnens erklæring kunne f.eks. være ... replacer INTEGER UNIQUE ... der er en del af din CREATE TABLE udmelding. Brug derefter en forespørgsel som f.eks.

REPLACE INTO t (col1, col2, ..., replacer) VALUES (?,?,...,1)Code language: SQL (Structured Query Language) (sql)

Når denne forespørgsel kører for første gang, udfører den blot en INSERT . Når det køres anden gang, vises UNIQUE begrænsning af replacer kolonnen udløses, og konfliktløsningsadfærden vil få den gamle række til at blive slettet, hvilket automatisk skaber en ny. Du kan også finde den relaterede UPSERT-kommando som nyttig.

Konklusion

Når antallet af rækker i din database vokser, bliver ydelsesjusteringer en nødvendighed. Indeks er den mest almindelige løsning. De bytter forbedret tidskompleksitet med reduceret pladskompleksitet, forbedrer læsehastigheder, mens de påvirker datamodifikationsydelsen negativt. Jeg har vist, at du skal være ekstra forsigtig, når du sammenligner for ulighed i SELECT sætninger, fordi SQLite ikke kan bruge indekser til sådanne slags sammenligninger. Jeg anbefaler generelt at bruge forespørgselsplanlæggeren der forklarer, hvad der sker internt for hver SQL-forespørgsel. Når du justerer noget, så mål virkningen!


  1. Introduktion til PL/SQL-pakker i Oracle-databasen

  2. SQL Server-transaktionsloggen, del 3:Grundlæggende logføring

  3. Sådan overvåges HAProxy-metrics med ClusterControl

  4. 8 funktioner til at returnere dagen fra en dato i MariaDB