Mysql

MySQL 為什麼更新 0 行很慢?

  • March 9, 2018

更新: where 子句是相同的。結果如下所述。

以下查詢在 0.1 秒內執行並返回 0 個結果。

SELECT id from content WHERE compliance_overridden = 1 AND compliance_overridden_date < DATE_SUB(NOW(), INTERVAL 30 DAY);

因此,我希望以下查詢會在同一時間內返回(因為它實際上不需要更新任何內容)。

UPDATE content SET compliance_overridden = 0 WHERE compliance_overridden = 1 AND compliance_overridden_date < DATE_SUB(NOW(), INTERVAL 30 DAY);

需要幾分鐘才能完成。 在此處輸入圖像描述 a) 為什麼?

UsingEXPLAIN表明第一個查詢沒有使用任何索引(key=None),但第二個查詢是(key=PRIMARY)。這讓我更加困惑。

選擇查詢 更新查詢

b) 為什麼一個查詢使用索引,而另一個不使用?也許 MySQL 先選擇行然後按主鍵更新?我曾嘗試分別執行這兩個查詢(選擇 ids,然後更新)並且兩者都很快。

c) 為什麼使用 PRIMARY 索引而不是無索引時第二個查詢會變慢?

**PS:**我嘗試添加USE INDEX (PRIMARY)到第一個查詢和IGNORE INDEX (PRIMARY)第二個查詢,兩者都對查詢時間沒有影響。

**PPS:**用於SQL_NO_CACHE第一個查詢也對查詢時間沒有影響。

引擎: Aurora MySQL 5.6.10a

顯示創建表內容;

CREATE TABLE `content` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `title` varchar(255) NOT NULL,
 `content_key` char(40) NOT NULL,
 `body` mediumtext,
 `original_body` mediumtext,
 `meta` mediumblob,
 `status` enum('approved','deleted','draft','library','flagged','in progress','pending','published','publishing error','queued','ready','retracted','scheduled','removed','for review','reviewed','disabled') NOT NULL DEFAULT 'in progress',
 `is_flagged` int(11) NOT NULL DEFAULT '0',
 `extraction_status` enum('queued','processing','processed','processing error') DEFAULT NULL,
 `type` enum('internal','external','library') NOT NULL DEFAULT 'internal',
 `compliance_status` enum('ok','error','warning','unchecked','fail','overridden-ok','overridden-error','queued') DEFAULT 'unchecked' COMMENT 'Status when content is reviewed against guidelines',
 `queued_for_compliance` tinyint(4) NOT NULL DEFAULT '0',
 `queued_date` timestamp NULL DEFAULT NULL,
 `review_retries` int(11) NOT NULL,
 `review_notes` varchar(255) DEFAULT NULL,
 `needs_review` tinyint(1) DEFAULT '0' COMMENT 'Indicates that the content items needs the compliance reviewed to be checked',
 `pushed_for_review` enum('no','yes','error') NOT NULL DEFAULT 'no' COMMENT 'Flags if content is pushed to Minerva.',
 `risk_score` tinyint(1) DEFAULT '0',
 `keywords` text,
 `track` varchar(60) DEFAULT NULL,
 `purpose` enum('arbitrary','compliance_file_check','compliance_text_check','document','promotion','reply','retweet','site','site_post','soa','status_update','url') NOT NULL DEFAULT 'site' COMMENT 'Changed to an enum with applicable values. This will allow us to optimise queries on this column.',
 `purpose_note` text COMMENT 'Optional note explaining the purpose of this item',
 `format` varchar(20) DEFAULT NULL,
 `media` varchar(255) DEFAULT NULL,
 `media_alternate` varchar(255) DEFAULT NULL,
 `mime_type` varchar(255) DEFAULT NULL,
 `user_id` int(11) DEFAULT NULL,
 `tag_id` int(11) DEFAULT NULL,
 `email_template_id` int(11) DEFAULT NULL,
 `social_account_id` int(11) DEFAULT NULL,
 `target_social_account_id` int(11) DEFAULT NULL,
 `parent_id` int(11) DEFAULT NULL,
 `notes` text,
 `options` text,
 `compliance_notes` text,
 `notified` tinyint(1) NOT NULL COMMENT 'Indicates if legal have been notified of the content change',
 `publish_immediately` tinyint(1) DEFAULT '0',
 `score` int(11) DEFAULT NULL,
 `insights` text,
 `publish_date` timestamp NULL DEFAULT NULL,
 `date_published` timestamp NULL DEFAULT NULL,
 `external_id` varchar(40) DEFAULT NULL,
 `feed_id` int(11) DEFAULT NULL,
 `site_id` int(11) DEFAULT NULL,
 `client_id` int(11) DEFAULT NULL,
 `has_changed` tinyint(1) DEFAULT '0' COMMENT 'Indicates if the content has ever changed',
 `was_flagged` tinyint(4) NOT NULL DEFAULT '0',
 `last_flagged` timestamp NULL DEFAULT NULL COMMENT 'Date content was last flagged',
 `compliance_overridden` tinyint(4) NOT NULL DEFAULT '0',
 `compliance_overridden_date` timestamp NULL DEFAULT NULL,
 `was_risky` tinyint(1) DEFAULT '0' COMMENT 'Indicates if the content was ever risky',
 `last_risky` timestamp NULL DEFAULT NULL COMMENT 'Date content was last assigned risk',
 `reference_urls` enum('none','ok','unchecked','error') NOT NULL DEFAULT 'none',
 `screenshot_url` text,
 `rescan` enum('no','manual-queued','compliance-changed','compliance-unchanged','compliance-unchecked') NOT NULL DEFAULT 'no',
 `rescan_rules` varchar(50) DEFAULT NULL,
 `applicable_rules` text COMMENT 'Applicable rules for a review',
 `lsh_hash` char(70) DEFAULT NULL,
 `comment_count` int(11) NOT NULL DEFAULT '0',
 `modified` timestamp NULL DEFAULT NULL,
 `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 UNIQUE KEY `content_key` (`content_key`),
 KEY `fk_content_user` (`user_id`),
 KEY `fk_content_content` (`parent_id`),
 KEY `fk_content_email_template` (`email_template_id`),
 KEY `fk_content_target_social_account` (`social_account_id`),
 KEY `fk_content_feed` (`feed_id`),
 KEY `fk_content_site` (`site_id`),
 KEY `title` (`title`),
 KEY `status` (`status`),
 KEY `type` (`type`),
 KEY `needs_review` (`needs_review`),
 KEY `compliance_status` (`compliance_status`),
 KEY `risk_score` (`risk_score`),
 KEY `purpose` (`purpose`),
 KEY `extraction_status_idx` (`extraction_status`),
 KEY `client_id` (`client_id`),
 KEY `is_flagged_idx` (`is_flagged`),
 KEY `purpose_idx` (`purpose`),
 FULLTEXT KEY `content_index` (`title`,`body`),
 CONSTRAINT `content_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `client` (`id`),
 CONSTRAINT `fk_content_content` FOREIGN KEY (`parent_id`) REFERENCES `content` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `fk_content_feed` FOREIGN KEY (`feed_id`) REFERENCES `feed` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `fk_content_site` FOREIGN KEY (`site_id`) REFERENCES `site` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `fk_content_social_account` FOREIGN KEY (`social_account_id`) REFERENCES `social_account` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `fk_content_target_social_account` FOREIGN KEY (`social_account_id`) REFERENCES `social_account` (`id`),
 CONSTRAINT `fk_content_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=247236 DEFAULT CHARSET=utf8

在更新語句中,MySQL 必須為每一行計算“date_sub(created,interval 30 day)”,並將其與compliance_overridden_​​date 進行比較。在選擇中,它只需要計算一次 date_sub(now(), interval 30 day) 。您的 where 子句不允許 MySQL 使用索引來選擇要修改的行。而且由於必須讀取所有行,因此最好掃描表而不是在索引和數據之間跳過。我對解釋中的“PRIMARY”沒有任何解釋。你的猜測比我的好。

此查詢不以任何方式利用主鍵。檢查的行數(大約 160K 行)表明了這一點。所以你認為你UPDATE什麼都不做的假設是不正確的:它檢查了幾行。

您的 SELECT 更快的原因很清楚。此表達式在查詢執行開始時計算一次:

DATE_SUB(NOW(), INTERVAL 30 DAY) 

但是這個是每一行的電腦(這也是這個查詢不能使用索引的原因):

DATE_SUB(created, INTERVAL 30 DAY);

為什麼會EXPAIN顯示PRIMARY?我不知道。但從技術上講,只要不使用二級索引,就始終使用主鍵——因為數據儲存在主鍵中,而不是按特定順序儲存。

引用自:https://dba.stackexchange.com/questions/199555