Mysql SELECT COUNT(*) OR SELECT 1? PDO - php

It has long been known that PDO does not support COUNT(*) and a query like below would fail as it doesn't return any affected rows,
$q = $dbc -> prepare("SELECT COUNT(*) FROM table WHERE id = ?");
$q -> execute(array($id));
echo $q -> rowCount();
Doing some research I found that you can also get the row count using other methods of count and not using count at all, for example the following query is supposed be the same as above but will return correct for PDO,
$q = $dbc -> prepare("SELECT 1 FROM table WHERE id = ?");
$q -> execute(array($id));
echo $q -> rowCount();
There are various sources on the internet claiming that;
"SELECT COUNT(*)
"SELECT COUNT(col)
"SELECT 1
Are all the same as each other (with a few differences) so how come using mysql which PDO cannot properly return a true count, does
"SELECT 1
work?
Methods of count discussion
Why is Select 1 faster than Select count(*)?

PDO does not support COUNT(*)
WTF? Of course PDO supports COUNT(*), you are using it the wrong way.
$q = $dbc->prepare("SELECT COUNT(id) as records FROM table WHERE id = ?");
$q->execute(array($id));
$records = (int) $q->fetch(PDO::FETCH_OBJ)->records;
If you are using a driver other than MySQL, you might have to test rowCount first, like this.
$records = (int) ($q->rowCount()) ? $q->fetch(PDO::FETCH_OBJ)->records : 0;

Oh. You are confusing everything.
PDO do not interfere with SQL queries. It support EVERYTHING supported by SQL.
When doing COUNT(*) you shouldn't use rowcount at all, as it just makes no sense. You have to retreive the query result instead.
Dunno what "various sources" you are talking about but COUNT(*) and COUNT(col) (and even COUNT(1)) are the same and the only proper way to get count of records when you need no records themselves.
COUNT is an aggregate function, it counts rows for you. So, it returns the result already, no more counting required. Ad it returns just a scalar value in the single row. Thus, using rowcount on this single row makes no sense
SELECT 1 is not the same as above, as it selects just literal 1 for the every row found in the table. So, it will return a thousand 1s if there is a thousands rows in your database. So, rowcount will give you the result but it is going to be an extreme waste of the server resources.
there is a simple rule to follow:
Always request the only data you need.
If you need the count of rows - request count of rows. Not a thousand of 1s to count them later.
Sounds sensible?

Best way I think to test if a line exist in your database is to perform.
SELECT 1 FROM table WHERE condition LIMIT 1
If it find a row it will stop and tell you there is a line. If it don't and you have an index on your where clause column it will also goes very fast to see there are none available.

Related

How can I count entries in mySQL database faster?

I am counting the entries in my SQL database:
$sql = "SELECT * FROM files WHERE id = ?";
$q = $pdo->prepare($sql);
$q->execute([$id]);
$rowCount =$q->rowCount();
The result of $rowCount is 500000.
But to output this single number takes 5 seconds! Is it possible to get this result faster?
Use the COUNT() function https://dev.mysql.com/doc/refman/8.0/en/counting-rows.html:
$sql = "SELECT COUNT(*) FROM files WHERE id = ?";
Also ensure that 'id' is an indexed column:
https://dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html
Replace * with a field(use auto-increment id) - This will reduce the time a bit.
Index that field. - If you use indexed field the query performance will increase.
SELECT * ..., then counting in PHP, requires shoveling all columns of all rows back to PHP. That's a lot of effort for very little gain.
SELECT COUNT(col) ... does the counting in by MySQL, but it must check for whether col is NULL. And it needs to get at the value of col for every row.
SELECT COUNT(*) ... counts the rows by whatever way is most efficient. This involves looking for the 'smallest' index (or the whole table, if no secondary indexes), and counting through it.
You must learn about INDEXes to get anywhere in databases! This is only one minor use for them.

PDO Connection : row count using where clause

I want to count the no of rows in my database..along with where clause and AND clause..
please show me how can we do that in pdo..
these are my queries:
$stmt=$dbh->prepare("SELECT * from questions where (category_id = ?) AND (complexity_id = ?) ORDER BY RAND()");
$stmt->execute(array($_POST['category'],$_POST['complexity']));
$data = $stmt->fetchAll(PDO::FETCH_OBJ)
count:
$nRows = $dbh->query("SELECT COUNT(*) FROM questions");
i need to write both queries in one query only..
you can use fetchColumn.
$number_of_rows=$stmt->fetchColumn(); // will give no. of rows
$data = $stmt->fetchAll(PDO::FETCH_ASSOC)// give the data array
If your queries are different
If your queries are different, like it shown in the question, then keep them as two separate queries. There is no way to get them in one. Just leave it two separate queries, it's all right.
If your queries actually the same
If your queries actually the same, and you want to get your data filtered and also get the number of rows, then you don't need the second query at all. In PHP, there is a function called count(). You can use it to count results returned by your first query.
$nRows = count($data);
as simple as that
Can you just use
$stmt=$dbh->prepare("SELECT COUNT(*) from questions where (category_id = ?) AND (complexity_id = ?)");
query?

Cleanest way to check if a record exists

I am using the following code to check if a row exists in my database:
$sql = "SELECT COUNT(1) FROM myTable WHERE user_id = :id_var";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id_var', $id_var);
$stmt->execute();
if ($stmt->fetch()[0]>0)
{
//... many lines of code
}
All of the code works and the doubts I have are concerning if the previous code is clean and efficient or if there is room for improvement.
Currently there are two questions bugging me with my previous code:
Should I have a LIMIT 1 at the end of my SQL statement? Does COUNT(1) already limit the amount of rows found by 1 or does the server keep searching for more records even after finding the first one?
The if ($stmt->fetch()[0]>0). Would this be the cleanest way to fetch the information from the SQL Query and execute the "if conditional"?
Of course if anyone spots anything else that can improve my code, I would love your feedback.
Q: Should I have a LIMIT 1 at the end of my SQL statement? Does COUNT(1) already limit the amount of rows found by 1 or does the server keep searching for more records even after finding the first one?
Your SELECT COUNT() FROM query will return one row, if the execution is successful, because there is no GROUP BY clause. There's no need to add a LIMIT 1 clause, it wouldn't have any affect.
The database will search for all rows that satisfy the conditions in the WHERE clause. If the user_id column is UNIQUE, and there is an index with that as the leading column, or, if that column is the PRIMARY KEY of the table... then the search for all matching rows will be efficient, using the index. If there isn't an index, then MySQL will need to search all the rows in the table.
It's the index that buys you good performance. You could write the query differently, to get a usable result. But what you have is fine.
Q: Is this the cleanest...
if ($stmt->fetch()[0]>0)
My personal preference would be to avoid that construct, and break that up into two or more statements. The normal pattern...separate statement to fetch the row, and then do a test.
Personally, I would tend to avoid the COUNT() and just get a row, and test whether there was a row to fetch...
$sql = "SELECT 1 AS `row_exists` FROM myTable WHERE user_id = :id_var";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id_var', $id_var);
$stmt->execute();
if($stmt->fetch()) {
// row found
} else {
// row not found
}
$stmt->closeCursor();

php mysqli get number of rows [duplicate]

I'm just wondering which method is the most effective if I'm literally just wanting to get the number of rows in a table.
$res = mysql_query("SELECT count(*) as `number` FROM `table1`");
$count = mysql_fetch_result($res,0,'number');
or
$res = mysql_query("SELECT `ID` FROM `table1`");
$count = mysql_num_rows($res);
Anyone done any decent testing on this?
mysql_query() transfers all result records from the MySQL into the php pcrocess before it returns (unlike mysql_unbufferd_query()). That alone would make the mysql_num_rows() version slower.
Furthermore for some engines (like MyISAM) MySQL can serve a Count(*) request from the index of the table without hitting the actual data. A SELECT * FROM foo on the other hand results in a full table scan and MySQL has to read every single dataset.
Test in database with more then 2300000 rows, type:InnoDB, size near 1 GiB, using xhprof
test1:
....SELECT COUNT(id) as cnt FROM $table_name....;
row= mysqli_fetch_assoc($res2);
echo $row['cnt'];
//result1:
1,144,106
1,230,576
1,173,449
1,163,163
1,218,992
test2:
....SELECT COUNT(*) as cnt FROM $table_name....;
row= mysqli_fetch_assoc($res2);
echo $row['cnt'];
//result2:
1,120,253
1,118,243
1,118,852
1,092,419
1,081,316
test3:
....SELECT * FROM $table_name....;
echo mysqli_num_rows($res2);
//result3:
7,212,476
6,530,615
7,014,546
7,169,629
7,295,878
test4:
....SELECT * FROM $table_name....;
echo mysqli_num_rows($res2);
//result4:
1,441,228
1,671,616
1,483,050
1,446,315
1,647,019
conclusion:
The fastest method is in the test2 :
....SELECT COUNT(*) as cnt FROM $table_name....;
row= mysqli_fetch_assoc($res2);
echo $row['cnt'];
Definitely the first. MySQL can usually do this by looking at an index rather than the whole table, and if you use MyISAM (the default), the row count for the table is stored in the table metadata and will be returned instantly.
Your second method will not only read the entire table into memory but also send it to the client through the network before the client counts the rows. Extremely wasteful!
I don't really think any testing is needed.
Doing the COUNT in the SQL query
1) Sends only one row of data back the
to client (instead of every row)
2) Lets SQL do the count
for you which is likely always going
to be faster than PHP.
I guess count(1) will be even faster:
$res = mysql_query("SELECT count(1) as `number` FROM `table1`");
$count = mysql_fetch_result($res,0,'number');
Although haven't tried the proposed methods, the first makes database fetch all the records and count them in the database, the second makes database fetch a separate field for all the records and count the number of results on the server.
As a rule of thumb the less data you fetch for a particular record the less time it will take therefore I'd vote for updated first method (fetching constant for every record and counting the number of constants fetched).
Using Count with index and inodb makes it too much slow, but when use it with mysqli_num_rows it returns without any delay. you can check mysqli_num_rows result at http://ssajalandhar.org/generalinstruction-0-1-0.html it wouldn't take fraction of second to load. For me mysqli works awesome.

Count rows from results of a "mysql_query"

If I have this:
$results = mysql_query("SELECT * FROM table_name WHERE id=$id");
is there then any way to check how many rows which have a field-value of "Private" or "Company" ?
I need to show the user how many "Private" and "Company" records where found, without making another query. (There is a column called 'ad_type' which contains either "private" or "company")
I already know the mysql_num_rows for counting all rows!
EDIT:
There are 500thousand records! So maybe an iteration through the result is slow, what do you think?
Thanks for all help :)
The above answers are great and all, but the currently checked answer will work very inefficiently should you be dealing with a large amount of data
Example of the above answer (via Gal)
$results = mysql_query("SELECT *,(SELECT COUNT(*) FROM table_name WHERE column=$value) count FROM table_name WHERE id=$id");
It's good and all, and it returns what you need but the obvious design flaw is that making your SQL server return the results then re-return them and look at just the count is very inefficient for large amounts of data.
Simply do this:
$results = mysql_query("SELECT * FROM table_name WHERE column=$value");
$num_rows = mysql_num_rows($result);
It will yield the same results and be much more efficient in the long run, additionally for larger amounts of data.
You can do something like:
$results = mysql_query("SELECT *,(SELECT COUNT(*) FROM table_name WHERE column=$value) count FROM table_name WHERE id=$id");
in order to fetch the number with sql.
If you don't want to change your query you could do a
$results = mysql_query("SELECT * FROM table_name WHERE id=$id");
$count = mysql_num_rows($results);
steps to get a count():
use mysql_query() to get count,
use mysql_fetch_array() to get the only 1 row
get the only one column of the row, this is the count,
here is an example, which check whether the email is already used:
// check whether email used
$check_email_sql = "select count(*) from users where email='$email'";
$row = mysql_fetch_array(mysql_query($check_email_sql));
$email_count = $row[0];
Iterate through the result set of rows and count the number of occurences of Private and Company in ad_type, respectively?
You can do
SELECT COUNT(*) FROM table_name WHERE id=$id GROUP BY fieldvalue HAVING fieldvalue = "Private"
SELECT COUNT(*) FROM table_name WHERE id=$id GROUP BY fieldvalue HAVING fieldvalue = "Company"
but that would be another query. But if you process the data anyway, you could simply sum up the number of "Private" and "Company" rows after doing the query.
In the case you don't have to get all results, use this.
SELECT ad_type, COUNT(*)
FROM table_name
WHERE (id=$id)
GROUP BY ad_type
HAVING ((ad_type = 'Private') OR (ad_type = 'Company'))
If you still have to fetch all the records where id = $id, it won't work. But executing such a query (once) before fetching the real data should be more efficient than using a subquery.
I guess this query would do the job:
SELECT ad_type, count(*) FROM table_name WHERE id=$id GROUP BY ad_type;
I don't see any reason so far to use HAVING, since you probably want to show the user an overview of all the ad_type's found in DB (at least you didn't mention that there are other values for ad_type then the two given).
I also strongly suggest NOT to use sub-queries; always try to use just one.
If there's one thing that will slow your query down, it's a subquery (or subqueries).
Good luck!
Iterate through the results of the query and keep a count of how many of each show up in local variables.

Categories