Slow Database in your PHP stack? Don't blame the DBA!

Post on 07-Apr-2017

258 views 2 download

transcript

SlowdatabaseinyourPHPstack?Don’tblametheDBA!

harald.zeitlhofer@dynatrace.com@HZeitlhofer

Lettheblamegamestart!

WebServer ApplicationServer Database

DEV Team DBA Team

Blame the database for all performance issues

Blame the SW/HW or system administrators

Network?

function roomReservationReport($room)

{

$reservations = loadDataForRoom($room->id);

return generateReport($room, $reservations);

}

SlowReport

function roomReservationReport($room)

{

$tstart = microtime(true);

$reservations = loadDataForRoom($room->id);

$dataLoadTime = microtime(true) - $tstart;

return generateReport($room, $reservations);

}

DEVteamaddlogoutput

45sDEVteamresult

<1msDBAteamlooksatDBstatsperquery

ExcessiveSQL:24889!CallstoDatabase

DatabaseHeavy:66.51%(40.27s)

TimeSpentinSQLExecs

Server/Infrastructure

DBQueries

Applicationdesign

DBDesignDatabase

Performancehotspots

DatabasePerformanceHotspots

Application Design Database Infrastructure

http://apmblog.dynatrace.com/2015/06/25/when-old-jira-tickets-killed-our-productivityuser-experience/

Toomanydatabasequeries

Exercise:createlistofcourses

Createlistofcourses$schools = new SchoolEntities();

foreach ($schools as $school) {

foreach ($school->departments as $department) {

foreach ($department->courses as $course) {

echo $department->name . ": " . $course->title;

}

}

} • 10schools• 20departmentsperschool• 50cursesperdepartment

N+1problem• 10schools• 20departmentsperschool• 50cursesperdepartment

=>10x20x50=10001singledatabasestatements!!!

UseaJOINquery$rows = $db->query ("

select department.name as department, course.title as course

from school

join department on school_id = school.id

join course on department_id = department.id

");

foreach ($rows as $row) {

echo $row->department . ": " . $row->course;

}

=>ONEdatabasestatement!!!

Retrievingtoomanyrecords

Retrievingtoomanyrecords$schools = new SchoolEntities();

foreach ($schools->departments as $department) {

foreach ($department->courses as $course) {

if ($course->category == "SQL" &&

$course->level == "expert") {

echo $department->name . ": " . $course->title);

}

}

}

=>3records,still10001queries

UseaJOINquery$rows = $db->query ("

select department.name as department, course.title as course

from school

join department on school_id = school.id

join course on department_id = department.id

where course.category = 'SQL' and course.level = 'expert'

");

foreach ($rows as $row) {

echo $department . ": " . $course);

}

=>ONEdatabasestatement!!!

Caching

MySQLQueryCache• Cachesqueryresultsinmemory

OracleSQLCache• OracleSQLcachestorestheexecutionplanforaSQLstatement• Evendifferentplansastoredfordifferentbindvariablevalues• Noparsingrequired• ParsingisthemostCPUconsumingprocess• CachekeyisfullSQLquerytext

select * from country where code = 'AT'

!=

SELECT * from country where code = 'AT'

OracleSQLCache<?php

$db = new PDO('oci:dbname=sid', 'username', 'password');

$data = Array();

$data[] = $db->query("select * from country where code = 'AT'");

$data[] = $db->query("select * from country where code = 'AU'");

$data[] = $db->query("select * from country where code = 'NZ'");

$data[] = $db->query("select * from country where code = 'ES'");

?>

?>

OracleSQLCache<?php

$db = new PDO('oci:dbname=sid', 'username', 'password');

$data = Array();

$ps = $db->prepare("select * from country where code = :code");

$data[] = $ps->exec(array("code" => "AT"));

$data[] = $ps->exec(array("code" => "AU"));

$data[] = $ps->exec(array("code" => "NZ"));

$data[] = $ps->exec(array("code" => "ES"));

?>

DatabaseHealth

Indexes

Indexesaredatastructuresforreferencingasearchvalue(inanindexedcolumn)to(a)row(s)inthetargettable

Indexesareusedtofindrecordsinatablewhenawhereclauseisused

Indexesarealsousedtojointablesinaquery,wheremultipletablesareused

UsefulcommandsinMySQL

explain select ...

show indexes for table_name

I'madeveloperforbusinesslogic!Idon'thavetounderstandwhatthe

databasedoesandIdonotcareatall!

I'madeveloperforbusinesslogic!MycodecanbemuchmoreefficientifIunderstandwhatthedatabasedoesand

howitworks!

Makedevelopersself-sufficient

Makedevelopersself-sufficient

Makedevelopersself-sufficient

SlowSingleSQLquery–tuning/indexingmightberequired

Makedevelopersself-sufficient

Takeaways• Muchtimespentindatabasedoesnotnecessarilymeandatabaseisslow!• Performancehotspots

• ToomanySQLstatements• Missingcaching• Badquerydesign• Index(mis)usage• Undersizeddatabaseserver

• Letdevelopersknowwhat’shappeninginthedatabase• TheDBAisourfriend!

HaraldZeitlhoferPerformanceAdvocate@HZeitlhoferharald.zeitlhofer@dynatrace.comhttp://blog.dynatrace.com

DynatraceFreeTrialFreePersonalLicensehttp://bit.ly/monitoring-2016