Things To Avoid, Episode 1: INSERT IGNORE

Legendaarinen koodi iskee takaisin

Luottaa dokumentoimattomiin kieliominaisuuksiin on melko riskialtista. Ja kun se sekoitetaan INSERT IGNOREen, asiat menevät todella huonosti.

Yksi käyttöjärjestelmän päivityksen aikana vuoden 2016 alussa Perl päivitettiin 5.14:stä 5.18:aan. Valitettavasti hashien käsittely muuttui, avainten järjestystä ei enää ylläpidetty aivan tietyssä skenaariossa ja koodi hajosi. Olet oikeassa, Perl ei koskaan luvannut järjestystä, mutta koodimme luotti joihinkin toteutuksen erityispiirteisiin.

Ote Perlin muutospäiväkirjasta v5.18:

Esimerkiksi kaksi erillistä hash-muuttujaa, joilla on identtiset avaimet ja arvot, voivat nyt antaa sisältönsä eri järjestyksessä siellä, missä se aiemmin oli identtinen.

Miksi se oli ongelma? Koodi valmisteli luetteloa tietokantaan lisättävistä hash-muuttujista. Sitten se käytti ensimmäistä kohdetta valmistellakseen luettelon sarakkeiden nimistä, jotka välitetään seuraaviin INSERT-kyselyihin. Jokainen lähetetty INSERT-kysely käytti kuitenkin eri hasheja valmistellessaan luetteloa lisättävistä arvoista. Tämä johti seuraavaan:

INSERT IGNORE INTO foo (id, date) VALUES (1, ’2006-10-11`), (’2007-12-09’, 2), …

Periaatteessa sarakkeiden nimien ja vastaavien arvojen järjestystä ei noudatettu. MySQL tietysti normaalisti antaa virheen, kun päivämäärää yritetään lisätä kokonaislukusarakkeeseen. Mutta muistathan lainauksen MySQL:n dokumentaatiosta? Näitä virheitä ei nosteta, kun käytetään INSERT IGNOREa ja tapahtuu hiljainen datan muuntaminen:

Data johdonmukaisesti epäjohdonmukaista

Skripti toimi hyvin Perl-päivityksen jälkeen (ainakin sen stderr oli hiljainen), mutta muutaman päivän kuluttua saimme vikailmoituksen, jonka mukaan jotain on vialla sisäisissä työkaluissamme, jotka käyttävät Perl-käyttöisiä taulukoita. Raportista päätellen jokin oli aika epäilyttävää. Ja huolemme todistettiin nopealla SELECT-kyselyllä:

Data inconsistency, powered by INSERT IGNORE

Mitäs tässä onkaan. Aikaleima ja kokonaislukuarvot muunnettu merkkijonoksi ja syötetty käyttäjänimeksi, vuosiluvut tallennettu kokonaislukusarakkeisiin (onko 2016 muokkausten määrä vai viimeisimmän muokkauksen vuosi). Datan epäjohdonmukaisuus parhaimmillaan.

Ei sinun tarvitse olla samaa mieltä, mutta minulle mikään data ei ole parempaa kuin yllä olevien rivien kaltainen ”data”.

Haitan kohteena oleva taulukko painaa yli 75 GiB ja tallentaa 460 mm riviä. Voimme luoda ne uudelleen, mutta se on pitkä prosessi. Skripti on käynnissä tätä juttua lukiessasi. No, se on ollut käynnissä jo viisi viikkoa… Kaikki kiitos IGNORE:n yhdessä ainoassa kyselyssä.

Oppien oppi

  • INSERT IGNORE on hiljainen peto, joka vain odottaa virhettäsi muuttaakseen datan merkityksettömäksi arvojen joukoksi.
  • Älä koskaan jätä virheitä huomiotta. Tee niistä äänekkäitä. Fail early.
  • Luottaa dokumentoimattomiin kielen ominaisuuksiin (Perl ja hash-avainten järjestys on vain yksi lukuisista esimerkeistä) on riskialtista peliä.

Sinua on varoitettu. Tarkista nyt koodisi tai ngrep-liikenteesi INSERT IGNORE -kyselyjen varalta.

Vastaa

Sähköpostiosoitettasi ei julkaista.