我的表 A 包含IP范围(列startIpNum,endIpNum,locId)和表 A_location (列locaId和其他非重要列)。有以下索引 - A上的startIpNum和endIpNum,以及A_location上的locId。
问题是有时查询执行得非常慢。下面是一个mysql-slow日志文件,它包含两个查询,其中没有返回任何内容。
# 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;
这种行为可能是什么原因?
EXPLAIN结果:
更新: 问题解决了,最终查询
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;
答案 0 :(得分:3)
您当前的查询我已更新如下,请运行以下查询并检查响应时间,我99.99%肯定会给您最好的结果
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;
我刚从您的查询和表格中删除 ORDER BY字段DESC ,并使用 ALTER TABLE A ORDER BY startIpNum DESC;
答案 1 :(得分:0)
打开简介并像Sherlock Holmes一样:
mysql> set profiling = 1;
mysql> select * from A;
mysql> show profiles;
找到您的查询(可能是id为1)并执行:
mysql> show profile for query 1;
答案 2 :(得分:0)
我不太确定您是否正在尝试获取具有最高startipnum的位置,或者所有位置以及每个位置的最高startipnum。
您当前的查询似乎是通过大量记录进行无索引搜索,这可能需要很长时间
第一次尝试这个
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
这将依赖于表A上的startIpNum索引和表A_location上的locid索引。
第二次试试这个: -
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
这将依赖于表A上覆盖locid和startIpNum的索引,并且表A_location上的locid索引可能很有帮助
答案 3 :(得分:0)
试试这个:
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;
答案 4 :(得分:0)
A
上应该只有一个综合索引:A(startIpNum, endIpNum)
。似乎第二个查询对使用的最佳索引感到困惑。
以下内容将重写查询以使用显式join
。这不应该对绩效产生影响:
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;