I recently ran across some code which the person did the first one. Would like some thoughts on if the top one is better or why a person would write it that way? Any positive reasons over the bottom way.
$result = mysql_query($query)or die("Obtaining location data failed!");
for ($i = mysql_num_rows($result) - 1; $i >=0; $i--)
{
if (!mysql_data_seek($result, $i))
{
echo "Cannot seek to row $i\n";
continue;
}
if(!($row = mysql_fetch_object($result)))
continue;
echo $row->locationname;
}
mysql_free_result($result);
vs
$result = mysql_query($query) or die("Obtaining location data failed!");
while($row = mysql_fetch_object($result)){
echo $row->locationname;
unset($row);
}
mysql_free_result($result);
It looks like the top code is iterating through the mysql result backwards, where the first one is going through it forwards.
The second code example looks cleaner, and there is probably a way to adjust the query to get the results in reverse order in the first place, instead of the somewhat convoluted way the top loop was performed.
Those two are not equivalent since only the first processes the result set in reverse order.
I'd do that with an ORDER BY x DESC clause if only to keep the code simple. When using mysql_query() the complete result set is transferred from the MySQL server to the php process before the function returns and mysql_data_seek() is only moving some pointer within the process' memory, so performace-wise it shouldn't matter much. But if you at some point decide to use an unbuffered query instead it might very well affect the performance.
Definitely the second one :
less code = less code to maintain =~ maybe less bugs !!
The top one has definite advantages when it comes to job security and 'lines of code' performance metrics. Apart from that there is no good reason to do what they did.
Related
After some research, I have been sold on the idea of generators (more generally, iterators) for lots of tasks that would normally buffer results into an array, since the memory usage is O(1) instead of O(n).
So I plan to use generators to handle database results queried via mysqli. I have 2 questions regarding this approach that I have not been able to find answers on, and I am hoping the community can give me some creative solutions:
Is there a way to release resources opened by a generator, if the consuming code chooses to not fully iterate the results? Using an Iterator class, one might do this in the __desctruct method. But, from my tests, a generator will simply not execute code following an iteration sequence if it does not conclude naturally. I am looking for workarounds to this that will prevent having to create an Iterator subclass. See code below.
Does using a generator or iterator even provide any benefit for database results? Some of my snooping seemed to indicate that mysqli might be loading the resultset into memory anyway (MYSQLI_STORE_RESULT), defeating the purpose of an iterator. If the results are not buffered, I am curious whether multiple queries can be executed while their resultsets are being iterated (fetched) at the same time (think nested loops where you are iterating over a set of items and then query for child items for each parent). This seems like the database cursor might lock during the entire iteration.
Example
The below is a simplification of what I mean by cleanup. From my tests, the result only gets freed if the entire result is iterated. If there is an exception or break in the consuming loop, the results never get freed. Perhaps I am overthinking this and the garbage collector is good enough?
function query($mysqli, $sql){
$result = $mysqli->query($sql);
foreach($result as $row){
yield $row;
}
$result->free(); //Never reached if break, exception, take first n rows, etc.
}
tl;dr is I am just curious how to free resources used by a generator, and subsequently if generators for database access really saves anything, or if the results are buffered anyway
UPDATE
It looks here (http://www.php.net/manual/en/mysqlinfo.concepts.buffering.php) like PHP buffers queries by default, possibly defeating the purpose of generators. Although the argument could be made that buffering only one array is better than creating a copy of the buffered array and then having two buffered sets.
I am looking for anyone with experience in the matter to weigh in. Your thoughts are appreciated!
I may be a little late to the party, but if you are using generators and need to clean up when finished (say you break you parent loop before you are finished looping through everything), you can just use a try/catch/finally with the cleanup in the finally block:
function query($mysqli, $sql) {
$result = $mysqli->query($sql);
try {
if ($result) {
foreach($result as $row) {
yield $row;
}
}
} catch (Exception $e) {
throw $e; // send this up the stack (or you could handle here)
} finally {
$result->free(); // clean up when the loop is finished.
}
}
Here's how to detect loop breaks, and how to handle or cleanup after an interruption.
function generator()
{
$complete = false;
try {
while (($result = some_function())) {
yield $result;
}
$complete = true;
} finally {
if (!$complete) {
// cleanup when loop breaks
} else {
// cleanup when loop completes
}
}
// Do something only after loop completes
}
function query($mysqli, $sql){
$result = $mysqli->query($sql);
foreach($result as $i => $row) {
if ($i + 1 === $result->num_rows) {
$result->free();
}
yield $row;
}
}
I've got a few while loops in my PHP code that look somewhat like this:
qry_myquery = "SELECT * FROM table WHERE value = '$value' ";
$rs_myquery = mysql_query($qry_myquery) or die(mysql_error());
while($row = mysql_fetch_assoc($rs_myquery)){
if($row[$entryType] > 0){
$entryPointNumber = $row[$entryType];
}else {
$data["FatalError2"] = "Error!";
die();
}
} //END: While loop - entries from AJAX legal.
My question - is there anything wrong with writing while loops in this way? Will they continue to run indefinitely and suck memory/unneeded processing power? Am I supposed to close them off somehow after I'm done with them?
is there anything wrong with writing while loops in this way?
no
Will they continue to run indefinitely and suck memory/unneeded processing power?
no, it runs as long as the condition is true, in your case, when there are no more rows, the loop will stop
Am I supposed to close them off somehow after I'm done with them?
no (but maybe i didnt understand what you are asking here)
The WHILE loop seems to be fine and the loop wont run indefinitely.
But I see one issue with the code, which is the die() statement.
By calling the die(), you are not doing a clean exit in the code.
What I mean is you are not closing the database connect.
I've developed a habit of renaming my SELECT statement variable and I'm interested to know if it is necessary or not.
Here some typical code that I use:
$sql = ("SELECT * FROM tbl_one");
if(!$result_sql = $mysqli->query($sql))
{
// Error code here
}
while($a = $result_sql->fetch_assoc())
{
echo $a;
}
$sql2 = ("SELECT * FROM tbl_two");
if(!$result_sql2 = $mysqli->query($sql2))
{
// Error code here
}
while($b = $result_sql2->fetch_assoc())
{
echo $b;
}
For some reason I'm afraid there will be issues if I reuse the same $sql variable over again unless I rename it.
It's always good to have a different different variable for each statement you have as per coding standards even though PHP does not mind using same variable again and again.
It's just a string, so you shouldn't care. Its fine to use the same variable again if you don't need the previous value anymore.
Theoretically I opt not to reuse variable names for this sort of code, because of the risk of accidentally not overwriting one of them and getting strange results.
Then again, that problem doesn't go away just because you try to force yourself to remember to increment a number stuck on the end of the variable name.
Over time, as my code has improved, I've found that I very rarely need or want to execute multiple MySQL queries within a single PHP function, so the problem goes away entirely.
tl;dr: If I had a gun to my head, though... yes, I'd probably do it the same way you did. It's entirely subjective, though.
I usually try to minimize calls to MySQL where possible, but I've finally encountered the case where I have to do multiple calls to MySQL in a single script.
It looks like you can't use mysql_fetch_assoc twice in a single script(!).
It seems that mysql_data_seek is the solution, but I cannot seem to get it to work.
To be clear, I have two queries I need to make. The second query depends on results from the first... Here's the structure:
$result = mysql_query($query1);
while($row = mysql_fetch_assoc($result)){
$pos = $row['position'];
}
mysql_free_result($result); // result freed per comment below.
$query2 = ' '; //... dependent on $pos - in mysql shell this returns results!
$result2 = mysql_query($query2)
while($row = mysql_fetch_assoc($result2)){
echo $row['id'];
}
What happens above is that the second while loop returns no results even though the query should have nontrivial rows.
Just to be sure:
Is this how you clear the pointer from the previous result to be able to use mysql_fetch_assoc again?
mysql_data_seek($result,mysql_num_rows($result) - 1);
I'm not sure what to use as the second argument. Admittedly, I am not that clear on pointers, but it seems I should clear the pointer to 0. But I get this error:
Offset 0 is invalid for MySQL result index 8 (or the query data is unbuffered
Check your connection with mysql_error() and see if you're getting the "commands out of sync" error. If so, you need to call mysql_free_result() after completing the first query and before starting the second. You could also just call mysql_close() to close your database connection and then reopen a new one.
For more details, see this question.
OP changed the question, so see the edit
*Deleted the posted codes here**
EDIT
After your edited your question and made clear you have actually 2 resources it looks like there is something else wrong. You don't have to worry about pointer when you use two different resources to supply mysql_fetch_assoc(). The thing with mysql_fetch_assoc() is that it takes your param ($result) by reference.
Now to answer your question:
I usually try to minimize calls to MySQL where possible, but I've finally encountered the case where I have to do multiple calls to MySQL in a single script.
Nothing wrong with multiple SQL calls in one script. Although in general you should try to minimize the SQL calls (because they may hurt performance).
It looks like you can't use mysql_fetch_assoc twice in a single script(!).
Plain wrong. Ofc you can do it. As long as you note the above. However when you have two result sets this wouldn't be your problem.
It seems that mysql_data_seek is the solution, but I cannot seem to get it to work.
Again: this has nothing to do with it when you use two (different) result sets.
To be clear, I have two queries I need to make. The second query depends on results from the first.
This shouldn't be any problem at all. It looks like is something else wrong. Have you verified that the second query really is what you think it is? Are you sure there are records? Are you sure there aren't any (MySQL) errors. Do you have error reporting enabled? Have you tried printing out mysql_error()? To better be able to help you can you please provide your real code and not etc etc stuff? Maybe something else is going on.
Or maybe you are simply trying to run the second query inside the first loop. Which would be bad in so many ways.
I use often the function sizeof($var) on my web application, and I'd like to know if is better (in resources term) store this value in a new variable and use this one, or if it's better call/use every time that function; or maybe is indifferent :)
TLDR: it's better to set a variable, calling sizeof() only once. (IMO)
I ran some tests on the looping aspect of this small array:
$myArray = array("bill", "dave", "alex", "tom", "fred", "smith", "etc", "etc", "etc");
// A)
for($i=0; $i<10000; $i++) {
echo sizeof($myArray);
}
// B)
$sizeof = sizeof($myArray);
for($i=0; $i<10000; $i++) {
echo $sizeof;
}
With an array of 9 items:
A) took 0.0085 seconds
B) took 0.0049 seconds
With a array of 180 items:
A) took 0.0078 seconds
B) took 0.0043 seconds
With a array of 3600 items:
A) took 0.5-0.6 seconds
B) took 0.35-0.5 seconds
Although there isn't much of a difference, you can see that as the array grows, the difference becomes more and more. I think this has made me re-think my opinion, and say that from now on, I'll be setting the variable pre-loop.
Storing a PHP integer takes 68 bytes of memory. This is a small enough amount, that I think I'd rather worry about processing time than memory space.
In general, it is preferable to assign the result of a function you are likely to repeat to a variable.
In the example you suggested, the difference in processing code produced by this approach and the alternative (repeatedly calling the function) would be insignificant. However, where the function in question is more complex it would be better to avoid executing it repeatedly.
For example:
for($i=0; $i<10000; $i++) {
echo date('Y-m-d');
}
Executes in 0.225273 seconds on my server, while:
$date = date('Y-m-d');
for($i=0; $i<10000; $i++) {
echo $date;
}
executes in 0.134742 seconds. I know these snippets aren't quite equivalent, but you get the idea. Over many page loads by many users over many months or years, even a difference of this size can be significant. If we were to use some complex function, serious scalability issues could be introduced.
A main advantage of not assigning a return value to a variable is that you need one less line of code. In PHP, we can commonly do our assignment at the same time as invoking our function:
$sql = "SELECT...";
if(!$query = mysql_query($sql))...
...although this is sometimes discouraged for readability reasons.
In my view for the sake of consistency assigning return values to variables is broadly the better approach, even when performing simple functions.
If you are calling the function over and over, it is probably best to keep this info in a variable. That way the server doesn't have to keep processing the answer, it just looks it up. If the result is likely to change, however, it will be best to keep running the function.
Since you allocate a new variable, this will take a tiny bit more memory. But it might make your code a tiny bit more faster.
The troubles it bring, could be big. For example, if you include another file that applies the same trick, and both store the size in a var $sizeof, bad things might happen. Strange bugs, that happen when you don't expect it. Or you forget to add global $sizeof in your function.
There are so many possible bugs you introduce, for what? Since the speed gain is likely not measurable, I don't think it's worth it.
Unless you are calling this function a million times your "performance boost" will be negligible.
I do no think that it really matters. In a sense, you do not want to perform the same thing over and over again, but considering that it is sizeof(); unless it is a enormous array you should be fine either way.
I think, you should avoid constructs like:
for ($i = 0; $i < sizeof($array), $i += 1) {
// do stuff
}
For, sizeof will be executed every iteration, even though it is often not likely to change.
Whereas in constructs like this:
while(sizeof($array) > 0) {
if ($someCondition) {
$entry = array_pop($array);
}
}
You often have no choice but to calculate it every iteration.