This sounds like a really simple question, but I am new to PHP. If I have a statement like this:
$r =& $db->query("insert into table (col1, col2) values (10, 20)");
Do I have to still execute it, or does it get executed when I reference it? I have another case where I have a select query, which seems logically to run only when I call fetchrow, but the code I am copying from does not call execute or fetch. I would have expected it to, so I cannot tell if it is just that I don't get it, or that the missing execute statement is the problem. It also does not insert the record, but it does not throw an error I can find.
Also, I am a little confused by the =& notation. I looked it up on google, and found a few mentions of it, but I am still not clear on it.
Thanks.
It will be executed when you call query()
The =& notation is obsolete... it used to make the function return a reference to the resource object. But current versions of PHP (>5.0, I think) always pass (and return) objects by reference, so it doesn't really change anything anymore.
The query gets executed when you call the query function. when you talk about code that needs to be fixed, what is broken, and what does the code that "need[s] to be fixed" (according to who?) look like?
& is used in several contexts and it means by reference. You should start reading from here:
http://es.php.net/manual/en/language.operators.assignment.php
http://es.php.net/manual/en/language.references.return.php
In your code snippet it's most likely unnecessary (although you give little clue about what $db is) because the result set is probably an object and objects no longer need to be assigned by reference since that's the default behaviour. If you are learning PHP, be careful with outdated tutorials.
$db->query is a method contained by a class, it's not functional in php out of context. It is possible that this example of yours comes from a larger application that uses a database abstraction layer like ADODB or any of its kind.
If this is the case, then you could refer to the documentation specific to that db abstraction layer, because the query could be contained in a transaction for example and it would not be executed as soon as you call query();
To be sure the query is executed immediately try testing with a simple mysql function:
mysql_query("SHOW TABLES");
Related
I am trying to find the best way to get records from a MySQL table via a PHP function call using a prepared statement and PDO?
Efficiency is not the issue (I am sure there is perhaps a faster way or more memory efficient way to accomplish this task). My goal is to make the code simple, with one call to a function for to obtain records via a PHP function call and a using PDO prepared statement.
The caller so far looks like this:
$records = DB_Get_Records($pdo_connection, '"SELECT * FROM Table1 WHERE ID = ?', array($record_id);`
And the function looks like this:
function DB_Get_Records(&$pdo_connection, &$sql_statement, &$records_located, &$select_string, &$param_array) {
$sql_statement = $pdo_connection->prepare($select_string);
$sql_statement->execute($param_array);
$records_located = $sql_statement->fetch(PDO::FETCH_ASSOC);
return $records_located;
Because of the scope of the params, I am using pass by reference. But I am not sure how to best define in the main portion of the script. If I use pass by value, I believe that all results will be lost after returning from the function.
The confusion is how to define them prior to the function call so that they will receive the data. I am not sure if I have to reserve space of a some sort prior to calling the function. When using
$records_located = $sql_statement->fetch(PDO::FETCH_ASSOC);
In either the main portion of the script or the function, $records_located receives the records.
But trying to path this information from the caller to the main is not clear to me. When used in the function, the fetch statement (I believe) will create the necessary space using $records_located as the pointer. The question that pops up seems to be is how? Is the receiving variable used to create an array and then setting a point to $records_located variable? If so, then the scope would of the array would likely be limited to the function call. And if that is the case, then -- although the data pointer is retained -- the actual data returned from fetch would be gone after the function returns.
Hopefully, I am missing something here or overthinking the issue.
Again, it is not about trying to maximize speed of memory usage. It is simply about making simple calls to the database of one line instead of many lines to setup each call to get records.
Thanks for any help you can provide!
Looks like you need to forget all about allocating memory and who does what where, PHP mostly does that for you. If you change all of your parameters to NOT be passed by reference and then
return $sql_statement->fetchAll(PDO::FETCH_ASSOC);
This will just return an array of the results and no scope is involved
There is a long living large project in PHP, in the development of which at different times were involved a number of different developers. Potentially, there may have been places where duplicate database queries were made during bug fixing. Some developer to solve a local problem could write and execute a query returning data that were previously obtained. Now on the project there is a problem of DB performance and in light of it a have a question:
Are there any tools (besides General Log) that allow you to see what database queries were made as part of a single PHP script execution?
The question is related to the fact that there are a lot of API endpoints in the project and it will take a long time to check them all just by reading the code (which is sometimes very ornate).
Most PHP frameworks use a single connection interface - some kind of wrapper - that makes it possible to log all queries through that interface.
If that does not exist another approach would be to enable logging at the MySQL-level. But for some, probably legit, reason you don't want to do that either. If you want to prevent downtime you can actually enable query logging without restarting the MySQL server.
If none of the above solutions is possible you have to get your hands dirty :-)
One way could be to add your own logging in the PHP code.
Writing new lines to a file is not a performance issue if you write to the end of the file.
I'm not sure how you query the database, but if you..
A) ..use the procedural mysqli functions
If you use the procedural mysqli functions like mysqli_query() to call the database you could create your own global custom function which writes to the log file and then call the real function.
An example:
Add the new global function:
function _mysqli_query($link, $query, $resultmode = MYSQLI_STORE_RESULT )
{
// write new line to end of log-file
file_put_contents('queries.log', $query . "\n", FILE_APPEND);
// call real mysqli_query
return mysqli_query($link, $query, $resultmode);
}
The do a project-wide search and replace for mysqli_query( with _mysqli_query(.
Then a line like this:
$result = mysqli_query($conn, 'select * from users');
Would look like this after the search and replace:
$result = _mysqli_query($conn, 'select * from users');
B) ..use the mysqli class (object oriented style)
If you use the object oriented style by instantiation the mysqli class and then calling the query methods e.g. $mysqli->query("select * from users") an approach could be to create your own database class which extends the mysqli class, and inside the specific methods (e.g. the query function) you add the logging like in the above example.
In the highly recommendable book "High Performance MySQL" from O'Reilly they go through code examples how to do this and add extra debug information (timing etc.). Some of the pages are accessible at google books.
In general
I would consider using this as an opportunity to refactor some of the codebase to the better.
If you have written automated tests that is a good way to ensure that the refactoring did not break anything.
If you do not practice automated testing you have to test the whole application manually.
You said that you are afraid that your performance issues comes from duplicate database queries, which might very well be the case.
In most cases I find it to be missing indexes though or a need to rewrite single queries.
The performance schema in MySQL can help you debug these things if you find it realistic that it could be other causes to the performance issues.
I've created a basic class called Content for fetching content from a MySQL database, with a constructor like so:
$this->handle = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
and some methods utilizing this handle, chiefly one that fetches data and puts it into an array:
function select($query) {
$sth = $this->handle->prepare($query);
$sth->execute();
$result = $sth->fetchAll();
$sth->closeCursor();
return $result;
}
Nothing fancy, really. And it works terrific. Except, after a dozen or so various queries, fetchAll all of a sudden returns an empty result. When I run the same query directly on the database, I do get a result. Also, when I run the query before running the other ones, I get a result as well. Even more oddly, the fetchAll at this point in my script used to work fine, but when the queries that preceded it got more numerous, it started returning empty results.
Based on these findings, I assumed the scripting and database where just fine, and it most likely had something to do with PDO. Eventually, I 'fixed' it by creating a second object from my Content class in order to fetch the data I was missing:
$contentTwo = new Content();
Of course, this should not be necessary! I'm looking for a real solution, and also an understanding as to what's going on. I've turned on all sorts of error reporting (PHP, PDO, MySQL) but there are no errors. Could it be some internal PDO mixup? Is there a maximum amount of prepared statements? Any ideas/solutions would be appreciated.
Could it be some internal PDO mixup?
No.
Is there a maximum amount of prepared statements?
No.
Any ideas/solutions would be appreciated.
Yes.
The problem you faced with is not something unusual.
Every developer has to deal with such a case once or twice a day. This is quite normal for our profession, when something goes wrong. A program is so complex a facility that sometimes it goes wrong. It is a duty of a programmer to find out and to fix the error.
So, you have to investigate the cause.
For such a purpose create a comprehensive logging system, and log everything you can hold of in case of an empty result returned. State of PDO object, input data, all involved variables, etc.
This way you most likely will be able to spot the problem
I have written a PHP OO class which will update 4 fields of a certain row in a table. For now the row is decided by a constant (user with name 'jip')
I have corrected the query in a previous post here, so i'm pretty sure the query itself is fine. So, there must be some sort of error within the class itself. Probaply the vars don't reach the query somehow. I have been looking for hours, but can't find the problem. I have linked both files of the class, since i downt know where the error is, the values just don't show up in the database. If anyone would like to check them, (s)he'd make my entire week! SO here is the link and i hope someone is willing to help :)
UpdateForm.php: http://pastebin.com/dUaZPrn6
Update.class.php: http://pastebin.com/6mnL4DzE
Try replacing mysqli_real_escape_string($conn, $variable) with
$conn->real_escape_string($variable);
For example,
$conn->real_escape_string($this->Lengte_update);
You're using the object-oriented style, so you can't use the procedural escape function. See the docs on mysqli::real_escape_string.
Edit:
The query isn't being executed. You assign the query to $query, but you need to call
$conn->query($query);
For anything to happen in the database.
I am running following PHP code to interact with a MS Access database.
$odbc_con = new COM("ADODB.Connection");
$constr = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=" . $db_path . ";";
$odbc_con -> open($constr);
$rs_select = $odbc_con -> execute ("SELECT * FROM Main");
Using ($rs_select -> RecordCount) gives -1 though the query is returning non-zero records.
(a) What can be the reason?
(b) Is there any way out?
I have also tried using count($rs_select -> GetRows()). This satisfies the need but looks inefficient as it will involve copying of all the records into an array first.
ADODB has its own rules for what recordcount is returned depending on the type of recordset you've defined. See:
MS Knowledge Base article 194973
W3C Schools article
In the example above, the PHP COM() object is used to instantiate ADODB, a COM interface for generic database access. According to the PHP documentation, the object reference produced is overloaded, so you can just use the same properties/methods that the native ADODB object would have. This means that you need to use the ADODB methods to set the recordset type to one that will give an accurate recordcount (if you must have it). The alternative, as others have mentioned, is to use a second query to get the COUNT() of the records returned by the SELECT statement. This is easier, but may be inappropriate in the particular environment.
I'm not an ADO guru, so can't provide you with the exact commands for setting your recordset type, but from the articles cited above, it is clear that you need a static or keyset cursor. It appears to me that the proper method of setting the CursorType is to use a parameter in the command that opens the recordset. This W3C Schools article on the CursorType property gives the appropriate arguments for that command.
Hopefully, this information will help the original poster accomplish his task, one way or the other.
It is possible that ODBC doesn't know the recordcount yet. In that case it is possible to go to the last record and only then will recordcount reflect the true number of records. This will probably also not be very efficient since it will load all records from the query.
As Oli said, using SELECT COUNT(*) will give you the result. I think that using 2 queries would still be more efficient than using my first method.
Doesn't Access have its own COUNT operator? eg:
$rs_select = $odbc_con -> execute ("SELECT COUNT(*) FROM Main");
Basically, Access is not going to show you the whole record set until it needs to (it's faster that way for much of the user experience anyway) - especially with larger recordsets.
To get an accurate count, you must traverse the entire record set. In VBA I normally do that with a duo of foo.MoveLast and foo.MoveFirst - I don't know what the php equivalents are. It's expensive, but since it sounds like you are going to be processing the whole record set anyway, I guess it is OK.
(a side note, this same traversal is also necessary if you are manipulating bookmarks in VBA, as you can get some wild results if you clone a recordset and don't traverse it before you copy the bookmark back to the form's recordset)
If you're using a dynamic cursor type of connection, then it could actually change. Someone may delete a record from that database while you're browsing through pages of records. To avoid, use a static sort of snapshot cursor. I have this bookmarked which will explain it well. This always got me and the bookmark always reminded me why.
http://support.microsoft.com/kb/194973