【问题标题】:MySql with 109 million records - very slow, with keysMySql 有 1.09 亿条记录 - 非常慢,有键
【发布时间】:2021-11-22 12:18:38
【问题描述】:

我有一个包含 1.09 亿条记录的表(每天都在增长)——现在大约 20GB。 这是一个从许多带有时间戳的变量中收集数据的表。这是一个scada系统。 很简单,

CREATE TABLE `INVIEW_LOGS` (
  `id` bigint(20) NOT NULL,
  `iws_conn_id` smallint(6) NOT NULL,
  `prf_station_id` smallint(3) NOT NULL,
  `iws_var_id` mediumint(9) NOT NULL,
  `var_name` char(125) NOT NULL,
  `dia_hora` datetime NOT NULL,
  `valor` decimal(18,2) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `INVIEW_LOGS`
--
ALTER TABLE `INVIEW_LOGS`
  ADD PRIMARY KEY (`id`),
  ADD KEY `prf_station_id` (`prf_station_id`),
  ADD KEY `var_name` (`var_name`),
  ADD KEY `var_name_2` (`var_name`),
  ADD KEY `var_name_3` (`var_name`),
  ADD KEY `var_name_4` (`var_name`),
  ADD KEY `var_name_5` (`var_name`);

我必须制作图形,并且必须检索 6 或 7 个变量的最后 10000 条记录来绘制图表。

问题是......即使有索引和优化,一些变量(有超过 10000 条记录,我有百万条记录的变量),检索该变量的时间很长.. 大约 28 秒。

我该如何调整这个?!

我将它从 INODDB 更改为 MyISAM - 这是第二个数据库,用于读取一整天并在夜间的短时间内写入每日记录。

已编辑 - 2021 年 10 月 1 日

-- Estrutura da tabela `INVIEW_LOGS`
--

CREATE TABLE `INVIEW_LOGS` (
  `id` bigint(20) NOT NULL,
  `iws_conn_id` smallint(6) NOT NULL,
  `prf_station_id` smallint(3) NOT NULL,
  `iws_var_id` mediumint(9) NOT NULL,
  `var_name` char(125) NOT NULL,
  `dia_hora` datetime NOT NULL,
  `valor` decimal(18,2) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `INVIEW_LOGS`
--
ALTER TABLE `INVIEW_LOGS`
  ADD PRIMARY KEY (`id`),
  ADD KEY `prf_station_id` (`prf_station_id`),
  ADD KEY `var_name` (`var_name`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `INVIEW_LOGS`
--
ALTER TABLE `INVIEW_LOGS`
  MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

我不知道为什么 var_name 上有这么多索引 我重建了它。

查询

select dia_hora, valor FROM INVIEW_LOGS WHERE var_name='PRF.Posto.var_5.VALUE' ORDER BY id DESC LIMIT 10000 10000 行(29.09 秒)

带有和索引 选择 dia_hora, valor FROM INVIEW_LOGS WHERE prf_station_id=12 AND var_name='PRF.Posto.var_5.VALUE' ORDER BY id DESC LIMIT 10000 10000 行(21.13 秒)

【问题讨论】:

  • 尝试使用分区
  • 为什么同一列有五个相同的索引?
  • 当您询问有关查询优化的问题时,您应该显示查询本身。某些查询将无法使用您的索引。还为您尝试改进的查询运行EXPLAIN SELECT ...,以显示当前优化器估计它将如何使用索引(或不使用索引)。

标签: mysql performance indexing


【解决方案1】:

(“var_id 与 var_name 相同”——这令人困惑。) 这是相当多余的。 PostGres 的旧代码使用 var_id,但 MySQL 的新代码使用 var_name。

我承认我还没有意识到我可以在同一个索引中插入超过 1 列。 我会试试你对这些索引的方法。

我们的变量记录率很高...有时每秒...客户希望获得在 Javascript 上绘制的月度和年度图表的概览...所以,我必须抓住几千浏览器的变量。

【讨论】:

    【解决方案2】:

    var_name 的平均长度是多少?如果它相对较短,那么您尝试创建表ROW_FORMAT=FIXED 会导致它变为 20GB,而它可能只有 8GB。这可能会导致额外的 I/O,从而导致处理速度变慢。标准化可能会带来更多的节省。

    DECIMAL(18,2) 占用 9 个字节;对于 SCADA 系统来说,这是一个非常大的数字。 valor 代表什么?一个 4 字节的 FLOAT(大约 7 个有效位)就足够了吗?

    折腾多余的索引;他们放慢了速度INSERTs

    您正在访问“最后 10000 条记录”,但dia_hora 上没有索引。

    “对于 6 个或 7 个变量”是指 var_id 的不同值吗?

    由于“覆盖”索引在 MyISAM 和 InnoDB 之间的工作方式不同,我真的需要查看 SELECT

    (来自 OP 的评论)

    select  dia_hora, valor
        FROM  INVIEW_LOGS
        WHERE  var_name='PRF.Posto.var_5.VALUE'
        ORDER BY  id DESC
        LIMIT  10000;
    -- 10000 rows in set (29.09 sec) 
    select  dia_hora, valor
        FROM  INVIEW_LOGS
        WHERE  prf_station_id=12
          AND  var_name='PRF.Posto.var_5.VALUE'
        ORDER BY  id DESC
        LIMIT  10000;
    -- 10000 rows in set (21.13 sec)
    

    更多

    在 MyISAM 中,每一行当前占用大约 160 个字节。假设var_name 平均只有 15 个字符,CHAR 中平均有 125-15-1 = 109 个字节的空格。如果您切换到VARCHAR,这些空间就会消失。该更改会将表大小从 20GB 缩小到 7GB 以下。切换到 InnoDB(出于多种原因推荐)会将其恢复到大约 20GB。

    移动到查找表会进一步缩小主表,但这可能值得,也可能不值得。

    ("var_id is the same as var_name" -- 这很混乱。)

    这些选择可能会从中受益

    INDEX(var_name, id)
    INDEX(prf_station_id, var_name, id)
    

    并摆脱这些,因为它们现在是多余的:

    KEY `prf_station_id` (`prf_station_id`),
    KEY `var_name` (`var_name`);
    

    (这些索引建议适用于 MyISAM 和 InnoDB。

    图表

    10K 点需要绘制很多。如果只有 1K 点,图表会不会一样好?采样频率是多少?例如,如果您每 5 秒采样一次,那么拥有一个包含每分钟平均值的“汇总表”将使其更接近 1K 点来绘制。这将使SELECT 和图形包运行得更快。

    关于汇总表的更多信息:http://mysql.rjweb.org/doc.php/summarytables

    【讨论】:

    • var_name 的平均值约为 15 个字符(平均值)我真的不需要那个值那么大,这是真的。我打算换个小一点的。我可能是错的,但我认为我不需要 dia_hora 上的 INDEX - 它是每条记录的时间戳 - 永远不相等。 var_id 与 var_name 相同。所有代码都是为了调用 var_name 而编写的。想象一下:prf_station_id 代表一个独特的设备 - var_id 总是不同的,但每个不同的 prf_station_id 都有相同的 var_name 结构(变量名称)
    • QUERIES select dia_hora, valor FROM INVIEW_LOGS WHERE var_name='PRF.Posto.var_5.VALUE' ORDER BY id DESC LIMIT 10000;集合中的 10000 行(29.09 秒)选择 dia_hora, valor FROM INVIEW_LOGS WHERE prf_station_id=12 AND var_name='PRF.Posto.var_5.VALUE' ORDER BY id DESC LIMIT 10000; 10000 行(21.13 秒)
    • @EduardoLuís - 我添加了很多。
    猜你喜欢
    • 2016-11-09
    • 1970-01-01
    • 2014-02-27
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 2013-11-12
    • 2017-06-18
    • 1970-01-01
    相关资源
    最近更新 更多