is there any way to remove the MAX with something else, maybe the ASC LIMIT 1 to decrease database throttling? My query gets the maximum id and adds 1 to it.
This is my query:
$query = 'SELECT MAX(ID) +1 as maxidpost
FROM wp_posts';
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result)) {
echo 'p='. $row['maxidpost'];
}
mysql_close();
What does the database tell you about your query? If id is indexed then
mysql> explain select max(id) + 1 from times;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
1 row in set (0.18 sec)
mysql> explain select id from times order by id ASC limit 1;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | times | index | NULL | PRIMARY | 4 | NULL | 1 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.00 sec)
This is fine. adding limit 1 isn't going to give any noticeable performance improvements.
This shouldn't cause any kind of issues, are you having problems with this particular query?
The SQL MAX() function will automatically look for just one result. There's no need of LIMIT it in any way. If you want to improve that query try setting ID as index.
SELECT ID + as maxidpost FROM wp_posts ORDER BY ID DESC LIMIT 1;
or If the table have Auto_increment ID
SHOW TABLE STATUS LIKE 'wp_posts';
There should be a field called Auto_increment which should be exactly MAX(ID) + 1;
Related
Currently we are using a custom CI library to generate PDF files from documents which exist as database records in our database.
Each document is related to the contents (== rows) with a one-has-many relation. Each row has a number (field: row_span) to indicate how many lines it will use once it gets printed in the PDF.
Per PDF page that gets build, Rows needed for that page only are selected using a subquery:
$where = $this->docType."_id = ".$this->data['doc']->id." AND visible = 1";
$sql = "SELECT *,
(SELECT
sum(row_span) FROM app_".$this->docType."_rows X
WHERE X.position <= O.position
AND ".$where."
ORDER BY position ASC) 'span_total'
FROM app_".$this->docType."_rows O
WHERE ".$where."
HAVING span_total > ".(($i-1)*$this->maxRows)." AND span_total <= ".($i*$this->maxRows)." ORDER BY O.position ASC ";
$rows = $rows->query($sql);
In the code $i is the page number and $this->maxRows is loaded from the document template record which indicates how many available lines the PDF template has.
So when the SQL renders it might look like this for page 1 of an order with ID 834:
SELECT `app_order_rows`.*,
(SELECT SUM(`app_order_rows_subquery`.`row_span`) AS row_span
FROM `app_order_rows` `app_order_rows_subquery`
WHERE `app_order_rows_subquery`.`position` <= 'app_order_rows.position'
AND `app_order_rows_subquery`.`order_id` = 834
AND `app_order_rows_subquery`.`visible` = 1
ORDER BY `app_order_rows_subquery`.`position` asc) AS span_total
FROM (`app_order_rows`)
WHERE `app_order_rows`.`order_id` = 834
AND `app_order_rows`.`visible` = 1
HAVING span_total > 0
AND span_total <= 45
ORDER BY `app_order_rows`.`position` asc
And running this with EXPLAIN gives this as output:
+====+=============+=========================+======+===============+======+=========+======+======+=============================+===+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | |
+====+=============+=========================+======+===============+======+=========+======+======+=============================+===+
| 1 | PRIMARY | app_order_rows | ALL | NULL | NULL | NULL | NULL | 1809 | Using where; Using filesort | 1 |
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-----------------------------+---+
| 2 | SUBQUERY | app_order_rows_subquery | ALL | NULL | NULL | NULL | NULL | 1809 | Using where | 2 |
+====+=============+=========================+======+===============+======+=========+======+======+=============================+===+
This is working great, but... When we have large orders or invoices it renders the documents very slow. This might be due to the subquery.
Does anyone have an idea on how to do the same select without subquery? Maybe we will have to go for a whole new approach to select rows and build the PDF. We are open for suggestions ^^
Thanks in advance
------------------------------- edit ------------------------------
The EXPLAIN after index creation:
+====+=============+=========================+=======+===============+============+=========+=======+======+=============+===+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | |
+====+=============+=========================+=======+===============+============+=========+=======+======+=============+===+
| 1 | PRIMARY | app_order_rows | ref | index_main | index_main | 5 | const | 9 | Using where | 1 |
+----+-------------+-------------------------+-------+---------------+------------+---------+-------+------+-------------+---+
| 2 | SUBQUERY | app_order_rows_subquery | range | index_main | index_main | 10 | NULL | 1 | Using where | 2 |
+====+=============+=========================+=======+===============+============+=========+=======+======+=============+===+
As you confirmed in the comments, the tables have no indexes.
The immediate solution would be:
create index index_main on app_order_rows (order_id, position);
I'm working on an application with has millions of data, and I need to list all the data in a page. At first I was fetching all the data in a single query and the pagination was done in the client side. But that takes almost 15 minutes to load the complete set. So I changed the code for fetching 10 rows per request and the pagination was done on server side. But still the performance is not up to the mark. So what all things should do to get the data quickly or what is the best way to handle huge data.
My query to fetch data :
UPDATED :
SELECT w.work_order_id,
(SELECT CONCAT(user_fname, ' ', user_lname) FROM users WHERE user_id = w.created_by) AS created_by,
CASE w.assignee WHEN 0 THEN 'All' WHEN -1 THEN 'Unassigned' ELSE CONCAT(u.user_fname, ' ', u.user_lname) END AS assignee
FROM FiveVan_work_orders w
LEFT JOIN users u ON (u.user_id = w.assignee)
WHERE ( w.work_order_status != 'Deleted' && w.work_order_status != 'Closed') ORDER BY w.created_on DESC LIMIT 0,10;
I have created index for the pages and this is the result of explaining the query
+----+--------------------+-------+--------+-------------------+---------------+---------+-------------------------------+--------+------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+--------+-------------------+---------------+---------+-------------------------------+--------+------------------------------------------+
| 1 | PRIMARY | w | index | work_order_status | work_order_id | 790 | NULL | 340319 | Using where; Using index; Using filesort |
| 1 | PRIMARY | u | eq_ref | PRIMARY | PRIMARY | 4 | fivevan_loadtest.w.assignee | 1 | NULL |
| 2 | DEPENDENT SUBQUERY | users | eq_ref | PRIMARY | PRIMARY | 4 | fivevan_loadtest.w.created_by | 1 | NULL |
+----+--------------------+-------+--------+-------------------+---------------+---------+-------------------------------+--------+------------------------------------------+
WHERE ( w.work_order_status != 'Deleted' &&
w.work_order_status != 'Closed')
ORDER BY w.created_on DESC
If there is only one more value of work_order_status, then change that to
WHERE w.work_order_status = 'Open'
ORDER BY w.created_on DESC
and add
INDEX(work_order_status, created_on)
If there are multiple other values, the this may work (less well):
INDEX(created_on)
To get even better performance, you need to "remember where you left off" instead of using OFFSET. I discuss that in my pagination blog.
Why do this two queries return different result set when they have the same ORDER BY.
Only difference in query is that first time I user INNER JOIN an it takes about 5 seconds.
Second time I used LEFT JOIN and it took 0.05 seconds. In both cases they return exactly 43.000 rows, but tck.id order is different and I can't figure out why or in which way?
SELECT tck.*, acc.ac_name
FROM support_tickets tck
INNER JOIN support_ticket_accounts acc USING (id_support_ticket_account)
WHERE tck.id_company = 2 AND tck.st_status = 1 ORDER BY tck.st_priority DESC
Edit:
SELECT tck.*, acc.ac_name
FROM support_tickets tck
LEFT JOIN support_ticket_accounts acc ON tck.id_support_ticket_account = acc.id_support_ticket_account
WHERE tck.id_company = 2 AND tck.st_status = 1
ORDER BY tck.st_priority DESC;
+----+-------------+-------+--------+---------------+------------+---------+-------------------------------+-------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+------------+---------+-------------------------------+-------+-----------------------------+
| 1 | SIMPLE | tck | ref | id_company | id_company | 5 | const | 37586 | Using where; Using filesort |
| 1 | SIMPLE | acc | eq_ref | PRIMARY | PRIMARY | 4 | tck.id_support_ticket_account | 1 | |
+----+-------------+-------+--------+---------------+------------+---------+-------------------------------+-------+-----------------------------+
SELECT tck.*, acc.ac_name
FROM support_tickets tck
INNER JOIN support_ticket_accounts acc ON tck.id_support_ticket_account = acc.id_support_ticket_account
WHERE tck.id_company = 2 AND tck.st_status = 1
ORDER BY tck.st_priority DESC;
+----+-------------+-------+------+-------------------------------------+----------------------------+---------+-------------------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+--------------------------------------+---------------------------+---------+-------------------------------+------+---------------------------------+
| 1 | SIMPLE | acc | ALL | PRIMARY | NULL | NULL | NULL | 5 | Using temporary; Using filesort |
| 1 | SIMPLE | tck | ref | id_company,id_support_ticket_account | id_support_ticket_account | 5 | acc.id_support_ticket_account | 2085 | Using where |
+----+-------------+-------+------+--------------------------------------+---------------------------+---------+-------------------------------+------+---------------------------------+
I think using temporary is responsible for the delay (but I don't see why it's necessary for one query and not the other one). I think creating multi-column index should help:
CREATE INDEX filter
ON support_tickets(id_company, st_status, st_priority)
USING BTREE;
If you just ORDER BY tck.st_priority DESC multiple different recordsets are posible and can be returned, for each of both cases (left or inner). That is because you must have a lot of records that has the same st_priority so any of them can came in no particular order
Add more fields to the order by clause to give any record unique possible position and you will have same order on both querys.
I have a query in my PHP where I'm searching for string:
select * from feed1 where PNAME like '%clothes%' limit 5;
I also want to get count of PNAME like cloth for which I'm using separate search query:
$qry=mysqli_query(select * from feed1 where PNAME like '%clothes%');
$rows=mysqli_num_rows($qry);
Rows query is taking too much time to load the page. Is there any way we can get total row count and limit of up to 5 products from one query? Thereby, the load time will decrease.
+-------+------------+----------+--------------+-------------+-----------+------
-------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardi
nality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+------
-------+----------+--------+------+------------+---------+---------------+
| xml | 0 | PRIMARY | 1 | BOSID | A |
7233 | NULL | NULL | | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+------
-------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
You can't do this by one query, but for get count, use COUNT(*) instead of get all the data out.
To get the count:
select count(*) from feed1 where PNAME like '%clothes%'
then get first 5:
select * from feed1 where PNAME like '%clothes%' limit 5
There should be at least two queries for pagination.
how to get all the record from Mysql by supplying month in the query?
i am working in php project and i have a mysql table for posts in which all the posts are saved with their dates(not the publish date or post date but any random date).
now i am selecting the month from the front end and querying for the posts for the given month.
how to retrieve the posts that are in between that month ?
You could use MySQL's MONTH() function
SELECT * FROM tbl WHERE MONTH( date_col ) = 3
You can use MONTHName() function to check the data with the name of month you selected rom front-end.
SELECT * FROM tablename WHERE MONTHNAME(date_column) = "March"
you can fire this query
Select * from table where Date =>'$date1' and Date = '$date2'
to find data between any two dates
you can add where condition as
WHERE YEAR(col_name_of_date) = 2014 AND MONTH(Date) = 4";
or
WHERE YEAR(col_name_of_date) = YEAR(now()) AND MONTH(Date) = 4";
This will need the column col_name_of_date to be in DATE or DATETIME type.
Also you should avoid this kind of DATE() function since its a load to the mysql server.
Its better to construct the date parameter on PHP side before u pass them to query. If you
know the moth start and end and can easily construct the start and end date in Y-m-d format. For the start date d is always 01 and for the end date its the last day of the month.
Check how the query behaves using DATE() and without date
I have a table users where regdate is not indexed
explain select count(*) from users where year(regdate) = year(now()) and month(regdate) = 01 ;
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 79309 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+-------+-------------+
As u can see num of rows it may scan is the upper limit of the table.
Now lets add an index
mysql> alter table users add index `u_regdate_idx`(`regdate`) ;
Query OK, 79309 rows affected (1.44 sec)
Records: 79309 Duplicates: 0 Warnings: 0
Now run the same again
mysql> explain select count(*) from users where year(regdate) = year(now()) and month(regdate) = 01 ;
+----+-------------+-------+-------+---------------+---------------+---------+------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+-------+--------------------------+
| 1 | SIMPLE | users | index | NULL | u_regdate_idx | 4 | NULL | 79309 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------------+---------+------+-------+--------------------------+
As u can see there is no change in the performance.
Now lets change the query and see
mysql> explain select count(*) from users where regdate between '2014-01-01' AND '2014-01-31' ;
+----+-------------+-------+-------+---------------+---------------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+--------------------------+
| 1 | SIMPLE | users | range | u_regdate_idx | u_regdate_idx | 4 | NULL | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+--------------------------+
Now u can see its far better.