【问题标题】:Optimize MySQL query with more than 100 thousand records [duplicate]优化超过 10 万条记录的 MySQL 查询 [重复]
【发布时间】:2021-07-28 08:28:19
【问题描述】:

我希望你帮我优化这个查询。

SELECT  carrier,
        SUM(views) AS views,
        SUM(views-1) AS repeated,
        SUM(views >= 1) AS unique_views,
        COUNT(1) AS total
    FROM  stats s1
    WHERE  id_link = 39
      AND  EXISTS (
        SELECT  *
            FROM  stats s2
            where  id_link = 39
              AND  s2.carrier = s1.carrier
            LIMIT  1, 1 )
    GROUP BY  carrier
    HAVING  COUNT(1) >= 1
    LIMIT  1,1
 UNION 
 SELECT  'TOTAL' AS carrier,
        SUM(views) AS views,
        SUM(views-1) AS repeated,
        SUM(views >= 1) AS unique_views,
        COUNT(1) AS total
    FROM  stats s4
    WHERE  id_link = 39
      AND  EXISTS (
        SELECT  *
            FROM  stats s3
            where  s3.carrier = s4.carrier
            LIMIT  1, 1 )

数据库:

CREATE TABLE `stats` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_link` int(11) NOT NULL,
`country` varchar(100) NOT NULL,
`ip` varchar(100) NOT NULL,
`views` varchar(1000) NOT NULL,
`asn` varchar(1000) NOT NULL,
`carrier` varchar(1000) NOT NULL,
`type` varchar(1000) NOT NULL,
`device` varchar(1000) NOT NULL,
`browser` varchar(1000) NOT NULL,
`fecha` datetime NOT NULL,
`referrer` varchar(2000) NOT NULL,
PRIMARY KEY (`id`),
KEY `id_link` (`id_link`),
CONSTRAINT `stats_ibfk_1` FOREIGN KEY (`id_link`) REFERENCES `campaigns` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=614606 DEFAULT CHARSET=utf8

我正在创建一个网络流量跟踪器。 我有一个名为“统计”的表格,我保存在那里; VIEWS、ASN、IP、BROWSER、DEVICE等,其中有“运营商”,即互联网服务商

我想看看每个运营商有多少访问,帐户重复多次,有多少唯一访问。

我已经完成了我想要的代码,但它仅在记录很少时才有效,现在我有超过 100k 条记录服务器崩溃,它不加载查询,我什至必须重新启动 apache。

这里我只留下一个说明性的图像

有什么方法可以加快查询速度?

提前感谢您的 cmets 和帮助。

【问题讨论】:

  • 为了让任何人能够在这里为您提供帮助,我们需要更多信息,例如所有涉及的表的架构、示例数据和所有索引。如果您对源一无所知,则很难帮助优化查询。
  • 你好,我已经添加了表结构,只涉及“stats”表
  • 您想知道是否至少有 2 行? EXISTS ( ... LIMIT 1,1)

标签: php mysql


【解决方案1】:

你可以使用 Mysql OffSet 和 LIMIT 来实现它

您可以尝试使用 ajax,首先加载 1500 条记录,滚动或单击下一个加载接下来的 1500 条记录,使用数据表,它具有内部分页 + 附加下一步按钮以获得更多结果, 例如在 第 1 页偏移量 = 0,限制 = 1500 第二页偏移量 = 1500 ,限制 1500 .. 等等

【讨论】:

  • 感谢您的回答,问题是我在这里不是要显示数据,而现在是我理解的分页数据,但在这种情况下,我所做的计算必须经过所有表中的数据,所以分页少了
  • 再添加一张表,只保留你的表的数学,比如有人使用 AT&T 访问了网站 > 你的正常插入程序照常运行,但在那个新表中 AT&T 的列值增加 >>> > 所以在计算时它会加快速度>> 如果有任何新的运营商发现新表将添加一列并保持其数学
  • 希望你得到这个,每当访问者点击你的访问计数>>并且在你的操作计算机时将处理几个大值,而不是数千个小值
  • 我怀疑是否有超过 1500 个“运营商”。
  • 直到4000还是没有问题,还有其他方法比如制作json数组,每次访问都会编辑/创建json数组[{"Carrier Name":"AT&T", "Device": "三星","IP":"80.80.80",},{...等}]
【解决方案2】:

** views 用作数字。如果是这种情况,请不要使用VARCHAR。建议INT UNSIGNED(最高为 40 亿)。

** 使用合理的限制而不是varchar(1000)

** 越小越快。所以...标准化经常重复的列。 carrier 有大约 9 个不同的值? SMALLINT UNSIGNED 只需要 2 个字节,并且有足够的空间来处理运营商的世界。大多数varchar(1000) 也是如此。

** 建议使用标准的 2 字母“country_code”(CHAR(2)) 而不是 country(100) -- IN、US、UK、FR、...

** 专门为了加快查询速度,改

KEY `id_link` (`id_link`),

KEY `id_link` (`id_link`, carrier),

** 考虑将WITH ROLLUPGROUP BY 一起使用,这样您就不需要UNION 和第二个SELECT

** 考虑构建和维护一个包含每日小计的“汇总表”。查询此表将比查询您当前拥有的原始(“Fact”)表快得多。更多信息:http://mysql.rjweb.org/doc.php/summarytables。 (这扩展了 Shubham 在评论中提到的内容。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    相关资源
    最近更新 更多