mysql查询优化 选择 b、 类别, 作为cnt的总和(视图计数), 分类名 从…起 bookvisit AS bv b.isbn=bv.isbn上作为b的内部连接簿 在b.categoryid=c.categoryid上左连接类别为c 哪里 b、 categoryid不为NULL,并且 b、 类别0 分组 b、 类别 订购人 cnt DESC, bv.isbn 限制0,4

mysql查询优化 选择 b、 类别, 作为cnt的总和(视图计数), 分类名 从…起 bookvisit AS bv b.isbn=bv.isbn上作为b的内部连接簿 在b.categoryid=c.categoryid上左连接类别为c 哪里 b、 categoryid不为NULL,并且 b、 类别0 分组 b、 类别 订购人 cnt DESC, bv.isbn 限制0,4,mysql,optimization,Mysql,Optimization,我有三张桌子- 图书(包含图书信息) 图书访问(图书访问信息) 类别(类别主控) 我需要的是流行类别,上面的查询有两个eq\u ref,但它有一个 使用临时设备;还使用文件排序 有什么帮助吗?根据您昨天的评论,我认为问题在于您在计算(聚合)列上执行ORDER BY,因此它不能使用索引 唯一的解决方法是添加category.viewcount列,在更新book.viewcount时更新该列。它不会占用太多额外的空间。此解决方案的缺点是: 当一本书的类别发生变化时(我认为这很少见),您需要从旧类别中

我有三张桌子- 图书(包含图书信息) 图书访问(图书访问信息) 类别(类别主控)

我需要的是流行类别,上面的查询有两个eq\u ref,但它有一个 使用临时设备;还使用文件排序


有什么帮助吗?

根据您昨天的评论,我认为问题在于您在计算(聚合)列上执行ORDER BY,因此它不能使用索引

唯一的解决方法是添加category.viewcount列,在更新book.viewcount时更新该列。它不会占用太多额外的空间。此解决方案的缺点是:

  • 当一本书的类别发生变化时(我认为这很少见),您需要从旧类别中减去book.viewcount并将其添加到新类别中
  • 类别表上的锁争用可能是性能问题
  • 如果这是我,并且性能至关重要,我会编写一个单独的服务,在启动时将当前统计数据读入内存,并让系统向其发送更新并查询以获取最新的统计数据。这样可以避免锁定和写入类别表


    当然,如果数字不必是100%最新的,那么您可以隔夜运行查询并缓存当天的结果。

    根据您昨天的评论,我认为问题在于您在计算(聚合)列上执行ORDER BY,因此它不能使用索引

    唯一的解决方法是添加category.viewcount列,在更新book.viewcount时更新该列。它不会占用太多额外的空间。此解决方案的缺点是:

  • 当一本书的类别发生变化时(我认为这很少见),您需要从旧类别中减去book.viewcount并将其添加到新类别中
  • 类别表上的锁争用可能是性能问题
  • 如果这是我,并且性能至关重要,我会编写一个单独的服务,在启动时将当前统计数据读入内存,并让系统向其发送更新并查询以获取最新的统计数据。这样可以避免锁定和写入类别表


    当然,如果数字不必是100%最新的,那么您可以隔夜运行查询并缓存当天的结果。

    正如@dj_segfault所说,您不能在
    MySQL
    中的聚合列上有索引,您必须编写一个服务来缓存shapshot表中的总和(您可以为其编制索引)

    以下是您如何做到这一点并仍然拥有准确的统计数据:

  • 创建快照表:

    SELECT
        b.categoryid,
        SUM(viewcount) AS cnt,
        categoryname
    FROM
        bookvisit AS bv
        INNER JOIN book AS b ON b.isbn = bv.isbn
        LEFT JOIN category AS c ON b.categoryid = c.categoryid
    WHERE
        b.categoryid IS NOT NULL AND
        b.categoryid <> 0 
    GROUP BY
        b.categoryid 
    ORDER BY
        cnt DESC,
        bv.isbn
    LIMIT 0, 4
    
    使用
    类别
    上的
    主键

  • 创建一个名为
    snapshot\u time
    的单字段单记录表:

    category  cnt
    
  • 及时在该表中填写以下查询:

    taken
    
  • 运行此查询:

    snapshot (cnt)
    bookvisit (visit_time)
    book (category)
    
  • 查询将返回准确的访问次数

    其主要思想是,您只需要扫描
    bookvisit
    中缓存统计数据后收集的记录

    更重要的是:你甚至不必扫描缓存统计数据中的所有记录。由于访问次数只会增加,你只能扫描可能进入前四位的结果

    如果
    4th
    记录在快照中具有
    1000000
    页面视图,并且
    1000
    页面视图发生在您拍摄快照之后,则您只能从快照中选择
    cnt>=999000
    的记录。其他记录理论上不能达到此限制,因为它将花费
    1K
    页面浏览量


    唯一的问题是你可以删除这些书或更改它们的类别。在这种情况下,你只需要重新计算统计数据或返回到原来的方法。

    正如@dj_segfault所说,你不能在
    MySQL
    中的聚合列上有索引,你必须编写一个可以缓存的服务e shapshot表中的总和(可以索引)

    以下是您如何做到这一点并仍然拥有准确的统计数据:

  • 创建快照表:

    SELECT
        b.categoryid,
        SUM(viewcount) AS cnt,
        categoryname
    FROM
        bookvisit AS bv
        INNER JOIN book AS b ON b.isbn = bv.isbn
        LEFT JOIN category AS c ON b.categoryid = c.categoryid
    WHERE
        b.categoryid IS NOT NULL AND
        b.categoryid <> 0 
    GROUP BY
        b.categoryid 
    ORDER BY
        cnt DESC,
        bv.isbn
    LIMIT 0, 4
    
    使用
    类别
    上的
    主键

  • 创建一个名为
    snapshot\u time
    的单字段单记录表:

    category  cnt
    
  • 及时在该表中填写以下查询:

    taken
    
  • 运行此查询:

    snapshot (cnt)
    bookvisit (visit_time)
    book (category)
    
  • 查询将返回准确的访问次数

    其主要思想是,您只需要扫描
    bookvisit
    中缓存统计数据后收集的记录

    更重要的是:你甚至不必扫描缓存统计数据中的所有记录。由于访问次数只会增加,你只能扫描可能进入前四位的结果

    如果
    4th
    记录在快照中具有
    1000000
    页面视图,并且
    1000
    页面视图发生在您拍摄快照之后,则您只能从快照中选择
    cnt>=999000
    的记录。其他记录理论上不能达到此限制,因为它将花费
    1K
    页面浏览量


    唯一的问题是你可以删除这些书或更改它们的类别。在这种情况下,你只需要重新计算统计数据或返回到原来的方法。

    你能解释一下你的第二段是什么意思吗?我不明白这意味着什么。上面的查询显示了流行的类别。书是主要的表和目录包含isbn、分类和其他字段。bookvisit包含isbn和viewcount字段