MySQL 针对大型 myisam 的优化 table
MySQL optimization for large myisam table
OS=centos 6.7 [Dedicated server]
memory=15G
cpu=Intel(R) Xeon(R) CPU E5-2403
mysql= V 5.1.73
这是一个 MyISAM table,包含大约 500 万行数据。每 5-6 分钟插入大约 3000 个用户的数据(例如上传和下载速率、会话状态等)。
Table 信息:描述“radacct”
my.cnf
来自mysql 慢查询日志下面是花费时间最多的查询之一
Query_time: 7.941773 Lock_time: 0.155912 Rows_sent: 1 Rows_examined: 5377
use freeradius;
SET timestamp=1461582118;
SELECT sum(acctinputoctets) as upload,
sum(acctoutputoctets) as download
FROM radacct a
INNER JOIN (SELECT acctuniqueid, MIN( radacctid ) radacctid
FROM radacct
WHERE username='batman215'
and acctstarttime between '2016-02-03 12:10:47'
and '2016-04-25 16:46:01'
GROUP BY acctuniqueid) b
ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid;
解释查询输出
当有许多用户试图查看他们消耗的带宽时,由于高负载和 IO,服务器无法满足请求。
我可以做些什么来进一步优化数据库吗?
来自 table“radacct”的索引
不使用 \G
解释查询
谢谢
让我们从您的内部查询开始解决这个问题,即:
SELECT acctuniqueid,
MIN( radacctid ) radacctid
FROM radacct
WHERE username='batman215'
and acctstarttime between '2016-02-03 12:10:47'
and '2016-04-25 16:46:01'
GROUP BY acctuniqueid
您正在寻找 username
上的相等匹配和 acctstarttime
上的范围匹配。然后,您将使用 acctuniqueid
进行分组并从 radacctid
.
中提取极值 (MIN()
)
因此,要加速这个子查询,需要下面的复合索引。
(username, acctstarttime, acctuniqueid, radacctid)
这是如何工作的?将索引(这些是 BTREE 索引)视为其中值的排序列表。
- 查询引擎随机访问列表——快速,O(log(n))——找到第一个条目匹配
username
和你的 BETWEEN
范围的低端。
- 然后按顺序逐条扫描列表,直到到达
BETWEEN
范围的高端。这称为 索引范围扫描 .
- 扫描时,它会按顺序查找
acctuniqueid,
的每个新值,然后取 radacctid
的最低值——按顺序排列的第一个值,然后跳到accuniqueid
的下一个值。这就是所谓的 松散索引扫描 并且它的成本低得惊人。
所以,添加那个复合索引。这可能会对您的查询性能产生重大影响。
您的外部查询如下所示。
SELECT sum(acctinputoctets) as upload,
sum(acctoutputoctets) as download
FROM radacct a
INNER JOIN ( /*an aggregate
* yielding acctuniqueid and raddactid
* naturally ordered on those two columns
*/
) b ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid
为此你需要复合覆盖指数
(acctuniqueid, radacctid, acctinputoctets, acctoutputoctets)
这部分查询对index magic也很满意
- 索引中的前两列允许根据内部查询的结果查找您需要的每一行。
- 然后查询引擎可以扫描将其他两列的值相加的索引。
(这称为 覆盖 索引,因为它包含一些列,这些列的存在只是因为我们需要它们的值,而不是因为我们希望它们被索引。其他一些品牌和型号的DBMS 允许在索引中包含额外的列而不使它们可搜索。这要便宜一些,尤其是在 INSERT
操作上。MySQL 不会那样做。)
因此,您的第一个行动项目:添加这两个复合索引并重试您的查询。
从您的问题看来,您在 table 上放置了很多单列索引,希望它们能加快速度。这是数据库设计中臭名昭著的反模式。尊重,你应该摆脱任何你不知道你需要的索引。它们无助于查询,而且会减慢 INSERTS
。这是你的第二个行动项目。
第三,去读这个http://use-the-index-luke.com/很有帮助。
专业提示:您看到我如何格式化您的查询了吗?当您必须理解一个查询时,制定一个清晰显示 table s、列、ON
条件和查询的其他方面的个人格式约定非常重要。
WHERE username='batman215'
and acctstarttime between ...
按顺序请求 INDEX(username, acctstarttime)
。
ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid;
求 INDEX(acctuniqueid, radacctid)
(任意顺序)(或 Ollie 的覆盖索引)。
"In every 5-6 minutes data for about 3000 users is inserted" 请求 InnoDB 而不是 MyISAM。 MyISAM 执行 table 锁,从而使 'insert' 干扰其他查询。 Conversion tips.
OS=centos 6.7 [Dedicated server]
memory=15G
cpu=Intel(R) Xeon(R) CPU E5-2403
mysql= V 5.1.73
这是一个 MyISAM table,包含大约 500 万行数据。每 5-6 分钟插入大约 3000 个用户的数据(例如上传和下载速率、会话状态等)。
Table 信息:描述“radacct”
my.cnf
来自mysql 慢查询日志下面是花费时间最多的查询之一
Query_time: 7.941773 Lock_time: 0.155912 Rows_sent: 1 Rows_examined: 5377
use freeradius;
SET timestamp=1461582118;
SELECT sum(acctinputoctets) as upload,
sum(acctoutputoctets) as download
FROM radacct a
INNER JOIN (SELECT acctuniqueid, MIN( radacctid ) radacctid
FROM radacct
WHERE username='batman215'
and acctstarttime between '2016-02-03 12:10:47'
and '2016-04-25 16:46:01'
GROUP BY acctuniqueid) b
ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid;
解释查询输出
当有许多用户试图查看他们消耗的带宽时,由于高负载和 IO,服务器无法满足请求。 我可以做些什么来进一步优化数据库吗?
来自 table“radacct”的索引
不使用 \G
解释查询谢谢
让我们从您的内部查询开始解决这个问题,即:
SELECT acctuniqueid,
MIN( radacctid ) radacctid
FROM radacct
WHERE username='batman215'
and acctstarttime between '2016-02-03 12:10:47'
and '2016-04-25 16:46:01'
GROUP BY acctuniqueid
您正在寻找 username
上的相等匹配和 acctstarttime
上的范围匹配。然后,您将使用 acctuniqueid
进行分组并从 radacctid
.
MIN()
)
因此,要加速这个子查询,需要下面的复合索引。
(username, acctstarttime, acctuniqueid, radacctid)
这是如何工作的?将索引(这些是 BTREE 索引)视为其中值的排序列表。
- 查询引擎随机访问列表——快速,O(log(n))——找到第一个条目匹配
username
和你的BETWEEN
范围的低端。 - 然后按顺序逐条扫描列表,直到到达
BETWEEN
范围的高端。这称为 索引范围扫描 . - 扫描时,它会按顺序查找
acctuniqueid,
的每个新值,然后取radacctid
的最低值——按顺序排列的第一个值,然后跳到accuniqueid
的下一个值。这就是所谓的 松散索引扫描 并且它的成本低得惊人。
所以,添加那个复合索引。这可能会对您的查询性能产生重大影响。
您的外部查询如下所示。
SELECT sum(acctinputoctets) as upload,
sum(acctoutputoctets) as download
FROM radacct a
INNER JOIN ( /*an aggregate
* yielding acctuniqueid and raddactid
* naturally ordered on those two columns
*/
) b ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid
为此你需要复合覆盖指数
(acctuniqueid, radacctid, acctinputoctets, acctoutputoctets)
这部分查询对index magic也很满意
- 索引中的前两列允许根据内部查询的结果查找您需要的每一行。
- 然后查询引擎可以扫描将其他两列的值相加的索引。
(这称为 覆盖 索引,因为它包含一些列,这些列的存在只是因为我们需要它们的值,而不是因为我们希望它们被索引。其他一些品牌和型号的DBMS 允许在索引中包含额外的列而不使它们可搜索。这要便宜一些,尤其是在 INSERT
操作上。MySQL 不会那样做。)
因此,您的第一个行动项目:添加这两个复合索引并重试您的查询。
从您的问题看来,您在 table 上放置了很多单列索引,希望它们能加快速度。这是数据库设计中臭名昭著的反模式。尊重,你应该摆脱任何你不知道你需要的索引。它们无助于查询,而且会减慢 INSERTS
。这是你的第二个行动项目。
第三,去读这个http://use-the-index-luke.com/很有帮助。
专业提示:您看到我如何格式化您的查询了吗?当您必须理解一个查询时,制定一个清晰显示 table s、列、ON
条件和查询的其他方面的个人格式约定非常重要。
WHERE username='batman215'
and acctstarttime between ...
按顺序请求 INDEX(username, acctstarttime)
。
ON a.acctuniqueid = b.acctuniqueid
AND a.radacctid = b.radacctid;
求 INDEX(acctuniqueid, radacctid)
(任意顺序)(或 Ollie 的覆盖索引)。
"In every 5-6 minutes data for about 3000 users is inserted" 请求 InnoDB 而不是 MyISAM。 MyISAM 执行 table 锁,从而使 'insert' 干扰其他查询。 Conversion tips.