Out of curiosity, which of these segments of code would have the faster performance time when implemented on a mass scale?
Let's say we have a table members and we want to fetch their photos.
Method 1
$members = $db->query('SELECT * FROM members ORDER BY id ASC');
foreach($members as $m)
$memberIDs[] = $m['id'];
$photos = $db->query('SELECT * FROM photos WHERE member IN'.join(',', $memberIDs).' ORDER BY id ASC');
foreach($photos as $p) {
// multi_arr_search(search_val, search_column, search_array) returns parent key in multi dimensional array
$memberArrayKey = multi_arr_search($p['member'], 'id', $members);
$members[$memberArrayKey]['photos'][] = $p;
}
OR
Method 2
$members = $db->query('SELECT * FROM members ORDER BY id ASC');
foreach($members as $k=>$m)
$members[$k]['photos'] = $db->query('SELECT * FROM photos WHERE member='.$m['id'].' ORDER BY id ASC');
Method 1 would result in fewer queries being ran, but requires more PHP work.
neither. You are using 15 years old deprecated methods.
If you want to go fast, you need PDO prepared statements.
#alberto is right. I am pretty sure, you can have one and only sql to perform this but here is a way you might want to consider in case off:
$showError = true;
define("SQLHOST", "127.0.0.1");
define("SQLUSER", "login");
define("SQLPASS", "password");
define("SQLSGBD", "database");
$conn = new PDO('mysql:host=' . SQLHOST . ';dbname=' . SQLSGBD . ';charset=UTF8', SQLUSER, SQLPASS);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql1 = 'SELECT * FROM members ORDER BY id ASC';
$stmt1 = $conn->prepare($sql1);
$sql2 = 'SELECT * FROM photos WHERE member IN ? ORDER BY id ASC';
$stmt2 = $conn->prepare($sql2);
try {
$stmt1->execute();
$members = $stmt1->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
if ($showError === true) {
var_dump("error query 1:" . __LINE__ . "-------" . __FUNCTION__ . "-------" . $e->getMessage());
exit;
}
}
if (count($members) !== 0) {
$memberIDs = array();
foreach ($members as $m) {
$memberIDs[] = $m['id'];
}
$memberlist = join(',', $memberIDs);
foreach ($members as $memberArrayKey => $result1) {
$stmt2->bindParam(1, $memberlist, PDO::PARAM_STR);
try {
$stmt2->execute();
$photos = $stmt2->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
if ($showError === true) {
var_dump("error query 2:" . __LINE__ . "-------" . __FUNCTION__ . "-------" . $e->getMessage());
exit;
}
}
if (count($photos) !== 0) {
$memberArrayKey = multi_arr_search($p['member'], 'id', $members);
$members[$memberArrayKey]['photos'][] = $p;
}
}
}
Well, hard truth: none is actually scalable. If you're working with large sets of data, PHP will need quite a bit of memory to perform all the operations to link users and photos and will do it in a much more inefficient way than the DB can.
You should have the tool you have that is best at doing these kind of things, which is your DB: the DB should join the users & photos and get you that set.. anything you do differently will mean reduced performance and scalability.
1- It depends on many factors how are you working with MySQL, if you connect and disconnect connection with the DB at each call.
2- MySQL Server is in the same PHP.
Ideally, connect 1 time mysql to retrieve information with a single Query. And in your case, you can solucuonar with a JOIN. Which it is best to disconnect as quickly as possible and continue with MySQL PHP.
Another recommendation is to not use " * " in the SELECT. Only puts the fields that you go to work. This eat fewer resources because only you use is requested. It is optimal in Memory, CPU, Data via LAN
Related
I am creating search option using php .I want to do search when user give multiple fields according to given fields i need fetch records from the database.to get clear idea about what i need to do below is the interface of the search option
when user click go in form submit i need to get user given filds and fetch record according to given search crieteria
so i have looked many options and i found below as efficient
$query = 'SELECT *
FROM user
WHERE 1 = 1 ';
if(!empty($serviceNumber) )
{
$query .= ' and serviceNumber = ? ';
$params[] = $serviceNumber;
}
if(!empty($name))
{
$query .= ' and userName = ? ';
$params[] = $name;
}
if(!empty($status))
{
$query .= ' and status = ? ';
$params[] =$status;
}
if(!empty($params))
{
$sth->execute($params);
$dbh->prepare($query);
$result= mysqli_query($dbcon,$sth);
if(!$result )
{
die('Could not get data: ' . mysqli_error());
}
}
else
{
echo 'Missing Values';
}
but i got $sth as undefined variable so is there efficient way or can i correct this error.if any one can help appreciated.
This code would work (even if you reverse the wrong order prepare an execute called in) only with PDO.
For mysqli you have to always bind your values explicitly, which is a distinct pain in the back. Luckily, since PHP version 5.6 there is an argument unpacking operator that helps:
$stmt = $db->prepare($query);
$types = str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
$res = $statement->get_result();
$data = $res->fetch_all();
however, if your PHP version doesn't meet this requirement or get_result() function is not supported, I would strongly suggest to forget about mysqli and turn to PDO. Which will make your code a lot simpler and - which is way more important - would work with any PHP version regardless:
$sth = $dbh->prepare($query);
$sth->execute($params);
$data = $sth->fetchAll();
Just started learning PHP, Angular and mySQL and am trying to retrieve just one field value from one single row. The same code below works for a query that returns multiples rows:
$qry = "SELECT ID FROM SharePoint001 ORDER BY DownloadedTimeStamp DESC LIMIT 1"; //returns a5f415a7-3d4f-11e5-b52f-b82a72d52c35
$data = array();
while($rows = mysql_fetch_array($qry))
{
$data[] = array("ID" => $rows['ID']);
}
print_r(json_encode($data[0]));
I highly recommend switching to the mysqli extension. It's a much better way of doing things and you will probably find it much easier.
Here's a simple mysqli solution for you:
$db = new mysqli('localhost','user','password','database');
$resource = $db->query('SELECT field FROM table WHERE 1');
$row = $resource->fetch_assoc();
echo "{$row['field']}";
$resource->free();
$db->close();
If you're grabbing more than one row, I do it like this:
$db = new mysqli('localhost','user','password','database');
$resource = $db->query('SELECT field FROM table WHERE 1');
while ( $row = $resource->fetch_assoc() ) {
echo "{$row['field']}";
}
$resource->free();
$db->close();
With Error Handling: If there is a fatal error the script will terminate with an error message.
// ini_set('display_errors',1); // Uncomment to show errors to the end user.
if ( $db->connect_errno ) die("Database Connection Failed: ".$db->connect_error);
$db = new mysqli('localhost','user','password','database');
$resource = $db->query('SELECT field FROM table WHERE 1');
if ( !$resource ) die('Database Error: '.$db->error);
while ( $row = $resource->fetch_assoc() ) {
echo "{$row['field']}";
}
$resource->free();
$db->close();
With try/catch exception handling: This lets you deal with any errors all in one place and possibly continue execution when something fails, if that's desired.
try {
if ( $db->connect_errno ) throw new Exception("Connection Failed: ".$db->connect_error);
$db = new mysqli('localhost','user','password','database');
$resource = $db->query('SELECT field FROM table WHERE 1');
if ( !$resource ) throw new Exception($db->error);
while ( $row = $resource->fetch_assoc() ) {
echo "{$row['field']}";
}
$resource->free();
$db->close();
} catch (Exception $e) {
echo "DB Exception: ",$e->getMessage(),"\n";
}
The MySQL extension is:
Officially deprecated (as of PHP 5.5. Will be removed in PHP 7.)
Lacks an object-oriented interface
Much slower than mysqli
Not under active development
Does not support:
Non-blocking, asynchronous queries
Transactions
Stored procedures
Multiple Statements
Prepared statements or parameterized queries
The "new" password authentication method (on by default in MySQL 5.6; required in 5.7+)
Since it is deprecated, using it makes your code less future proof. See the comparison of SQL extensions.
You have not executed the query, so you'll never get results.
First you have to prepare query and place it into a variable lets say $qry.
Then execute that query by using mysql_query() function and capture result into a variable lets say $result
Now you can iterate that $result with loop to fetch rows and cells (what you call fields).
Below is code I have corrected:
$qry = "SELECT ID FROM SharePoint001 ORDER BY DownloadedTimeStamp DESC LIMIT 1";
$result = mysql_query($qry); // You are missing this line
$data = array();
while($rows = mysql_fetch_array($result)) // You have to pass result into mysql_fetch_array not query string
{
$data[] = array("ID" => $rows['ID']);
}
print_r(json_encode($data[0]));
I made a search but I couldn't find anything fulfilling
Imagine the following:
<?php
$connection = new \PDO($dsn, $user, $pass);
$stmt1 = $connection->prepare("
SELECT
*
FROM
table
WHERE
a = :a
AND b = :b
AND c = :c
AND d = :d
AND search LIKE :search
");
$stmt1->bindValue(":a", $a);
$stmt1->bindValue(":b", $b);
$stmt1->bindValue(":c", $c);
$stmt1->bindValue(":d", $d);
$stmt2 = clone $stmt1;
$stmt1->bindValue(":search", "a%");
$stmt2->bindValue(":search", "b%");
$stmt1->execute();
$stmt2->execute();
while(($r1 = $stmt1->fetchObject()) && ($r2 = $stmt2->fetchObject()))
echo $r1->foo . " " . $r2->foo . "\n";
}
Am I allowed to do something like this? How can I clone/reuse a PDOStatement instance and use it at the same time of its original instance?
Don't say "use UNION", that's not the point of my question :P
Thank you in advance.
This is not what prepared statement re-use is for. The idea of reusing a prepared statements is consecutive, not concurrent.
So you can do this:
$connection = new \PDO($dsn, $user, $pass);
$stmt = $connection->prepare("
SELECT *
FROM table
WHERE a = :a
AND b = :b
AND c = :c
AND d = :d
AND search LIKE :search
");
$stmt->bindValue(":a", $a);
$stmt->bindValue(":b", $b);
$stmt->bindValue(":c", $c);
$stmt->bindValue(":d", $d);
foreach (["a%", "b%"] as $search) {
$stmt->bindValue(":search", $search);
$stmt->execute();
while($r = $stmt->fetchObject()) {
echo $r->foo . "\n";
}
$stmt->closeCursor();
}
If you want to handle multiple result sets concurrently (at least with MySQL), you will need to do one of the following:
Use an appropriate set of UNION/JOIN to create a single result set.
Buffer the result sets in memory and iterate them again when you have all the data available.
Create multiple connections - you cannot have more than one open statement cursor per connection, but you can have multiple open connections.
If you want to use multiple connections, your code becomes:
$query = "
SELECT *
FROM table
WHERE a = :a
AND b = :b
AND c = :c
AND d = :d
AND search LIKE :search
";
$connection1 = new \PDO($dsn, $user, $pass);
$connection2 = new \PDO($dsn, $user, $pass);
$stmt1 = $connection1->prepare($query);
$stmt1->bindValue(":a", $a);
$stmt1->bindValue(":b", $b);
$stmt1->bindValue(":c", $c);
$stmt1->bindValue(":d", $d);
$stmt1->bindValue(":search", "a%");
$stmt2 = $connection2->prepare($query);
$stmt2->bindValue(":a", $a);
$stmt2->bindValue(":b", $b);
$stmt2->bindValue(":c", $c);
$stmt2->bindValue(":d", $d);
$stmt2->bindValue(":search", "b%");
$stmt1->execute();
$stmt2->execute();
while(($r1 = $stmt1->fetchObject()) && ($r2 = $stmt2->fetchObject()))
echo $r1->foo . " " . $r2->foo . "\n";
}
$stmt1->closeCursor();
$stmt2->closeCursor();
Sounds like you're looking for an abstraction of a prepared statement that is able to carry it's own parameters with it.
As you actually consume each result by traversing it, adding an Iterator that knows how to traverse such a parametrized prepared statement looks fitting then.
However this suggestion is not part of PDO, so you would need to write it your own (however this might also prevent to repeat yourself with PDO code and you perhaps can even deffer the actual creation and execution of the statement so this might also create some benefit for lazy loading data).
Here's the problematic PHP function:
//Get data associated with $criteria from db
function getUserData($criteria, $value) {
//obtain user data from db based on $criteria=$value
global $pdo;
//echo $criteria . " " . $value;
try {
$sql = 'SELECT id, first, last, email, userid FROM users WHERE :criteria= :value';
//var_dump($sql);
$st = $pdo->prepare($sql);
$st->bindValue(':criteria', $criteria);
$st->bindValue(':value', $value);
$st->execute();
}
catch (PDOException $ex) {
$error = "Failed to obtain user data.";
$errorDetails = $ex->getMessage();
include 'error.html.php';
exit();
}
$row = $st->fetch();
//var_dump($row);
if ($row)
{
$userdata = array();
$userdata['id'] = $row['id'];
$userdata['first'] = $row['first'];
$userdata['last'] = $row['last'];
$userdata['email'] = $row['email'];
$userdata['userid'] = $row['userid'];
return $userdata;
}
return FALSE;
}
I use this function to return a whole row of data associated with specific column in it.
When used at it's current state, with a call like that getUserData("email", "John_Stewart_2013"), it returns false, meaning an empty result, while the same query runs fine in MySQL CLI.
If I, on the other hand, substitute the query string $sql with :
$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria='$value'";
And comment out the bindValue calls, Every thing runs fine in PHP, and the query returns as desired.
But the problem is, those function arguments are user-submitted form data, meaning the solution is vulnerable to SQL Injection.
What's wrong here in the first query form?
You can't use bindValue with column names I'm afraid.
If you think about what a prepared statement is, this should become more obvious. Basically, when you prepare a statement with the database server, it creates an execution plan for the query beforehand, rather than generating it at the time of running the query. This makes it not only faster but more secure, as it knows where it's going, and the datatypes that it will be using and which are going to be input.
If the column/table names were bindable in any way, it would not be able to generate this execution plan, making the whole prepared statement idea somewhat redundant.
The best way would be to use a hybrid query like so:
$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria = :value";
I'm going to hope that the $criteria column isn't entirely free form from the client anyway. If it is, you'd be best limiting it to a specific set of allowed options. A simplistic way to do would be to build an array of allowed columns, and check if it's valid with in_array, like so:
$allowed_columns = array('email', 'telephone', 'somethingelse');
if (!in_array($criteria, $allowed_columns))
{
$error = "The column name passed was not allowed.";
$errorDetails = $ex->getMessage();
include 'error.html.php';
exit;
}
Good afternoon everyone, I have a doubt.
I have a SELECT with PDO. More must be done within another SELECT WHILE to get data for that select, giving it more
Error (Error: There Is Already an active transaction).
If anyone can help me be grateful.
Example code.
try{
$this->conex->beginTransaction();
$query = $this->conex->prepare("SELECT idUser FROM usuario WHERE id = :id ORDER BY data DESC LIMIT $pagin, $paginaF");
$query->bindParam(":id", $ID, PDO::PARAM_INT, 20);
$query->execute();
while ($lista = $query->fetch()){
$idUser = $lista['idUser'];
echo "<div id='avatar'>"box::avatar($idUser)."</div>"
}
//Here he works out of WHILE. Inside it does not work...
echo box::avatar($idUser);
$this->conex->commit();
}catch (PDOException $ex) {
echo "Erro: " . $ex->getMessage();
}
public function avatar($idUser){
$idUser = (int) $idUser;
$query = $this->conex->prepare("SELECT avatar FROM login WHERE id = :id LIMIT 1");
$query->bindParam(":id", $idUser, PDO::PARAM_INT, 20);
$query->execute();
while ($avatar = $query->fetch()){
$avatar = $avatar['avatar'];
}
return $avatar;
}
You have to close the cursor before calling for a new transaction.
Besides, may I ask why are you creating transactions since you're only doing simple *select*s?
Nested Transactions are not possible (as mentioned by the error message). In the first line, you start one transaction. Within the loop, you call avatar(), that starts another transaction, which fails, because there is already one.
However, for SELECT-Queries you dont need transactions at all. Just omit it.
You may also think about JOIN, so you can handle all in just one Query (and then transactions are really useless).
May not be an answer to the problem for now but this line :
echo "<div id="avatar">".$box = box::avatar($id)."</div>"
is full of errors.
" aren't escaped.
no ; at the end.
You're trying to give a value to a variable inside an echo. This'll throw an error.
If you don't use the avatar() function elsewhere, you can do :
try{
$this->conex->beginTransaction();
$query = $this->conex->prepare("SELECT usuario.id as id, login.avatar as avatar FROM usuario, login WHERE usuario.id = :id and usuario.id ORDER BY data DESC LIMIT $pagin, $paginaF");
$query->bindParam(":id", $ID, PDO::PARAM_INT, 20);
$query->execute();
while ($lista = $query->fetch()){
$id = $lista['id'];
$avatar = $lista['avatar']
echo '<div id="avatar">'.$avatar.'</div>';
}
}catch (PDOException $ex) {
echo "Erro: " . $ex->getMessage();
}