which mysqli functions do a client server round trip - php

I want to understand how many client sever calls are made for a typical mysqli query?
Step(1) $result = mysqli_query($link, $query);
Depending on the type of query, we use other mysqli function after this like
mysqli_fetch_fields, mysqli_affected_rows, mysqli_insert_id, mysqli_fetch_row
etc. then we close the result object.
Now, is all data retrieved and stored in php memory after step (1)?
Or mysqli_fetch_fields, mysqli_insert_id etc makes another call to mysql server?
Reason for asking: Trying to understand how mysqli calls work. But can not find such explanation anywhere for beginners like me.

PHP MySQLi API is built on MySQL C API. So it would be better if you have knowlegdes of it.
Basically, SELECT query could generate large ResultSet and this ResultSet is transfered from Server to Client when you call PHP's mysqli_store_result() (In C API, mysql_store_result()).
C API mysql_fetch_row() just returns a pointer to MYSQL_RES* (which is already stored in PHP right after mysql_store_result(). But 'mysqli_fetch_row()` would require some memories to make PHP's array.
mysqli_insert_id() (which is last_insert_id() of C API) just returns insert id of MYSQL connection data stucture which means there is no extra memory for insert id.
If you want to know how MySQLi works, I would recommand to learn MySQL C API and see PHP source codes.

mysqli_query runs the query on the server and returns false is the query failed, true is the query was successful but did not return anything (UPDATE query for example) or a mysqli_result otherwise. That mysqli_result is a class that extends Traversable interface, so yes, it's in memory. All other functions mysqli_fetch_fields, mysqli_affected_rows etc. are just methods in that class so those just read what's already in memory.
For more details, read this: php documentation

The documentation tells you everything you need to know about mysqli.
mysqli_query execute the query and returns a query object, this object has some methods and amongst them there are:
mysqli_fetch_fields:
Returns an array of objects representing the fields in a result set
mysqli_affected_rows:
Returns the number of rows affected by the last INSERT, UPDATE, REPLACE or DELETE query.
mysqli_insert_id:
Returns the auto generated id used in the last query
mysqli_fetch_row:
Get a result row as an enumerated array
Being all method of an object they don't execute sql requests, they simply access object values and gives you back different results depending on the method.

Related

Do mysqli_result need an alive connection to seek results?

We noticed that a call to our API endpoint usually have multiple duplicated MySQL queries for SELECT statements (sometimes hundreds). So we decided to create a hashmap to store the
mysqli_result and check if a given query has already been done and return the result saved in our map.
My question is: do mysqli_result maintain a reference to our connection? Would this actually help us to avoid overloading our database with queries that have already been requested unnecessarily? If the mysqli_result is too big, could this overflow the memory for our fpm process?
What I want to know basically is what approach is better:
For query A, reuse mysqli_result object everytime I need it;
Redo query A everytime I need it.
mysqli_result() requires neither a connection to MySQL nor a mysqli object once the results are fetched from MySQL.
Caveat: The above only applies to the buffered queries. If you are using unbuffered resultsets then mysqli_result requires an open mysqli connection to fetch the data otherwise you will receive an error saying:
PHP Warning: mysqli_result::fetch_all(): Error while reading a row in ...
However, this error message can only happen when you close the connection when using unbuffered queries. e.g.
$res = $mysqli->query('SELECT id FROM Users LIMIT 1', MYSQLI_USE_RESULT);
$mysqli->close();
$res->fetch_all();
Even though mysqli_result requires a valid connection when creating an instance of it, it only needs the connection to fetch the data. The second parameter in the mysqli_result::__construct() is used to decide whether the resultset should be buffered in PHP or stored on MySQL server and fetched row by row. When you create an instance of mysqli_result you need to pass an instance of mysqli as the first parameter.
// Execute query on MySQL server
$res = $mysqli->real_query('SELECT id FROM Users LIMIT 1');
// Create the result object.
// The second argument can be MYSQLI_STORE_RESULT for buffered result or MYSQLI_USE_RESULT for unbuffered.
$res = new mysqli_result($mysqli, MYSQLI_STORE_RESULT);
// If MYSQLI_STORE_RESULT was used then you can close mysqli here.
unset($mysqli); // or $mysqli->close(); or both
$data = $res->fetch_all();
// If MYSQLI_USE_RESULT was used then you can't close mysqli yet.
// unset($mysqli);
$data = $res->fetch_all();
Buffering of SQL queries is a rather complex task and it would be better to avoid duplicate calls rather than implementing caching. Try to refactor your code so that it does not call the same SELECT query multiple times during the execution of your script.
There is also a pre-made solution for this, although not very popular. Mysqlnd query result cache plugin
And as always remember that:
premature optimization is the root of all evil

Mysqli dynamic query bind_results

I wrote one databasse class which I use often and I used mysqli.I wanted to write it with PDO but it was slow (It is not about ip connection :) ),and my website is really huge and this pdo little slowness will be really big problem,that's why I choosed difficult way --Mysqli--.I wrote some dynamic class which bind params dynamicly and easily usage like this:
DB::getInstance()->query(sql,'ss',array($a,$b));
This was really useful untill today.I wanted to get result and also count values but I discover reaally big problem that when I use num_rows mysqli get_result will not work,When I use get_result num rows will never work,also when I use get_result and if I want to use it again for same query second one will not work
.Also get_result is not good function because it support only mysqlid.Then I have tried bind result which is useless because every select query I should write bind_result(params) which is not good for other developers on company also.What Should I do?Pdo is slow and for my website it is really slow,mysqli is not for developers it increase development time.How can I bind results dinamicly for query?I want something like I will write sql statement and bind result should get column names dinamicly bind them aoutomaticly and then I will write fetch() and I will write column names and I will get result.How can I do that?
When I use get_result num rows will never work
this is not true
besides, you never need num rows anyway
when I use get_result and if I want to use it again for same query
you don't want it
get_result is not good function because it support only mysqlid
this is true
however, if your site is so big and distinct, there is no problem to install a required module or two.
How can I bind results dinamicly for query?
use get_result.
To reuse a result get all the rows into array using fetch_all() and then use this array anywhere you wish
Instead of num_rows just fetch the data and see whether anything was fetched or not.

Add element to array in the conditional statement of a loop in PHP

I have this piece of code:
while ($i = $res->fetchArray(SQLITE3_ASSOC))
{
$items[] = $i;
}
I tried neatening it to this:
while ($items[] = $res->fetchArray(SQLITE3_ASSOC));
It looks very satisfying but I now get an extra element at the end of the array (when the call to fetchArray() returns false. Is there a way of writing this statement without getting the extra element at the end?
If you're using PDO as your database library, you should use the fetchAll() method (documentation)
$items = $stmt->fetchAll(PDO::FETCH_ASSOC)
This will provide you a bidimensional associative array. Its index goes from 0 to n-1 where n is the fetched rows count and every row contains an array with column names as indexes. For example:
$items[3]['id']
will contain the value stored in the id column of the 4th fetched row.
if you're using mysqli_* instead, there is mysqli_fetch_all() but it's discouraged because it's more expensive rather a loop of mysqli_fetch_array(), or so the documentation says.
If you're using a third party library, consult the provided documentation. If there is none provided or there is no fetchAll equivalent it's a sign of poor quality. Drop it and use the native PDO instead.
Since you're using SQLITE3 driver, i suggest you to look at this page: SQLITE (PDO) which explains how to use PDO with SQLITE3. Believe me, it's worth it. Most probably you won't stick to SQLITE for long and when you'll migrate to MySQL or PostgreSQL you'll thank me for this read.
PDO's main advantage is that's (usually) transparent to the user regarding which DB is below. Therefore, it shouldn't break your application if you change database, just change the PDO connection string and it'll be enough.
Try
while(($item=$res->fetchArray(SQLITE3_ASSOC))&&$items[]=$item);

How many sql queries does this scenario make (PHP)?

Ok, so if I set into a variable an sql_query like so:
$query = mysql_query("..");
and call multiple mysql_result's like so:
mysql_result($query, 0);
mysql_result($query, 1);
mysql_result($query, 2);
How many queries will the page call to the server?
Only once? or three times?
When you execute mysql_query, It executes the sql and it keeps the result in an internal result structure. Next time when you call mysql_result, it fetches from that internal result.
For buffered query the reusult will be copying from MySQL server to PHP as soon as mysql_query is executed. For un-buffered query it'll be copied lazily.
So in both case Query executes only one time. But for un-buffered query it'll be fetched from MySQL server. every time you call mysql_result or mysq_fetch_*.Buffered and Unbuffered queries
You have given the answer yourself. If you are calling "query" function once, then it will only
execute once no matter how many times you parse its return value
$query = mysql_query("..");
When you run the above code then query gets executed and the returned resource is in $query variable. Then you can fetch data from it multiple times but query wont run again.
Here will be one query with database that's means Server. mysql_result() should not be mixed with calls to other functions that deal with the result set.
For more information you can visit : http://php.net/manual/en/function.mysql-result.php
Only *mysql_query* is executing against the mysql server. Only one query
mysql_result only fetches data from a mysql resource, it doesn't matter if you have previously gotten it from a query in code or managed to get it from another source.
From PHP 5.5.0 onwards this function is deprecated; the new way to perform this action would be to create a mysqli object and use over the functions mysqli::query and mysqli::fetch_field

PDO - 'no fields' result when AzureSQL is returning a result

I'm using PDO::query to run the following SQL statement:
INSERT INTO pages (template_id,user_id,page_default,page_internal_title,page_menu_text,page_nav_link,globalcontent_id,page_parent_id,page_order,page_active,page_show_in_menu,page_hide,page_created,page_updated,page_deleted,page_type) values (
4,1,'n','Test',
...snip...
'n','page');SELECT LAST_INSERT_ID=##IDENTITY
Which if I run in the AzureSQL manager directly performs the insert as expected and returns the last_insert_id as it should.
However, when I call fetchAll() on the statement object returned from PDO::query, it throws an "The active result for the query contains no fields." exception. PDO::query is working, as the row is being inserted, but it's as though either the select is failing (but it's not throwing an exception at that point), or there is something obvious I'm missing (more than likely).
Any help would be great!
Cheers!
Have you tried PDO::lastInsertId()?
I'm pretty sure I read about PDO with MSSQL not supporting multiple result sets, but I can't find the reference at the moment :-/. If your scenario allows you to use the function above, this might be the easiest solution.

Categories