Перформанси на базата на податоци: од реактивни поправки до проактивно инженерство
Повеќето инциденти со бази на податоци не започнуваат како проблеми со базата на податоци. Тие започнуваат како разумен апликациски код што се соочува со малку поголем сообраќај, малку поголема табела или една нова функционалност што менува шема на пристап. Потоа расте латентноста, врските чекаат во ред, контролната табла се вцрвува и тимот почнува да бара индекс што недостига.
Додавањето на тој индекс можеби е правилниот непосреден одговор. Но само реактивните поправки создаваат кревок систем: секое ново оптоварување станува итен случај што чека да се достигне следниот праг. Проактивното инженерство на бази на податоци ги третира перформансите како дизајнерско својство, мерено и заштитувано во текот на целиот животен век на апликацијата.
Почнете од барањето, а не од пребарувањето
Бавна SQL-наредба е важна поради тоа што му прави на работниот тек насочен кон корисникот или на оперативниот работен тек. Пред оптимизација, дефинирајте ја патеката на барањето: која крајна точка, задача или екран е бавен; кое време на одговор е прифатливо; колку често се извршува; и колку податоци мора да врати.
Ова спречува честа грешка: подобрување на изолирано пребарување што не е вистинското тесно грло. Една API крајна точка може да изврши неколку брзи пребарувања, да серијализира огромен граф на објекти, да повика друга услуга и дури потоа да истече времето. Обратно, едно пребарување може да биде прифатливо за административен извоз, но катастрофално за често повикувана крајна точка.
Инструментирајте ја границата меѓу апликацијата и базата на податоци. Запишувајте траење, исход на грешка, број на редови каде што е корисно и доволно контекст за барањето за да групирате слична работа. Избегнувајте да запишувате чувствителни вредности само поради практичност. Целта е да се идентификуваат обрасци, а не да се создаде втора копија од продукциските податоци во логовите.
Направете ја формата на пребарувањето видлива
Работата на перформансите станува многу полесна кога SQL е видлив како SQL. ORM може да ја подобри продуктивноста, но не го отстранува однесувањето на базата на податоци. Прегледувајте ги генерираните наредби за важните патеки, особено по промена на релации, филтри, пагинација или серијализација.
Класичен пример е шемата на пребарување N+1: вчитувате листа, па потоа преземате поврзани податоци еднаш за секој ред. Често изгледа безопасно во локален развој бидејќи листата е мала. При реална употреба, едно барање претвора во десетици или стотици повратни патувања.
$orders = $repository->findRecentOrders();
foreach ($orders as $order) {
$customerName = $order->getCustomer()->getName();
}
Дали ова издава дополнителни пребарувања зависи од конфигурацијата на ORM, токму затоа кодот заслужува внимателна проверка. За крајна точка што враќа листа, намерно преземете ја релацијата потребна за одговорот или користете наменско пребарување за читање што ги избира само потребните полиња. Не решавајте секој проблем N+1 со нетрпеливо вчитување на цел граф на објекти; тоа може да замени многу мали пребарувања со еден голем, скап резултат.
Читајте ги плановите за извршување како повратна информација за дизајнот
Кога пребарувањето е значително бавно, проверете го неговиот план за извршување пред да нагаѓате. Планот може да открие целосни скенирања, скапи сортирања, спојувања извршени во неочекуван редослед или проценки што остро се разликуваат од реалноста. Точните команди и форматот на планот се разликуваат според базата на податоци, затоа користете ја документираната explain-функционалност на базата и толкувајте ја заедно со вистинските параметри и големините на табелите.
Индексот не е декоративна оптимизација. Тој поддржува одредена шема на пристап. Композитниот индекс треба да одразува како пребарувањето филтрира, спојува и подредува податоци. На пример, крајна точка што доследно ги избира неодамнешните настани на еден закупец има различни потреби од пребарување меѓу закупци по тип на настан. Додавањето поединечни индекси на секоја референцирана колона може да ја зголеми цената на запишувањето и сепак да не му помогне на комбинираното пребарување.
Дизајнирајте API-и што не наметнуваат скапи читања
Перформансите на базата на податоци често се одлучуваат на нивото на API-договорот. Крајна точка што ветува „сите записи“ на крајот станува продукциска опасност. Пагинацијата, ограничените големини на резултатите, експлицитното сортирање и внимателно избраните филтри не се само детали на интерфејсот; тие се механизми за намалување на оптоварувањето.
Пагинацијата со отстапување е едноставна и може да биде сосема соодветна за умерени, стабилни множества резултати. За големи или често променливи колекции, пагинацијата базирана на курсор може да избегне постепено скенирање и отфрлање на претходните редови. Таа исто така бара стабилно подредување и курсор што правилно го претставува тоа подредување. Курсор заснован само на временска ознака што не е единствена, на пример, ризикува дупликати или изоставувања кога неколку редови ја делат истата вредност.
Бидете подеднакво внимателни со флексибилното филтрирање. Широк интерфејс за пребарување може да создаде комбинации за кои ниту еден индекс не служи добро. Дефинирајте ги поддржаните филтри, валидирајте ги нивните опсези и одлучете кои сортирања се навистина неопходни. Ако на корисниците им е потребно аналитичко истражување, трансакцискиот API можеби не е вистинската апстракција за секое прашање.
Заштитете го базенот на врски и патеката на запишување
Исцрпувањето на врските може да направи здрава база на податоци да изгледа расипано. Секоја врска троши ресурси, а голем базен на страната на апликацијата не создава поголем капацитет на базата. Поставете конзервативни ограничувања, повторно користете ги врските соодветно и осигурете се работниците да не држат трансакции отворени додека вршат далечински повици, работа со датотеки или бавна обработка во апликацијата.
Трансакциите треба да бидат онолку мали колку што дозволува исправноста. Започнете ги блиску до запишувањето, извршете ги потребните читања и запишувања и веднаш потврдете или поништете ги. Долгите трансакции можат да задржат заклучувања или да ја одложат работата за чистење, зависно од механизмот на базата на податоци и нивото на изолација.
За PHP апликации, ова често значи внимателно постапување со животниот циклус на барањето. Барање што отвора трансакција, испраќа HTTP-барање до друга услуга и чека одговор го поврзува спорот околу базата на податоци со варијабилноста на мрежата. Зачувајте ја локалната промена, потврдете ја и користете експлицитен асинхрон работен тек кога деловниот процес го дозволува тоа.
Користете кеширање и асинхрона работа намерно
Кеширањето е вредно кога податоците можат да бидат малку застарени, правилата за поништување се разбрани и кешот навистина отстранува значајна работа на базата на податоци. Помалку е корисно како рефлексивен слој поставен пред неефикасно пребарување. Прво утврдете што е скапо и зошто; потоа изберете клуч за кешот, политика на истекување и стратегија за поништување што одговараат на сопственоста на податоците и потребите за свежина.
Исто така, преместете ја неинтерактивната работа надвор од патеката на барањето кога е можно: испраќањето известувања, генерирањето извештаи, повторното пресметување агрегати и обработката на увози се чести кандидати. Редицата не ја прави работата бесплатна. Таа менува кога и како се извршува, па на работниците и понатаму им се потребни идемпотентност, ограничувања за повторни обиди, видливост на неуспесите и шема на пристап до базата на податоци што останува безбедна при конкурентност.
Вградете ги перформансите во испораката
Проактивното инженерство е рутина, а не еднократна сесија за подесување. Додајте преглед на пребарувања во pull request-ите што менуваат патеки со голем сообраќај. Тестирајте ги миграциите во однос на реалистични карактеристики на табелите. Воведувајте промени во шемата со внимание на однесувањето на заклучувањата и компатибилноста при распоредувањето. Распоредувањето на апликацијата треба да го толерира периодот кога стариот и новиот код коегзистираат со шема што се развива.
Одржувајте краток буџет за перформанси за критичните операции: очекуван број на пребарувања, големина на одговорот, прифатлива латентност и која било позната граница на скалирање. Буџетот не мора да има лажна прецизност. Неговата цел е регресиите да бидат предмет на разговор пред да станат инциденти.
- Мерете: идентификувајте бавни патеки на барања и скапи шеми на пребарувања.
- Објаснете: проверете ги плановите пред да изберете индекси или преработки.
- Ограничете: ограничете ги множествата резултати, трансакциите, повторните обиди и работата во заднина.
- Потврдете: набљудувајте го продукциското однесување по секоја значајна промена.
Најдобрата оптимизација на базата на податоци често не е паметен SQL-трик. Таа е јасна граница на производот, помал одговор, подобра шема на пристап или работен тек преместен надвор од критичната патека. Кога тимовите ги носат тие одлуки рано и постојано ги потврдуваат, перформансите на базата на податоци престануваат да бидат повторлива спасувачка мисија и стануваат дел од сигурниот дизајн на задниот дел.