我有一个很大的MySQL表,即使正确编制索引,每次查询也需要1秒钟(听起来不是很多,但它运行的是数千台服务器)。现在,我有四个查询通过获得第95百分位入站,第95百分位出站,以及两者的总和。
查询1:获取行数以获得第95百分位行
SELECT round(count(*)*.95 FROM traffic WHERE server_id = 1;
查询2& 3获得第95个百分点
SELECT inbound FROM traffic WHERE server_id = 1 ORDER BY inbound ASC LIMIT {95th},1
SELECT outbound FROM traffic WHERE server_id = 1 ORDER BY outbound ASC LIMIT {95th},1
查询4获取流量总和
SELECT sum(inbound+outbound) FROM traffic WHERE server_id = 1;
你能想到我可以将这些结合起来吗?因为我需要获得第95个百分位,所以通过根据计数选择特定行来计算,我被挑战想到一种方法。例如,如果有10000行,则按升序排序并选择第9500行。
答案 0 :(得分:3)
如果您愿意放弃一些精度,可以使用估计行数而不是精确行数。如果您的数据库使用InnoDB,SELECT count(*)
可能会非常慢。换句话说:
要估算,您可以使用SHOW TABLE STATUS
命令。它会快速闪电,但不一定100%准确。
替换您的陈述:
SELECT inbound FROM traffic WHERE server_id = 1 ORDER BY inbound ASC LIMIT {95th},1
与
SELECT inbound FROM traffic WHERE server_id = 1 ORDER BY inbound DESC LIMIT {5th},1
结果应该相同,但速度要快20倍。只需确保在(server_id, inbound)
上创建复合索引。
见2.
不管这个。
我希望获得必要数字的总时间将减少到几毫秒。
答案 1 :(得分:2)
如http://planet.mysql.com/entry/?id=13588中所述:
SELECT
SUBSTRING_INDEX(
SUBSTRING_INDEX(
GROUP_CONCAT(
t.inbound
ORDER BY t.inbound
SEPARATOR ','
)
, ','
, 95/100 * COUNT(*) + 1
)
, ','
, -1
) AS `Inbound95`
,
SUBSTRING_INDEX(
SUBSTRING_INDEX(
GROUP_CONCAT(
t.outbound
ORDER BY t.outbound
SEPARATOR ','
)
, ','
, 95/100 * COUNT(*) + 1
)
, ','
, -1
) AS `Outbound95`
FROM traffic AS t WHERE t.server_id = 1
会给你两个百分点
注意:您可能需要增加group_concat_max_len