MySQL 仅针对特定 table 的计数查询花费的时间太长

MySQL count query takes too long for particular table only

我有一个 table 包含文档,在生产中这个 table 中有大约 120 万条记录。在此 table 上,当我执行 select count(*) from <table> 时,花费的时间太长,最后我需要重新启动数据库。另一方面,我还有许多其他 table 包含 10-12 百万行,但那些 table 没有这个问题。

这些是 table

的索引
mysql> show index from candidates_resume\G
*************************** 1. row ***************************
        Table: candidates_resume
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 843657
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: candidates_resume
   Non_unique: 0
     Key_name: candidate_id
 Seq_in_index: 1
  Column_name: candidate_id
    Collation: A
  Cardinality: 844009
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 3. row ***************************
        Table: candidates_resume
   Non_unique: 1
     Key_name: candidates_resume_uploaded_on_e4c78158b8c18f_uniq
 Seq_in_index: 1
  Column_name: uploaded_on
    Collation: A
  Cardinality: 844009
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 4. row ***************************
        Table: candidates_resume
   Non_unique: 1
     Key_name: candidates_resume_pdf_file_5b052603240d1d43_uniq
 Seq_in_index: 1
  Column_name: pdf_file
    Collation: A
  Cardinality: 844009
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 5. row ***************************
        Table: candidates_resume
   Non_unique: 1
     Key_name: candidates_resume_watermark_file_68fd6000f27d4f8d_uniq
 Seq_in_index: 1
  Column_name: watermark_file
    Collation: A
  Cardinality: 844009
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL

这是 SHOW CREATE TABLE

的结果
Create Table: CREATE TABLE `candidates_resume` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(50) NOT NULL,
  `uploaded_on` datetime NOT NULL,
  `candidate_id` int(11) NOT NULL,
  `file` varchar(100) NOT NULL,
  `hash` varchar(10) NOT NULL,
  `pdf_file` varchar(100) DEFAULT NULL,
  `resume_text` longtext NOT NULL,
  `watermark_file` varchar(100) DEFAULT NULL,
  `html_file` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `candidate_id` (`candidate_id`),
  KEY `candidates_resume_uploaded_on_e4c78158b8c18f_uniq` (`uploaded_on`),
  KEY `candidates_resume_pdf_file_88ec1f31_uniq` (`pdf_file`),
  KEY `candidates_resume_watermark_file_23af2d43_uniq` (`watermark_file`),
  CONSTRAINT `candidate_id_refs_id_88f99c34` FOREIGN KEY (`candidate_id`) REFERENCES `candidates_candidate` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=591098 DEFAULT CHARSET=utf8

任何人都可以指导我如何解决这个 table 的问题吗?

SELECT COUNT(*) FROM ... 没有任何过滤 (WHERE) 必须扫描整个 table 或一个索引。这需要时间。

EXPLAIN SELECT ...看看它是如何处理的。我认为它将使用您的 UNIQUE(candidate_id)。 (请提供SHOW CREATE TABLE。)

假设 candidate_idINTBIGINT,查询不会 运行 快得多。

为什么要统计行数。 估计是否“足够好”?如果是这样,请参阅 SHOW TABLE STATUSinformation_schema 中的等效查询。

如果从今天早上午夜开始的计数“足够好”,则执行该计数并将其保存在某个地方。

如果您不知道如何避免超时,请参阅 wait_timeout。警告;有好几种口味。

有总结Table

构建并维护一个 table 来保存,比如说,每小时的行数:

CREATE TABLE counts (
    hr MEDIUMINT UNSIGNED NOT NULL,
    ct SMALLINT UNSIGNED NOT NULL,
    PRIMARY KEY(hr)
) ENGINE=InnoDB;

初始化(一次性任务):

INSERT INTO counts  (hr, ct)
    SELECT  FLOOR(UNIX_TIMESTAMP(uploaded_on) / 3600),
            COUNT(*)
        FROM candidates_resume
        GROUP BY 1;

新行插入 candidates_resume:

INSERT INTO candidates_resume
    (hr, ct)
    VALUES
    (FLOOR(UNIX_TIMESTAMP(uploaded_on) / 3600), 1)
    ON DUPLICATE KEY UPDATE ct = ct + 1;

想要计数时:

SELECT SUM(ct) FROM counts;

这给出了到当前小时开始的计数。如果您需要计数到当前秒数,请添加第二个查询以仅计算自该小时开始以来的行数。

(有一些未解决的问题需要解决。)

更多讨论:http://mysql.rjweb.org/doc.php/summarytables