PHP, MySQL, FastCGI - best way to handle many queries - php

I am trying to figure out the best way to handle db communication in PHP, MySQL setup through FastCGI and usig PHP-FPM; This is for a relatively heavy use site where there is anywhere from 100 to 1,000 SQL queries a second so I would like to make things as efficient as possible.
I am rewriting parts of the website and in the new code I am utilizing PDO and have the below class to handle DB queries and connections by doing database::insertEmployee($name, $SIN, $DOB, $position). My concern is that with every query a new PDO connection is established. Should I be trying to set up a persistent connection???
class database
{
protected $dbh;
protected static $instance;
private function __construct()
{
try {
// building data source name from config
$dsn = 'mysql:=' . DB_Config::read('db.host') .
';dbname=' . DB_Config::read('db.name');
$user = DB_Config::read('db.user');
$password = DB_Config::read('db.password');
$this->dbh = new PDO($dsn, $user, $password);
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
//#TODO-KP: log and alert
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}
public static function getInstance()
{
if (!isset(self::$instance)) {
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
public static function insertEmployee($name, $position, $SIN, $DOB)
{
$dbi = self::getInstance();
try {
$sthEmployee = $dbi->dbh->prepare('INSERT INTO employees SET
name = :name
, position = :position
, SIN = :SIN
, DOB = :DOB'
);
$sthEmployee->bindParam(':name', $name);
$sthEmployee->bindParam(':position', $position);
$sthEmployee->bindParam(':SIN', $SIN);
$sthEmployee->bindParam(':DOB', date('Y-m-d G:i:s', $DOB));
return $sthEmployee->execute();
} catch (PDOException $e) {
//#FIXME-KP: log and alert
print "Error!: " . $e->getMessage() . "-- name [$name]";
return '';
}
}
}
Any thoughts on most efficient approach would be very, very appreciated!
Kathryn.

My concern is that with every query a new PDO connection is established.
Well, verify your concern, because I would say this is likely not the case.
For performance reasons, take care you're using the mysql native driver under the hood as this allows extended metrics of the interaction from PHP with the database.
Also get a professional support plan from Oracle for Mysql, they have nice monitoring tools and very good support that should help you to get your database and PHP code ready for the traffic to handle.

Related

Different ways to create a Connect Function in a Class? [duplicate]

This question already has answers here:
How to properly set up a PDO connection
(5 answers)
Closed 9 years ago.
Okay so I have some what of a dumb question, I've seen tuts and different things on making a CMS and I want to make an oop CMS, and I was wondering if someone could explain to me what the difference was between using one of the two examples?
Ex 1 -
class myClass
{
var $username;
var $password;
public function connect()
{
try {
$pdo = new PDO('mysql:host=localhost;dbname=dbname', $this->username,
$this->password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
} catch(PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
}
}
// Then to call that function
$obj = new myClass();
$obj->username = "root";
$obj->password = "password";
$pdo = $obj->connect();
// Then run my query down here
Ex 2 -
class database
{
protected $connection = null;
//make a connection
public function __construct($hostname,$dbname,$username,$password)
{
try {
//MySQL with PDO_MYSQL
$this->connection = new PDO("mysql:host=$hostname;dbname=$dbname",
$username, $password);
$this->connection->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$this->connection = null;
die($e->getMessage());
}
}
}
Or I've even seen people use a __construct then a seperate connect function
So what exactly is the difference? Is there a performance benefit by doing it a particular way? Or is there a way that is more correct than the other or are all three if these incorrect ways of doing it? I haven't found a reliable source to find an answer.
For the most cases 3rd example is the best:
In fact, PDO is already a database class. So, if you have no particular reason to create another on top of it, PDO itelf is just a perfect:
$pdo = new PDO('mysql:host=localhost;dbname=dbname', $username,$password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
is all you actually need.
There are no noticeable performance differences between the two.
The second way is preferred by a lot of people because a database object would be kind of useless if it didn't try to connect to a database. Because attempting to connect to a database is so vital to the object's worth / existence, it makes sense to send in the connection details via the constructor so that it can attempt a connection as soon as it is being instantiated. Thus, changing:
$obj = new myClass();
$obj->username = "root";
$obj->password = "password";
$pdo = $obj->connect();
to
$obj = new myClass('localhost', 'root', 'mypassword');

PDO Active Record prepared statement in separate classes

I need to do continuous parsing of several external stomp data streams, inserts of relevant fields into a MySql db, and regular queries from the db. All of this is in a protected environment - ie I'm not dealing with web forms or user inputs
Because I'm implementing a range of inserts into + queries from different tables, I've decided to set up a PDO active record model - following the advice of Nicholas Huot and many SO contributors.
I've got a simple repeated insert working OK, but after several days of grief can't get a prepared insert to fly. I want to use prepared inserts given there are going to be a lot of these (ie for performance).
Relevant bits of the code are :
=========
Database class :
private function __construct()
{
try {
// Some extra bad whitespace removed around =
$this->dbo = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPSW, $options);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}
public static function getInstance()
{
if(!self::$instance)
{
self::$instance = new self();
}
return self::$instance;
}
public function prepQuery($sql) // prepared statements
{
try {
$dbo = database::getInstance();
$stmt = new PDOStatement();
$dbo->stmt = $this->$dbo->prepare($sql);
var_dump($dbo);
}
catch (PDOException $e) {
echo "PDO prepare failed : ".$e->getMessage();
}
}
public function execQuery($sql) // nb uses PDO execute
{
try {
$this->results = $this->dbo->execute($sql);
}
catch (PDOException $e) {
echo "PDO prepared Execute failed : \n";
var_dump(PDOException);
}
}
=========
Table class :
function storeprep() // prepares write to db. NB prep returns PDOstatement
{
$dbo = database::getInstance();
$sql = $this->buildQuery('storeprep');
$dbo->prepQuery($sql);
return $sql;
}
function storexecute($paramstring) // finalises write to db :
{
echo "\nExecuting with string : " . $paramstring . "\n";
$dbo = database::getInstance(); // Second getInstance needed ?
$dbo->execQuery(array($paramstring));
}
//table class also includes buildQuery function which returns $sql string - tested ok
=======
Controller :
$dbo = database::getInstance();
$movements = new trainmovts();
$stmt = $movements->storeprep(); // set up prepared query
After these initial steps, the Controller runs through a continuous loop, selects the fields needed for storage into a parameter array $exec, then calls $movements->storexecute($exec);
My immediate problem is that I get the error message "Catchable fatal error: Object of class database could not be converted to string " at the Database prepquery function (which is called by the Table storeprep fn)
Can anyone advise on this immediate prob, whether the subsequent repeated executes should work in this way, and more widely should I change anything with the structure ?
I think your problem in this line $dbo->stmt = $this->$dbo->prepare($sql);, php want to translate $dbo to string and call function with this name from this. Actually you need to use $this->dbo.
And actually your functions not static, so i think you don't need to call getInstance each time, you can use $this.

PHP designing OO database connection

So, I'm working on a project that requires a database connection. I've chosen to use PDO for its versatility and need to figure out how to set up the connection. Currently I'm going for something like this:
class Database {
private static $db;
static function initDB() {
if(!is_object(self::$db) || get_class(self::$db) != 'PDO') {
include('core/db.php');
try {
$db = new PDO($database, $username, $password);
} catch(PDOException $e) {
print("<br />Could not establish database connection. Error message: ".$e->getMessage()."<br />");
die();
}
}
//Try the transaction
/*
if($transaction = $db::query(PDO::quote($value)))
$db::query(PDO::quote("INSERT INTO log VALUES ('".Authorization::$user."','".PDO::quote($value)."', 'Success')"));
else
$db::query(PDO::quote("INSERT INTO log VALUES ('".Authorization::$user."','".PDO::quote($value)."', 'Failure')"));*/
}
}
So, this pretty much reveals one of the concepts I don't really know: singletons and static classes/objects. Any way to set up a database connection using OO best practices that initializes with the script via some kind of __construct method?
A database connection should not be either static or a singleton. This merely introduces another form of global state, which is bad for unit-testing and does hide obvious dependencies.
The right way here would be is to inject an instance of PDO into the classes that need it. You adhere the Single-Responsibility Principle and Dependency Injection.
Note, you should never log errors and do include() inside PDOAdapter constructor because its masked violation of the Single-Responsibility Principle
So, this would look like this:
final class PDO_Provider extends PDO
{
/**
* Constructor. Inits PDO
*
* #param array $params
* #return void
*/
public function __construct(array $params)
{
try {
extract($params);
parent::__construct(sprintf('mysql: host=%s; dbname=%s', $host, $database), $user, $password);
$this->setAttribute(parent::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES UTF8');
$this->setAttribute(parent::ATTR_ERRMODE, parent::ERRMODE_EXCEPTION);
$this->setAttribute(parent::ATTR_EMULATE_PREPARES, false);
$this->setAttribute(parent::ATTR_DEFAULT_FETCH_MODE, parent::FETCH_ASSOC);
} catch(PDOException $e) {
die($e->getMessage());
}
}
}
And you would use it like this,
<?php
$sql_config = array(
'host' => 'localhost',
'user' => 'root',
'password' => '',
'database' => '_DB_NAME_',
);
// <- Or you can include that, like
$sql_config = include(__DIR__ . '/core/db_params.php');
$pdoProvider = new PDO_Provider($sql_config);
$user = new User_Login($pdoProvider); // the point here is to inject an instance of $pdoProvider. User_Login is actually irrelevant
if you want to use a normal object instead of sigleton, try something like this:
class PDOConnector{
protected $connection;
function __construct($host, $user, $pass, $db_name)
{
//create database connection
try{
$this->connection = new PDO('mysql:host='.$this->host.';dbname='.$this->db_name.';charset=utf8', $this->user, $this->pass,array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(PDOException $ex) {
echo "An Error occured : ".$ex->getMessage();
}
}
}

Singleton with multiple databases

example app, having employee information and being accessed by different applications like payroll and pos. i have employee data in one database, payroll data and pos in separate databases each.
i have a database connection class like below, so everytime i want to get a connection to a db i just do $conn = Database::getInstance(db1).
works great, but is super slow basically. makes the app run really slow. Any tips on why that is so or better yet alternative ideas to do this?
any help will be greatly appreciated
<?php
class Database {
private $db;
static $db_type;
static $_instance;
private function __construct($db){
switch($db) {
case "db1":
try{
$this->db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD);
}
catch(PDOException $e){
print "Error!: " . $e->getMessage() . "<br />";
die();
}
break;
case "db2":
try{
$this->db = new PDO("mysql:host=" . DB_HOST_2 . ";dbname=" . DB_NAME_2, DB_USER_2, DB_PASSWORD_2);
}
catch(PDOException $e){
print "Error!: " . $e->getMessage() . "<br />";
die();
}
break;
}
self::$db_type = $db;
}
private function __clone(){}
static function getInstance($db_type){
if(!(self::$_instance) || $db != self::$db_type){
self::$_instance = new self($db_type);
}
return self::$_instance;
}
}
?>
With this design. If you change databases then it destroys the connection to the previous database.
Make separate objects for each connection then switch between the connection objects.
Also, this is not thread safe for the same reason. If multiple functions are hitting this as the same time, one can disconnect the other before its done loading.
You really should just create a new connection object for each function and not share it between functions or other objects.
Do not create new object constantly. What is happening is that everytime you request another database type, you are recreating it via the new keyword (although hard to confirm without seeing code that uses this).
$_instance is a static member, so you are constantly overwriting it when you change database type. so is $db_type for that matter
While this is overkill for what you are doing (why not just have two variables for each DB?), you could try something more like this:
<?php
class Database {
private $db;
static $db_types;
private function __construct($db){
switch($db) {
case "db1":
try{
$db_types[$db] = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASSWORD);
}
catch(PDOException $e){
print "Error!: " . $e->getMessage() . "<br />";
die();
}
break;
case "db2":
try{
$db_types[$db] = new PDO("mysql:host=" . DB_HOST_2 . ";dbname=" . DB_NAME_2, DB_USER_2, DB_PASSWORD_2);
}
catch(PDOException $e){
print "Error!: " . $e->getMessage() . "<br />";
die();
}
break;
}
}
private function __clone(){}
static function getInstance($db_type){
if(!inarray($db_types[$db_type]){
$db_types[$db_type] = new self($db_type);
}
return $db_types[$db_type];
}
}
?>
NOTE: syntax is likely off. Just wanted to demonstrate the pattern.
I dont see why that would be making things slow other than the fact that youre constantly switching conncections. The only thing i can suggest here is to allow multiple connections instead of switching them:
class Database {
protected static $connections;
protected $activeConnections = array();
protected static $instance;
protected function __construct() {
}
public static loadConnections(array $connections) {
self::$connections = $connections;
}
public function getConnection($name)
{
if(!isset($this->activeConnections[$name]) {
if(!isset(self::$connections[$name]) {
throw new Exception('Connection "' . $name . '" is not configured.');
}
$this->activeConnections[$name] = new PDO(
self::$connections[$name]['dsn'],
self::$connections[$name]['username'],
self::$connections[$name]['password']
);
}
return $this->activeConnections[$name];
}
}
// usage
Database::loadConnections(array(
'db1' => array(
'dsn' => "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME,
'user' => DB_USER,
'password' => DB_PASSWORD,
),
'db2' => array(
'dsn' => "mysql:host=" . DB_HOST2 . ";dbname=" . DB_NAME2,
'user' => DB_USER2,
'password' => DB_PASSWORD2,
)));
$conn1 = Database::getInstance()->getConnection('db1');
$conn2 = Database::getInstance()->getConnection('db2');
Using something like this you can actually manange several open connections at a time, and they are lazy loaded - meaning you dont actually instantiate a PDO connection until you ask for it with Database::getConnection Likewise you can inject additional DSN's and credentials in at anytime. Personally i would load thes form configuration right on to the class instead of hard coding them with constants int he class. then you could so something like:
// gives us an array
$config = Config::load('path/to/db/config.yml');
Database::loadConnections($config);
How about changing it to also use lazy load. You do not need to connect to the databases in the contractor. Only connect when the database is first required. That way, if the page only uses one of the connection, it does not need to wait for the other databases.
Check the value of DB_HOST and DB_HOST_2. Previously I've found MySQL extremely slow to connect using "127.0.0.1", but connecting instantly using "localhost".
It depends on how your server is setup, but just thought it might help.

Do I have this PDO Connection Class right?

I've been playing around with PDO for the last few days, I'm working on a small CMS system to teach myself OOP skills, but even though it's only a small CMS, I want it to be able to handle whatever the web can throw at it.
This is what I've come up with so far, I'm going to add connection pooling to the constructor to enable large amounts of concurrent connects on demand. I'm very new to this OOP stuff so I'm wanting a little advise and critism, no doubt I've done something terribly wrong here.
I took the top answer to Global or Singleton for database connection? as the base design, although I've added a private constructor as I want to use $this->dbConnectionInstance throughout the class for numerous helper functions to use.
Thanks very much for your time, I really will appreciate any advise you can give me,
-Drew
// Usage Example: $dbconn = dbManager::getConnection();
// $dbconn->query("SELECT * FROM accounts WHERE id=:id", "':id' => $id");
<?php
class dbManager {
private static $dbManagerInstance;
private $dbConnectionInstance;
private $stime;
private $etime;
public $timespent;
public $numqueries;
public $queries = array();
public static function getManager(){
if (!self::$dbManagerInstance){
self::$dbManagerInstance = new dbManager();
}
return self::$dbManagerInstance;
}
// Server details stored in definition file
private function __construct($db_server=DB_SERVER, $db_user=DB_USER, $db_pass=DB_PASS, $db_params=array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")) {
if(!$this->dbConnectionInstance)
{
try{
$this->dbConnectionInstance = new PDO($db_server, $db_user, $db_pass, $db_params);
$this->dbConnectionInstance->setAttribute(PDO::ATTR_PERSISTENT, PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$this->dbConnectionInstance = null;
die($e->getMessage());
}
}
return $this->dbConnectionInstance;
}
private function __destruct(){
$this->dbConnectionInstance = null;
}
private function query($sql, $params = array()) {
$this->queries[] = $sql;
$this->numqueries++;
$this->sTime = microtime();
$stmt = $this->dbConnectionInstance->prepare($sql);
$stmt->execute($params);
$this->eTime = microtime();
$this->timespent += round($this->eTime - $this->sTime, 4);
return $stmt;
}
}
?>
Thank you both for your suggestions, I've now added the rollback and commit into my exception handling, I'm just researching the use of buffered queries, I'm not entirely sure what ths will give me?
Looks good, I would add rollback functionality, along with the buffered query/errorInfo suggestions (If you're using a RDBMS that supports transactions):
try {
$this->dbConnectionInstance->beginTransaction();
$stmt = $this->dbConnectionInstance->prepare($sql);
$stmt->execute($params);
$this->dbConnectionInstance->commit();
}catch(PDOException $e){
$this->dbConnectionInstance->rollback();
}
commit() , beginTransaction()
EDIT: added links below for more info on buffered queries:
mysql performance blog
pdo mysql buffered query support
stack overflow: pdo buffered query problem
The code you have dosent look too bad. however if i could make a couple small changes (mainly error handling).
both the prepare and execute statements will return false on error. and you can access the error from $this->dbConnectionInstance->errorInfo() in your example above.
also if you plan on using any large queries I suggest using a buffered query: PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
looks like a good start. Good luck on your CMS.

Categories