How to add an index to such sql query? - mysql

Please tell me how to add an index to this sql query?
SELECT *
FROM table
WHERE (cities IS NULL) AND (position_id = '2') AND (is_pub = '1')
ORDER BY ordering asc
LIMIT 1
Field types:
cities = text
position_id = int(11)
is_pub = tinyint(1)
I try so:
ALTER TABLE table ADD FULLTEXT ( 'cities', 'position_id', 'is_pub' );
But I get an error: The used table type doesn't support FULLTEXT indexes

First, rewrite the query so you are not mixing types. That is, get rid of the single quotes:
SELECT *
FROM table
WHERE (cities IS NULL) AND (position_id = 2) AND (is_pub = 1)
ORDER BY ordering asc
LIMIT 1;
Then, the best query for this is on table(position_id, is_pub, cities, ordering):
create index idx_table_4 on table(position_id, is_pub, cities(32), ordering);
The first three columns can be in any order in the index, so long as they are the first three.
You should change cities to a varchar() type. Is there is reason you want to use a text for this?

You need to change the engine for your table to MyISAM.
possible duplicate of #1214 - The used table type doesn't support FULLTEXT indexes

Related

Mysql - inner join with or condition taking long time mysql

Need help with MySQL query.
I have indexed mandatory columns but still getting results in 160 seconds.
I know I have a problem with Contact conditions without it results are coming in 15s.
Any kind of help is appreciated.
My Query is :
SELECT `order`.invoicenumber, `order`.lastupdated_by AS processed_by, `order`.lastupdated_date AS LastUpdated_date,
`trans`.transaction_id AS trans_id,
GROUP_CONCAT(`trans`.subscription_id) AS subscription_id,
GROUP_CONCAT(`trans`.price) AS trans_price,
GROUP_CONCAT(`trans`.quantity) AS prod_quantity,
`user`.id AS id, `user`.businessname AS businessname,
`user`.given_name AS given_name, `user`.surname AS surname
FROM cdp_order_transaction_master AS `order`
INNER JOIN `cdp_order_transaction_detail` AS trans ON `order`.transaction_id=trans.transaction_id
INNER JOIN cdp_user AS user ON (`order`.user_id=user.id OR CONCAT( user.id , '_CDP' ) = `order`.lastupdated_by)
WHERE `order`.xero_invoice_status='Completed' AND `order`.order_date > '2021-01-01'
GROUP BY `order`.transaction_id
ORDER BY `order`.lastupdated_date
DESC LIMIT 100
1. Index the columns used in the join, where section so that sql does not scan the entire table and only scans the desired columns. A full scan of the table works extremely badly.
create index for cdp_order_transaction_master table :
CREATE INDEX idx_cdp_order_transaction_master_transaction_id ON cdp_order_transaction_master(transaction_id);
CREATE INDEX idx_cdp_order_transaction_master_user_id ON cdp_order_transaction_master(user_id);
CREATE INDEX idx_cdp_order_transaction_master_lastupdated_by ON cdp_order_transaction_master(lastupdated_by);
CREATE INDEX idx_cdp_order_transaction_master_xero_invoice_status ON cdp_order_transaction_master(xero_invoice_status);
CREATE INDEX idx_cdp_order_transaction_master_order_date ON cdp_order_transaction_master(order_date);
create index for cdp_order_transaction_detail table :
CREATE INDEX idx_cdp_order_transaction_detail_transaction_id ON cdp_order_transaction_detail(transaction_id);
create index for cdp_user table :
CREATE INDEX idx_cdp_user_id ON cdp_user(id);
2. Use Owner/Schema Name
If the owner name is not specified, the SQL Server engine tries to find it in all schemas to find the object.

Why does this query doesn't use index for ORDER BY?

SELECT `f`.*
FROM `files_table` `f`
WHERE f.`application_id` IN(6)
AND `f`.`project_id` IN(130418)
AND `f`.`is_last_version` = 1
AND `f`.`temporary` = 0
AND f.deleted_by is null
ORDER BY `f`.`date` DESC
LIMIT 5
When I remove the ORDER BY, query executes in 0.1 seconds. With the ORDER BY it takes 3 seconds.
There is an index on every WHERE column and there is also an index on ORDER BY field (date).
What can I do to make this query faster? Why is ORDER BY slowing it down so much? Table has 3M rows.
instead of an index on each column in where be sure you have a composite index that cover all the columns in where
eg
create index idx1 on files_table (application_id, project_id,is_last_version,temporary,deleted_by)
avoid IN clause for single value use = for these
SELECT `f`.*
FROM `files_table` `f`
WHERE f.`application_id` = 6
AND `f`.`project_id` = 130418
AND `f`.`is_last_version` = 1
AND `f`.`temporary` = 0
AND f.deleted_by is null
ORDER BY `f`.`date` DESC
LIMIT 5
the date or others column in select could be useful retrive all info using the index and avoiding the access to the table data .. but for select all (select *)
you probably need severl columns an then the access to the table data is done however .. but you can try an eval the performance ..
be careful to place the data non involved in where at the right of all the column involved in where
create index idx1 on files_table (application_id, project_id,is_last_version,temporary,deleted_by, date)

SELECT processing speed in SQL from element Position

I have 2 columns: column1 (id) is primary and column2 (title) is not primary (I mean contents of column2 can be repetitive in column2). Then I want to know the selecting speed is the same for the following two lines of code or not ?
Query #1:
SELECT *
FROM table
WHERE id = '$id' AND title = '$title';
Query #2:
SELECT *
FROM table
WHERE title = '$title' AND id = '$id';
Your two queries should have exactly the same execution plan. Both conditions are applied at the same time or at least in the same way.
If you want to optimize this query:
SELECT *
FROM table
WHERE id = '$id' AND title = '$title';
Then you can use an index:
create index idx_table_id_title on table(id, title)
Also, when writing queries in an application, you should use parameters for the queries rather than substituting values directly into the query string.

MySQL stops using index when additional constraints are added

Using EXPLAIN reveals that the following query does not use my index, could somebody please explain what is going on?
SELECT u.id AS userId, firstName, profilePhotoId, preferredActivityId, preferredSubActivityId, availabilityType,
3959 * ACOS(COS(radians(requestingUserLat)) * COS(radians(u.latitude)) * COS(radians(u.longitude) - radians(requestingUserLon)) + SIN(radians(requestingUserLat)) * SIN(radians(u.latitude))) AS distanceInMiles
FROM users u
WHERE u.latitude between lat1 and lat2 -- MySQL 5.7 supports Point data type, but it is not indexed in innoDB. I store latitude and longitude as DOUBLE for now
AND u.longitude between lon1 and lon2
AND u.dateOfBirth between maxAge and minAge -- dates are in millis, therefore maxAge will have a smaller value than minAge and so it needs to go first
AND IF(gender is null, TRUE, u.gender = gender)
AND IF(activityType is null, TRUE, u.preferredActivityType = activityType)
AND u.accountState = 'A'
AND u.id != userId
HAVING distanceInMiles < searchRadius ORDER BY distanceInMiles LIMIT pagingStart, pagingLength;
CREATE INDEX `findMatches` ON `users` (`latitude` ASC, `longitude` ASC, `dateOfBirth` ASC) USING BTREE;
The index is not used at all at this stage. To get it to work, I need to comment out a bunch of columns from the SELECT statement, and also removed any unindexed columns from the WHERE clause. The following works:
SELECT u.id AS userId --, firstName, profilePhotoId, preferredActivityId, preferredSubActivityId, availabilityType,
3959 * ACOS(COS(radians(requestingUserLat)) * COS(radians(u.latitude)) * COS(radians(u.longitude) - radians(requestingUserLon)) + SIN(radians(requestingUserLat)) * SIN(radians(u.latitude))) AS distanceInMiles
FROM users u
WHERE u.latitude between lat1 and lat2 -- MySQL 5.7 supports Point data type, but it is not indexed in innoDB. We store latitude and longitude as DOUBLE for now
AND u.longitude between lon1 and lon2
AND u.dateOfBirth between maxAge and minAge -- dates are in millis, therefore maxAge will have a smaller value than minAge and so it needs to go first
-- AND IF(gender is null, TRUE, u.gender = gender)
-- AND IF(activityType is null, TRUE, u.preferredActivityType = activityType)
-- AND u.accountState = 'A'
-- AND u.id != userId
HAVING distanceInMiles < searchRadius ORDER BY distanceInMiles LIMIT pagingStart, pagingLength;
Other things I tried:
I tried creating 3 distinct single-part indexes, in addition to my multi-part index that contains all 3 keys. Based on the docs here, shouldn't the optimizer merge them by creating a UNION of their qualifying rows, further speeding up execution? It's not doing it, it still selects the multi-part (covering) index.
Any help greatly appreciated!
This is a little difficult to explain.
The query that uses the index is using it because the index is a "covering" index. That is, all the column in the index are in the query. The only part of the index really being used effectively is the condition on latitude.
Normally a covering index would have only the columns mentioned in the query. However, the primary key is used to reference the records, so I'm guessing that users.Id is the primary key on the table. And the index is being scanned for valid values of latitude.
The query that is not using the index is not using it for two reasons. First, the conditions on the columns are inequalities. An index seek can only use equality conditions and one inequality. That means the index could only be used for latitude in its most effective method. Second, the additional columns in the query require going to the data page anyway.
In other words, the optimizer is, in effect, saying: "Why bother going to the index to scan through the index and then scan the data pages? Instead, I can just scan the data pages and get everything all at once."
Your next question is undoubtedly: "But how do I make my query faster?" My suggestion would be to investigate spatial indexes.

How do you combine these 3 mySQL queries into one?

The schematic code of what I am trying to do:
INPUT VAR inputOne; (First input of the desired statement)
INPUT VAR inputTwo; (Second input of the desired statement)
INPUT VAR inputThree; (Third input of the desired statement)
-
VAR repResult = getResult("SELECT * FROM `representatives` WHERE `rID` = inputOne LIMIT 1;")
VAR evResult = getResult("SELECT `events`.`eID` FROM `events` WHERE `eventDateTime` = inputTwo LIMIT 1;")
if (repResult != null && evResult != null) {
execureQuery("INSERT INTO `votes` (`representatives_rID`, `events_eID`, `voteResult`) VALUES(inputOne,evResult.eID,inputThree);");
}
It is quite slow, when I execute them in separated statement, especially because there are ~1.000.000 that needs to be checked and inserted.
I was wondering, if there is any alternative, one-query way of doing this.
You can use INSERT-SELECT syntax to accomplish this:
INSERT INTO `votes` (`representatives_rID`, `events_eID`, `voteResult`)
select inputOne, `events`.`eID`, inputThree FROM `events` WHERE `eventDateTime` = inputTwo LIMIT 1
The above combines all three params into one INSERT-SELECT statement where the results of the select are sent to the insert.
See: Insert into ... values ( SELECT ... FROM ... ) for select-insert statement.
Yes, you can put these statements into 1 Stored Procedure (which returns 2 resultsets and performs 1 insert), but no, this probably wouldn't help. Because 3 SQL statements are not a big amount of network traffic, and because Stored Procedures are slow in MySQL.
Is rID a primary key? Does the first query extract big fields you don't really need?
Is there a unique index on eventDateTime? If the table is not InnoDB, the index should explicitly include eID, so it becomes a covering index.
After making those keys, you can drop LIMIT 1.
Are rID and eID datatypes as small as possible?