【问题标题】:Big execution time differences each refresh with pdo/mariadb每次使用 pdo/mariadb 刷新时执行时间差异很大
【发布时间】:2018-06-20 20:09:46
【问题描述】:

我想 mariadb 的工作方式类似于 mysql,这就是我正在使用的,而且我知道有一个缓存系统。

我的问题和我不明白的是,我刷新的页面需要很长时间才能刷新,但时间根本不是恒定的。稍后详细说明。

在页面 A:

85% 的时间,执行大约需要 7 秒。

10% 的时间,大约需要 27 秒。

5% 的时间不到 1 秒(当我以非常短的间隔刷新时)。

在 B 页上:

80% 的时间,大约需要 5 秒。

有时大约是 2.5 秒。

有时不到一秒。

有一次超过 60 秒,触发错误。

我的代码没有变化,只是观察和 F5 刷新。

详情:

我有一个 MyISAM 表,每天大约有 150k 新行(“插入”)。 我希望每分钟查询一次该表(“选择”)。 它一次可以拥有的最大行数可能在 50,000,000 到 4,750,000,000 之间... 我正在使用 PHP 在同一台服务器上运行查询。

我目前使用的结构:

CREATE TABLE `ticks` (
 `primary` int(11) NOT NULL AUTO_INCREMENT,
 `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `pairs` text NOT NULL,
 `price` decimal(18,8) NOT NULL,
 `daily_volume` decimal(36,8) NOT NULL,
 PRIMARY KEY (`primary`),
 KEY `datetime` (`datetime`)
) ENGINE=MyISAM AUTO_INCREMENT=4007125 DEFAULT CHARSET=latin1

数据样本:

|primary | datetime            | pairs    | price          | volume           |
-------------------------------------------------------------------------------
|5810228 | 20/01/2018 21:34:02 | BTC_HUC  | 0.00002617     | 6.08607929       |
|5810213 | 20/01/2018 21:34:02 | BTC_BELA | 0.00002733     | 8.83542600       |
|5810224 | 20/01/2018 21:34:02 | BTC_FLDC | 0.00000374     | 12.72654326      |
|5810234 | 20/01/2018 21:34:02 | BTC_NMC  | 0.00037099     | 4.06446745       |
|5810219 | 20/01/2018 21:34:02 | BTC_CLAM | 0.00070798     | 13.65356478      |
|5810220 | 20/01/2018 21:34:02 | BTC_DASH | 0.07280004     | 423.88604591     |
|1706999 | 11/01/2018 17:09:01 | USDT_BTC | 13590.45341401 | 398959280.2620621|

我在日期时间创建了一个索引(“正常”索引)。

使用 pdo 运行页面 A 上的查询需要 7 秒,但在 phpmyadmin 中约为 0.0007:

SELECT DISTINCT(pairs)
FROM ticks

自从我为日期时间编制索引以来,第一次查询后的每次繁重计算大部分时间总共需要约 0.5 秒。

但是,由于未知原因,有时运行时间会延长 25 到 35 倍。这是使用的查询(循环运行 100 次):

SELECT datetime, price
FROM ticks
WHERE datetime <= DATE_SUB(NOW(),INTERVAL 1 MINUTE)
AND pairs = \''.$data['pairs'].'\'
ORDER BY datetime DESC
LIMIT 1

我不会进一步解释页面 B,因为该页面对我来说不太重要,而且我对与在此页面上进行的操作数量相关的平均执行时间感到满意。我唯一的疑问是这里也可能发生广泛的执行时间。

问题:

1-执行时间差异怎么会这么大,我怎么能让我的页面在 1 秒内运行,因为它有时会发生?我的 sql 查询仅在数据库上就非常简单和快速。我相信db和php服务器位于同一台机器上。

特别是,我想知道为什么使用 pdo 的查询运行速度比使用 phpmyadmin 慢 10,000。 7/0.0007 是 10k,这里肯定有很大的问题。

索引对不会改变任何东西。

2-您是否在我的解释中发现了任何可能导致修复和改进性能的不正确之处?你有什么特别的建议可以在本案例中提高性能吗?例如,我一直想知道 MyISAM 在我的情况下是否有效(我相信如此)。

【问题讨论】:

    标签: php sql pdo phpmyadmin mariadb


    【解决方案1】:

    基本上没有理由不再使用 MyISAM,尤其是在性能方面。

    7 秒对于页面加载来说是可怕的。其中有多少是 MySQL 操作?在代码中添加一些计时器。这将找出哪个查询最慢,让我们改进它。 (我猜想一个不必要的慢查询是你问题的根源。)

    “~0.0007”闻起来像查询缓存启动了,它并没有真正执行查询。我忽略了。

    使用 MyISAM,INSERTs 阻止 SELECTs。这可以解释一天中插入部分的麻烦。

    表格令人困惑——您有一个TIMESTAMP(分辨率为秒),但有一个“daily_volume”听起来像是“一天”的分辨率。

    我看到TEXT。行有多长?如果小于 255,请使用 VARCHAR,而不是 TEXT。这将允许您添加INDEX(pairs),从而使SELECT DISTINCT(pairs) FROM ticks 运行得更快。

    但是,要添加 INDEX(pairs, datetime) 而不是那个索引,以使第二个 SELECT 运行快得多

    缩小表格大小将有助于提高速度。 (有些人的意思是在 10% 到 10 倍之间,这取决于很多因素。)

    您的小数点过大。找到最差的(可能是BRKA)并缩小m,nDECIMAL(m,n)。目前,您为这两列使用 9 和 15 个字节。您可以考虑FLOAT(4 个字节,~7 有效 位)或DOUBLE(8 个字节,~16 位)。

    见我的notes on converting to InnoDB。请注意,磁盘占用空间可能会增加一倍或三倍。 (是的,这是 MyISAM 的一个优势。)

    考虑其他列(或列组合)是否是唯一的。如果您有这样的情况,请放弃primary 列,并将该列设为PRIMARY KEY。如果它恰好是(pairs, datetime),那么这将进一步提升某些查询的性能。

    “索引对没有改变任何东西。” -- 既然不使用“前缀”就无法索引TEXT 列,而且前缀实际上是无用的,我并不感到惊讶。

    您能给我看一个数据样本吗?我不熟悉什么是“对”。

    TIMESTAMPDATETIME 开头的索引 很少有用;摆脱它,除非您有另一个从中受益的查询。

    至于查询缓存——大小不应超过 50M。数据是不是一天 23 小时都没有变化,然后插入一连串?这将是使用 QC 的好案例。 (大多数生产服务器最好关闭它OFF。)超过 50M 可能会降低性能。

    在您解决了我的大部分建议后,其他一些问题可能会浮出水面。也就是说,我希望您再次提出另一个问题,以完成对应用性能的改进。

    【讨论】:

    • 针对该查询的最大修复pairs VARCHAR(40) 加上INDEX(pairs, datetime)。 ('40' 是任意的 - 比你的 15 多,并且比 可能 引起麻烦的下一个临界值 (191) 小。也就是说,this SELECT 将得到帮助,但这些。切换到 InnoDB 和其他建议将有助于其他事情。
    • 谢谢。我花了一些时间来应用您的建议:将 daily_volume 重命名为 volume。将 TEXT 更改为 VARCHAR(40)。仅此一项就使查询在 avg 上运行到 1.5 秒而不是 7 秒。已删除日期时间索引。创建了多字段键索引:create index datetime_pairs on TABLE (pairs, datetime);。查询运行到 ~0.002 秒而不是 1.5 秒。基于日期时间的查询没有运行时间更改。你说的“BRKA”和缩表是什么意思?离开这个。将音量从十进制 (36,8) 更改为十进制 (20,8)。将价格从小数 (18,8) 更改为小数 (14,8)。这将执行提高了约 15%。
    • 将 MyISAM 更改为 InnoDB。没有看到性能变化,但它可能改进了与插入锁定相关的事情。至于主要(对,日期时间),不幸的是,似乎〜0.0001%的行不是唯一的。哪一个足以让它成为一个坏主意?我的 query_cache_limit=2097152 和 query_case_size=67108864。其中略高于50M。这是一个问题吗?我在帖子中添加了数据样本。当我在未来的结果中遇到糟糕的表现时,我可能会有进一步的疑问。
    • BRKA 可能是最昂贵的(想想price 所需的大小)。你真的在同一秒钟有两个价格吗? QC 大小为 64M——OK。如果您有问题,请使用新的CREATE TABLE 等开始一个新问题。
    • @Aada-Ea - 还有,innodb_buffer_pool_size 的值是多少;你有多少内存?
    【解决方案2】:

    执行时间差异怎么会如此之大,我怎么能让我的页面在 1 秒内运行,因为它有时会发生?我的 sql 查询仅在数据库上就非常简单和快速。

    如果不分析您的平台、监控每个组件的性能、查看代码和所有查询等,就不可能确定地回答这个问题。这远远超出了 SO 的范围。

    可以说的是:

    • 它不太可能与 PDO 本身(或 PHPMyAdmin)有关
    • 这是典型的并发问题 - 除非您有专门用于呈现“页面 A”的服务器和数据库,否则同时发生的其他请求和查询可能会影响性能李>
    • 众所周知,MyISAM 在处理插入时的大卷时很糟糕,因为它使用表锁定(简而言之,每次插入时它都会锁定所有表)。 InnoDB 使用 基于行的锁定,如果每天写入 150k,效率可能会更高。引用 MySQL 文档:

    表锁定允许多个会话同时从一个表中读取,但是如果一个会话想要写入一个表,它必须首先获得独占访问,这意味着它可能必须等待其他会话完成对该表的访问第一的。在更新期间,想要访问这个特定表的所有其他会话必须等到更新完成。

    【讨论】:

    • 谢谢。我将表从 MyISAM 类型更改为 InnoDB。这可能会提高锁定结果的性能。注意到插入也每分钟发生一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 2010-10-01
    相关资源
    最近更新 更多