Mysql doesn't use index - mysql

I tried to make indexes on my table. But First mysql uses it then that doesn't use the index.
It is my table indexes.
enter image description here
My Query.
EXPLAIN SELECT
COUNT(DISTINCT K.bayiid) AS toplam,
SUM(K.tutar) AS yatirilan,
SUM(IF(K.durum='2', K.tutar*K.toplam,0)) AS kazanc,
SUM(IF(K.durum='-1', K.tutar, 0)) AS kayip,
SUM(IF(K.durum='1', K.tutar,0)) AS devam,
SUM(IF(K.durum='0', K.tutar,0)) AS iptal,
SUM(1) AS oynanan,
SUM(IF(K.durum='2', 1,0)) AS kazanan,
SUM(IF(K.durum='-1', 1,0)) AS kaybeden,
SUM(IF(K.durum='1', 1,0)) AS devameden,
SUM(IF(K.durum='0', 1,0)) AS iptalolan,
U.*
FROM kuponlar AS K
INNER JOIN users AS U ON U.id = K.bayiid AND U.durum != '4' AND U.id = '26689'
WHERE K.durum < 3 AND K.tarih >= '2016-12-01 00:00:00' AND K.tarih <= '2016-12-31 23:59:59'
Query explaination
enter image description here
But i don't want to use USE INDEX or FORCE INDEX. Do you have any idea why mysql works unstable?

ON U.id = K.bayiid
AND U.durum != '4'
AND U.id = '26689'
For clarity, move the last 2 parts to WHERE; leave only the condition(s) that defines the JOIN.
WHERE K.durum < 3
AND K.tarih >= '2016-12-01 00:00:00'
AND K.tarih <= '2016-12-31 23:59:59'
Suggestion: For date ranges, do something like this:
AND K.tarih >= '2016-12-01'
AND K.tarih < '2016-12-01' + INTERVAL 1 MONTH
For K, have
INDEX(bayiid, darum)
INDEX(bayiid, tarih)
(Without knowing the distribution of the data, I cannot predict which is better. The Optimizer will choose.)
If you want to discuss this further, please provide SHOW CREATE TABLE for each table. If there happen to be datatype inconsistencies, that could cause a lot of trouble, and we cannot see it without the SHOW.
Indexing cookbook

Related

MySQL, how to get time difference between rows

I'm trying to get time difference between rows. I tried this but it's not working.
SELECT id,locationDate,
TIMESTAMPDIFF(SECOND,
(SELECT MAX(locationDate) FROM location WHERE locationDate< t.locationDate),
created_at
) as secdiff
FROM location t where tagCode = 24414 AND locationDate >= '2017-05-10 16:00:01' and locationDate <= '2017-05-10 16:59:59';
What should I do for calculating time difference between rows ?
You can reach the sample structure and data from sqlfiddle
I am guessing you just want a correlated subquery:
select l.id, l.locationDate,
TIMESTAMPDIFF(SECOND,
(SELECT MAX(l2.locationDate)
FROM location l2
WHERE l2.locationDate < l.locationDate AND
l2.tagCode = l.tagCode
),
locationDate
) as secdiff
from location l
where l.tagCode = 24414 and
l.locationDate > '2017-05-10 16:00:00' and
l.locationDate < '2017-05-10 17:00:00';
I modified the date/time constants to be a bit more reasonable (from my perspective). If you really care about one second before or after a time, then you can use your original formulation.

How to get latest results by date when selecting from two table?

I have two tables and I would like to join then with a query.
result save the actual entry of results
user_tracking tracks the acceptance and completion of work, users can cancel and accepts work again at a later time.
SELECT *
from
svr1.result r,
svr1.user_tracking u
where
r.uid = u.user_id and r.tid = u.post1
and u.function_name = '7' #7 == accept work
and r.insert_time > '2015-09-23 00:00:00' and r.insert_time < '2015-10-03 00:00:00'
and u.track_time > '2015-09-23 00:00:00' and u.track_time < '2015-10-03 00:00:00'
my result table had 1785 records within the period I wanted to track
but the above query returns 1990 records. I would like to know how can i filter to get the latest date accepted by user only.
in result table: uid,INT, tid,INT, result,VARCHAR and insert_time,TIMESTAMP
in user_tracking table: user_id,INT, post1,VARCHAR function_name,VARCHAR, result,VARCHAR and track_time,TIMESTAMP
the user_tracking function sample records, in this query the track time will change and the rest will remain the same.
Use the GROUP BY command with a MAX() on the required date, this will select the latest date of all the options (assuming all the other columns are equal). Code as follows (need to declare all columns because of the MAX unfortunately):
SELECT r.uid,
r.tid,
r.result,
r.insert_time,
u.user_id,
u.post1,
u.function_name,
u.result,
MAX(track_time)
FROM
svr1.result r,
svr1.user_tracking u
WHERE
r.uid = u.user_id AND r.tid = u.post1
AND u.function_name = '7' #7 == accept work
AND r.insert_time > '2015-09-23 00:00:00' AND r.insert_time < '2015-10-03 00:00:00'
AND u.track_time > '2015-09-23 00:00:00' AND u.track_time < '2015-10-03 00:00:00'
GROUP BY
r.uid,
r.tid

MySQL aggregation

Hi all I am trying to aggregate the number of searches that clients are doing. I currently have this working for 1 day. I would also like to put in a column for searches for that week, month, year and total
USE live_travelcoglog;
SELECT lu.Name, lu.UID, IFNULL(l.AgentId, 'CP Total') AS "CP", COUNT(*) AS "DateTotal", MAX(l.Submitted) AS "LastSearchTime"
FROM logs l INNER JOIN live_travelcog.users lu ON l.ChannelPartnerId = lu.CustId
WHERE Submitted BETWEEN '2014-04-23 00:00:00' AND '2014-04-23 23:59:59'
AND l.MessageType = 'COG_HotelAvail_RS'
GROUP BY lu.Name, l.AgentId ASC WITH ROLLUP;
Now I can run the queries for the different values that I am after but I am sure there is a nicer way that they can all be grouped together. If someone could kindly point me in the right direction it would be greatly appreciated.
Thanks
Daz
Is this the sort of thing you were looking for?
USE live_travelcoglog;
SELECT
lu.Name,
lu.UID,
IFNULL(l.AgentId, 'CP Total') AS "CP",
SUM(Submitted BETWEEN '2014-04-23 00:00:00' AND '2014-04-23 23:59:59') AS DateTotal,
SUM(Submitted BETWEEN '2014-04-17 00:00:00' AND '2014-04-23 23:59:59') AS WeekTotal,
SUM(Submitted BETWEEN '2014-04-01 00:00:00' AND '2014-04-23 23:59:59') AS MonthTotal,
MAX(l.Submitted) AS "LastSearchTime"
FROM logs l
INNER JOIN live_travelcog.users lu
ON l.ChannelPartnerId = lu.CustId
WHERE
l.MessageType = 'COG_HotelAvail_RS'
GROUP BY
lu.Name,
l.AgentId ASC
WITH ROLLUP;

using multiple where cause in mysql

I have a table where I want to retreive data every hourly from database in report format.
like
username 8-9 9-10 10-11
====================================
kiran 20 27 33
Ram 25 23 44
Can we get like this in mysql please help.
select username,count(message) as '8-9' from customer_1.audit_trail
inner join inteliviz.users
on customer_1.audit_trail.user_id = inteliviz.users.id inner join
customer_1.carparks on customer_1.carparks.id = customer_1.audit_trail.location_id
where datetime>'2013-08-27 08:00:00' and datetime<'2013-08-27 09:00:00'
group by username limit 1000;
I think you are looking for conditional aggregation:
select username,
sum(datetime >= '2013-08-27 08:00:00' and datetime < '2013-08-27 09:00:00') as "8-9",
sum(datetime >= '2013-09-27 08:00:00' and datetime < '2013-08-27 10:00:00') as "9-10",
sum(datetime >= '2013-08-27 10:00:00' and datetime < '2013-08-27 11:00:00') as "10-11"
from customer_1.audit_trail t inner join
inteliviz.users u
on t.user_id = 8.id inner join
customer_1.carparks cp
on cp.id = t.location_id
group by username
limit 1000;
I also added table aliases to make the query easier to read. And, I changed the single quotes in column aliases to double quotes. It is a good idea to stick to using single quotes for strings and double quotes for aliases (which is consistent with the standard).
try using >= and <=
select username,count(message) as '8-9' from customer_1.audit_trail
inner join inteliviz.users on customer_1.audit_trail.user_id = inteliviz.users.id
inner join customer_1.carparks on customer_1.carparks.id = customer_1.audit_trail.location_id
where datetime>='2013-08-27 08:00:00' and datetime<='2013-08-27 09:00:00'
group by username limit 1000;
your current one looks between 01 and 59
edit:
http://www.artfulsoftware.com/infotree/queries.php#78
you want to be doing something like that and then grouping by hour(datetime)

MySQL efficiency / best practice of using subqueries versus the same calculations multiple times

What's the best practice of using subqueries versus calculations multiple times? I've used subqueries until now, but they seem so ridiculous to have when you just need a variable calculated from the previous query (in the following example we're talking about a query with a subquery with a subquery).
So which is the right / best practice method? Personally, being a programmer, everything in me tells me to use method a, seeing as it seems stupid to copy paste calculations, but at the same time, subqueries aren't always good seeing as it can make the query use filesort instead of index sorts (correct me if I'm wrong in this, please).
Method a - subqueries:
SELECT
tmp2.*
FROM
(
SELECT
tmp.*,
(NOW() < tmp.expire_time) as `active`
FROM
(
SELECT
tr.orderid,
tr.transactiontime,
pa.months as `months`,
DATE_ADD(tr.transactiontime, INTERVAL pa.months MONTH) as `expire_time`
FROM
`transactions` as `tr`
INNER JOIN
`packages` as `pa`
ON
tr.productid = pa.productid
WHERE
tr.isprocessed = '1'
ORDER BY
tr.transactiontime ASC
) as `tmp`
) as `tmp2`
WHERE
tmp2.active = 1
Explain:
Method b - reusing calculations:
SELECT
tr.orderid,
tr.transactiontime,
pa.months as `months`,
DATE_ADD(tr.transactiontime, INTERVAL pa.months MONTH) as `expire_time`,
(NOW() < DATE_ADD(tr.transactiontime, INTERVAL pa.months MONTH)) as `active`
FROM
`transactions` as `tr`
INNER JOIN
`packages` as `pa`
ON
tr.productid = pa.productid
WHERE
tr.isprocessed = '1'
AND
(NOW() < DATE_ADD(tr.transactiontime, INTERVAL pa.months MONTH))
ORDER BY
tr.transactiontime ASC
Explain:
Notice how DATE_ADD(tr.transactiontime, INTERVAL pa.months MONTH) is repeated 3 times, and (NOW() < DATE_ADD(tr.transactiontime, INTERVAL pa.months MONTH)) is repeated 2 times.
With the EXPLAINs it seems that method B is much better, but I still dislike the fact that it has to do the same calculation 3 times (I'm assuming it does this, and doesn't save the result and replace all instances itself.).
You should look at MySQL's EXPLAIN command:
http://dev.mysql.com/doc/refman/5.0/en/explain.html
which tells you how MySQL executes the queries.