簡體   English   中英

選擇 VARCHAR 時 MySQL 查詢速度變慢

[英]MySQL query slow when selecting VARCHAR

我有這張桌子:

CREATE TABLE `search_engine_rankings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `keyword_id` int(11) DEFAULT NULL,
  `search_engine_id` int(11) DEFAULT NULL,
  `total_results` int(11) DEFAULT NULL,
  `rank` int(11) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `indexed_at` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_ranking` (`keyword_id`,`search_engine_id`,`rank`,`indexed_at`),
  KEY `search_engine_rankings_search_engine_id_fk` (`search_engine_id`),
  CONSTRAINT `search_engine_rankings_keyword_id_fk` FOREIGN KEY (`keyword_id`) REFERENCES `keywords` (`id`) ON DELETE CASCADE,
  CONSTRAINT `search_engine_rankings_search_engine_id_fk` FOREIGN KEY (`search_engine_id`) REFERENCES `search_engines` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=244454637 DEFAULT CHARSET=utf8 

它在生產中有大約 2.5 億行。

當我做:

select id,
       rank 
  from search_engine_rankings 
 where keyword_id = 19 
   and search_engine_id = 11 
   and indexed_at = "2010-12-03";

...它運行得非常快。

當我添加 url 列 (VARCHAR) 時:

select id,
       rank,
       url 
  from search_engine_rankings 
 where keyword_id = 19 
   and search_engine_id = 11 
   and indexed_at = "2010-12-03";

……它運行得很慢。

有任何想法嗎?

第一個查詢可以僅通過索引來滿足——無需讀取基表來獲取 Select 子句中的值。 第二條語句需要讀取基表,因為 URL 列不是索引的一部分。

 UNIQUE KEY `unique_ranking` (`keyword_id`,`search_engine_id`,`rank`,`indexed_at`),

基表中的行與索引中的行的物理順序不同,因此基表的讀取可能涉及相當大的磁盤抖動。

您可以將其視為一種優化證明——在第一次查詢時避免了磁盤抖動,因為引擎足夠智能,可以查詢索引以獲取 select 子句中請求的值; 它已經為 where 子句將該索引讀入 RAM,因此它利用了這一事實。

除了蒂姆的回答。 Mysql 中的索引只能從左到右使用。 這意味着它只能在 WHERE 子句中使用索引的列,直到您使用它們為止。

目前,您的 UNIQUE 索引是keyword_idsearch_engine_idrankindexed_at 這將能夠過濾列keyword_idsearch_engine_id ,仍然需要掃描剩余的行以過濾indexed_at

但是,如果您將其更改為: keyword_idsearch_engine_idindexed_atrank (只是順序)。 這將能夠過濾列keyword_idsearch_engine_idindexed_at

我相信它將能夠充分利用該索引來讀取表的適當部分。

我知道這是一篇舊帖子,但我遇到了同樣的情況,但沒有找到答案。 這確實發生在 MySQL 中,當您有 varchar 列時,它需要花費大量時間進行處理。 我的查詢用了大約 20 秒來處理 1.7M 行,現在大約是 1.9 秒。

好的,首先,從這個查詢創建一個視圖:

CREATE VIEW view_one AS 
  select id,rank 
  from search_engine_rankings 
  where keyword_id = 19000 
  and search_engine_id = 11 
  and indexed_at = "2010-12-03";

其次,相同的查詢但具有內部連接:

select v.*, s.url 
from view_one AS v 
inner join search_engine_rankings s ON s.id=v.id;

TLDR:我通過在表上運行optimize解決了這個問題。


我剛才也有同樣的經歷。 即使是查找主鍵並只選擇幾行也很慢。 測試了一下,我發現它不僅限於varchar列,選擇一個int也需要相當多的時間。

大致如下所示的查詢大約需要 3 秒:

select someint from mytable where id in (1234, 12345, 123456)

雖然大致如下所示的查詢花費了 <10 毫秒:

select count(*) from mytable where id in (1234, 12345, 123456)

這里批准的答案是只創建一個也跨越 someint 的索引,它會很快,因為 mysql 可以從索引中獲取它需要的所有信息,而不必觸及表。 這可能在某些設置中有效,但我認為這是一個愚蠢的解決方法 - 顯然是錯誤的,從表中獲取三行不應該花費三秒鍾,此外,大多數應用程序只是執行“select * from mytable”。 在應用程序端進行更改並不總是微不足道的。

optimize table后,兩個查詢都需要 <10 毫秒。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM