Frage

I have table A which contains IP ranges (columns startIpNum, endIpNum, locId) and table A_location (column locaId and other not important columns). There are following indexes - startIpNum and endIpNum on A, and locId on A_location.

The problem is that sometimes queries are performed very slowly. Below there is a mysql-slow logfile, which contains two queries, bith of them return nothing.

# Time: 140001 21:18:45    
# User@Host: root[root] @ localhost [127.0.0.1]
# Query_time: 0.023001  Lock_time: 0.000000 Rows_sent: 0  Rows_examined: 0
SET timestamp=1394367480;
SELECT * FROM A_location AS location, (SELECT * FROM A WHERE (3998482191 BETWEEN startIpNum AND endIpNum) ORDER BY startIpNum DESC LIMIT 1) AS blocks WHERE location.locId = blocks.locId;

# Time: 140309 21:18:45
# User@Host: root[root] @ localhost [127.0.0.1]
# Query_time: 54.893140  Lock_time: 0.000000 Rows_sent: 0  Rows_examined: 0
SET timestamp=1394367525;
SELECT * FROM A_location AS location, (SELECT * FROM A WHERE (2463400155 BETWEEN startIpNum AND endIpNum) ORDER BY startIpNum DESC LIMIT 1) AS blocks WHERE location.locId = blocks.locId;

What could be the reason of such behaviour?

EXPLAIN results: Result for 3998482191 Result for 2463400155

UPDATE: The question was solved, final query

ALTER TABLE A ORDER BY startIpNum ASC;
SELECT A_location.* FROM A_location AS location,
(SELECT A.* FROM A as blocks,
(SELECT * FROM A WHERE startIpNum < 24465138 ORDER BY startIpNum DESC LIMIT 1) AS startipnumquery
WHERE blocks.startIpNum = startipnumquery.startIpNum AND blocks.endIpNum > 24465138
ORDER BY blocks.endIpNum ASC LIMIT 1) as subresult
WHERE location.locId = subresult.locId;
War es hilfreich?

Lösung

Your current query i have updated as below please run below query and check response time, i 99.99% sure it will giving to you best result

Step 1: ALTER TABLE A ORDER BY startIpNum DESC;


Step 2: SET timestamp=1394367480;
SELECT location.*, (SELECT * FROM A WHERE (3998482191 BETWEEN startIpNum AND endIpNum) LIMIT 1) AS blocks FROM A_location AS location, WHERE location.locId = blocks.locId;

Step 1: ALTER TABLE A ORDER BY startIpNum DESC;

Step 2: SET timestamp=1394367525;
SELECT location.*, (SELECT * FROM A WHERE (2463400155 BETWEEN startIpNum AND endIpNum) LIMIT 1) AS blocks FROM A_location AS location WHERE location.locId = blocks.locId;

i have just remove ORDER BY field DESC from your query and table alter with ALTER TABLE A ORDER BY startIpNum DESC;

Andere Tipps

Turn on profiling and be like Sherlock Holmes:

mysql> set profiling = 1;

mysql> select * from A;

mysql> show profiles;

Find your query (probably id is 1) and perform:

mysql> show profile for query 1;

I am not quite sure if you are trying to get the location with the highest startipnum, or all the locations and the highest startipnum for each of them.

You current queries seem to be doing unindexed searches through a very large number of records which will probably take a long time

For the first try this

SELECT location.*, A.*
FROM
(
    SELECT MAX(startIpNum) AS max_startIpNum
    FROM A 
    WHERE (2463400155 BETWEEN startIpNum AND endIpNum
) blocks
INNER JOIN A
ON A.startIpNum = blocks.max_startIpNum
INNER JOIN A_location AS location
ON A.locId = location.locId

This will rely on an index on startIpNum on the table A and an index on locid on the table A_location.

For the second try this:-

SELECT location.*, A.*
FROM A_location AS location
INNER JOIN
( 
    SELECT locId, MAX(startIpNum) AS max_startIpNum
    FROM A 
    WHERE (2463400155 BETWEEN startIpNum AND endIpNum
    GROUP BY locId
) blocks
ON location.locId = blocks.locId
INNER JOIN A
ON A.locId = blocks.locId
AND A.startIpNum = blocks.max_startIpNum

This will rely on an index covering locid and startIpNum on the table A, and an index on locid on the table A_location might well help

Try this one:

SELECT location.*, blocks.*
FROM A_location AS location 
join  A as blocks on (location.locId = blocks.locId)
WHERE startIpNum<=3998482191 AND endIpNum>=3998482191
group by block.locId
ORDER BY startIpNum DESC;

You should have only one composite index on A: A(startIpNum, endIpNum). It would seem that the second query is getting confused as to the best index to use.

The following rewrites the query to use an explicit join. This shouldn't have an impact on performance:

SELECT *
FROM (SELECT *
      FROM A
      WHERE 3998482191 BETWEEN startIpNum AND endIpNum
      ORDER BY startIpNum DESC
      LIMIT 1
     ) blocks join
     A_location location
     on location.locId = blocks.locId;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top