Teie aruanne lõpeb andmebaasi hostis umbes sekundiga ja VPN-i kaudu neljaga, ning arv, mille psql trükib, osutab otse andmebaasile. See arv on kliendipoolne stopper, mitte serveri mõõtmine. See hõlmab lause teekonda välja, ootust vastusele ja ridu teekonnal tagasi. Nende kolme eraldamine on ainus viis teada, millist poolt häälestada.

Mida psql-i taimer tegelikult mõõdab

\timing on käivitab stopperi vahetult enne, kui klient kirjutab lause soklisse, ja peatab selle, kui selle tulemuse viimane rida on loetud. Serveri enda täitmine asub kuskil selle akna sees, nagu ka iga millisekund, mille paketid tunnelis veedavad. Miski väljundis ei eralda neid. EXPLAIN trükib samuti arvu, kuid selle toodab server ja see jätab välja kliendi ootuse. Kaks arvu, kaks erinevat küsimust.

Alustage üks sessioon, jätke ajamõõtmine sisse ja käivitage lause, mis teid huvitab, selle seest. Sessiooni korduskasutamine hoiab ühenduse kulud esimesest mõõtmisest väljas.

psql "host=db.internal port=5432 dbname=appdb user=app" \
  -c "\timing on" \
  -c "select count(*) from orders where created_at > now() - interval '1 day';"

Arv sisaldab endiselt tulemuse ülekannet, mis on siin soovitud. See ei sisalda enam ühenduse ja autentimise vahetust, mille uus kutse lisaks.

Võrrelge ühte lauset kolmel teel

Käivitage sama lause Unix-sokli, LAN-aadressi ja VPN-hostinime kaudu ning võrrelge kolme. Kui aeglane on ainult viimane, ei ole päring muutuja.

Iga kutse loob esmalt ühenduse ja mõõdab lauset alles seejärel, nii et ühenduse kulu jääb arvust välja, samal ajal kui ülekanne jääb sisse. Hoidke WHERE-klausel, ridade arv ja kliendi masin samad, muidu võrdlete töökoormusi, mitte teid.

psql -h /var/run/postgresql -U app -d appdb -c "\timing on" -c "select count(*) from orders;"
psql -h 10.40.0.12 -U app -d appdb -c "\timing on" -c "select count(*) from orders;"
psql -h db.vpn.internal -U app -d appdb -c "\timing on" -c "select count(*) from orders;"

LAN-is on erinevus tavaliselt piisavalt väike, et seda eirata; VPN-i kaudu sageli mitte. Kolme tulemuse sorteerimine ütleb teile seejärel, millist ootust rünnata.

Aeglane kohalik sokkel tähendab serveri tööd või planeerimist. Aeglane LAN-i tulemus tähendab päringut või mahtu, mida see liigutab. Ainult aeglane VPN-i tulemus tähendab latentsust, MTU-d või saadaolevat ribalaiust teel, ja ükski indeksi muudatus ei paranda seda.

Hankige serveri enda täitmisaeg

Server saab teatada, kui palju aega see kulutas, ja just seda arvu tuleb kliendi omaga kõrvutada. EXPLAIN koos ANALYZE-ga käivitab lause ja trükib planeerimis- ja täitmisaja plaani sees, samas kui BUFFERS lisab vahemälu käitumise, mis sageli selgitab sooja käivitust külma vastu. Ärge suunake seda kirjutavatele lausetele, kui te ei kavatse kirjutada. Ainult lugemiseks mõeldud koopial on see kõige turvalisem koht alustamiseks, ja psql-i viide dokumenteerib taimeri kliendipoolse ulatuse.

Lausete puhul, mida rakendus juba käivitab, koondab pg_stat_statements serveripoolse täitmise ilma midagi uuesti käivitamata. Read on normaliseeritud päringu kohta, nii et üks kirje võib katta mitu kutsekoha.

select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;

Veerunimed erinevad väljaande järgi: PostgreSQL 13 ja uuemad näitavad mean_exec_time, vanemad versioonid nimetavad seda mean_time, seega kontrollige \d pg_stat_statements abil, kui see päring annab vea. Need väärtused jätavad välja planeerimise ja jätavad välja teekonna teie kliendini. Just see väljajätmine teeb need võrdlemiseks kasulikuks.

Loendage edasi-tagasi käike, mitte ainult millisekundeid

Kahesajast väikesest sõltuvast lausest koosnev aruanne korrutab iga latentsuse, mille tee lisab, kahesajaga. Üks lause, mis tagastab miljon rida, maksab selle latentsuse üks kord ja maksab seejärel pikka aega ribalaiust. Mõlemad näevad kliendi taimeris ühesugused välja ja vajavad vastupidiseid parandusi.

Mõõtke lausete arvu, selle asemel et seda hinnata. Lugege kogusumma, käivitage aruanne üks kord, seejärel lugege uuesti ja lahutage.

select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;

Kui delta on suur ja iga lause on serveris odav, on pakkimine parandus, mis ära tasub. Kombineerige sõltuvad päringud, kasutage ühte hulgapõhist lauset või juhtige tsüklit kursorist. Interaktiivses psql-is, \set FETCH_COUNT 1000 paneb suure tulemuse saabuma pakkidena ja muudab ülekande ning kliendi mälu käitumist. See ei vähenda serveri tööd, seega ei päästa aeglast päringut.

Kontrollige tunnelit kordussaatmiste ja MTU-tõrgete suhtes

Kui väikesed laused on kiired ja suured tulemused jäävad poolel teel seisma, on päring tavaliselt korras ja tee mitte. Tunnel, mille MTU on aluslingist madalam, koos blokeeritud ICMP-ga, tekitab täpselt sellise mustri: esimesed paketid saabuvad, suured kaovad ja ülekanne ripub, kuni see uuesti proovib. Kliendipoolsed kordussaatmiste loendurid näitavad seda.

Jälgige soklit ja tuuma loendureid, kui käib meelega aeglane ülekanne. Kordussaatmiste summad on kumulatiivsed, seega märkige need enne ja pärast, selle asemel et lugeda üht proovi.

ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12

Ülekande ajal kasvavad kordussaatmised koos pingiga, mis õnnestub 1400 baidil, kuid ebaõnnestub 1472 juures, osutavad pigem MTU probleemile kui andmebaasi probleemile. Tunneliliidese MTU langetamine või MSS-i kinnipidamine lüüs on tavaline parandus ja samad kolm käsku kinnitavad seda hiljem. Kui kordussaatmised jäävad tasaseks, samal ajal kui ülekanne on endiselt aeglane, vaadake tunnelile lubatud ribalaiust, mitte kadu.

Lühike jada katab järgmise aeglase aruande: võrrelge ühte lauset kohapeal, LAN-is ja VPN-i kaudu; lugege serveri täitmist EXPLAIN-ist või pg_stat_statements-ist; loendage kutsed enne ja pärast ühte käivitust; ja jälgige kordussaatmisi, kui suur tulemus liigub. Iga samm välistab tee ühe poole. Ükski neist ei nõua oletamist, millist komponenti taaskäivitada.

Seotud artiklid