中 MySQL 表的慢查询(100 万行)

Posted

技术标签:

【中文标题】中 MySQL 表的慢查询(100 万行)【英文标题】:Slow Query on Medium MySQL Table (1 Million Rows) 【发布时间】:2014-12-08 19:52:18 【问题描述】:

我有一个大约 100 万行的 mysql 表。表名是dedict 当我运行一个简单的查询时:

select writtenform from dedict where length(writtenform)>5 
    and partofspeech <> 'abbreviation' order by id asc limit 50,1

查询大约需要 1 秒。

我将id 列(自动增量)和writtenForm 上的索引作为主键。

下面你看到explain dedict的结果:

Field               Type                Null    Key     Default     Extra
senseid             varchar(255)        NO      NULL    
writtenForm         varchar(255)        YES     MUL     NULL
languageIdentifier  varchar(255)        YES     NULL        
partOfSpeech        varchar(255)        YES     NULL
_index              int(11)             YES     NULL
writtenText         longtext            YES     NULL
lexiconid           varchar(255)        YES     NULL
id                  int(11)             NO      PRI     NULL        auto_increment

一定有什么问题。我必须运行此查询 5 次才能显示网页,因此加载时间超过 5 秒。

你能帮帮我吗?

【问题讨论】:

可以改一下表的结构吗? 我不明白为什么人们选择关键字来命名表格的列 ***.com/questions/84346/…writtenfrom 上的索引是无用的,除非它是基于长度的索引。 那么只添加一个具有书面形式长度的新列就足够了吗?那么我应该简单地索引这个新列还是有更多的东西? MySQL 不支持基于长度的索引,所以创建一个触发器和另一个属性作为索引就可以了。 【参考方案1】:

也许你可以优化属性长度。 varchar(255) 类型的属性有 5 个。

无论如何,为了获得难以置信的速度,您可以在插入/更新语句上创建一个触发器,以将内容长度存储在另一个属性中。 因此,每次插入或更新一行时,触发器都会将长度存储在另一列整数类型中。

此外,您真的需要一次查询所有表吗?

【讨论】:

这个表是为字典准备的。它包含一种语言的大部分单词。我不打算更新它。那么,我应该添加一个具有书面长度的新列吗?它有帮助吗?关于另一个问题,我想在所有页面上显示 5 个随机单词。这就是我查询 5 次的原因。 添加一个新列来存储长度会更快,因为您会将一个整数与另一个整数(而不是两个字符串)进行比较。 "length(writtenform)>5" 检索属性的大小,然后进行比较。 "partofspeech 'abbreviation'" 也是一个比较。您应该尽量不要比较字符串以防止出现性能问题。 如果在另一个表中传播 'partOfSpeech' 并且只在 'dedict' 表中保存 id 是合理的,你应该这样做。因为如果您将“缩写”多次存储为关键字,则它是多余的。但是这个选择取决于你的架构。 @CatalinMarcu 您的查询不只是获得第 50 行。你得到满足两个特征的第 50 行。数据库不知道partofspeech 是什么直到它看起来,不知道writtenform 直到它看起来多长时间,也不知道它需要多长时间才能找到50。因为LONGTEXT 是一个BLOB 数据类型,使用函数查询效率非常低(在单个字段值中允许超过 4 GB 的文本的权衡)。 BLOB 不是为此而设计的。可以把它想象成在满足 4x^3 + x^2 is divisble by 7 的无序序列中找到第 50 个有序数。【参考方案2】:

你必须改变表的结构

like--senseid 为整数 书面形式 --- 应该使用此列添加索引到此 bcoz u r 以操作数据。

【讨论】:

我无法将 senseid 更改为整数,因为稍后我会在 senseid 上加入其他表【参考方案3】:

我已经重组了现有表并在架构中创建了更多表。现在查询运行时间不到 10 毫秒。 新的dedict 表是这样的(我已经抑制了writtenform 列并更改了languageIdentifierpartOfSpeechlexiconid 的类型):

Field               Type                Null    Key     Default     Extra
senseid             varchar(255)        NO      NULL    
languageIdentifier  tinyint             YES     NULL        
partOfSpeech        tinyint             YES     NULL
_index              int(11)             YES     NULL
writtenText         longtext            YES     NULL
lexiconid           tinyint             YES     NULL
id                  int(11)             NO      PRI     NULL        auto_increment

此外,我还创建了四个用于加入的表:writtenFormlanguageIdentifierpartOfSpeechlexiconid。其中三个表非常小(dedict_lang 有 2 条记录,dedict_partOfSpeech 有 37 条记录,dedict_lexicon 有 4 条记录),而 dedict_writtenForm 仅包含 idwrittenForm 本身和writtenForm 的长度为 100 万条记录,但已正确编入索引。

【讨论】:

以上是关于中 MySQL 表的慢查询(100 万行)的主要内容,如果未能解决你的问题,请参考以下文章

mysql中的慢查询会不会影响速度

MySQL 的慢查询日志

phpMyAdmin中的慢查询但Mysql慢查询日志文件中没有[关闭]

学会读懂 MySql 的慢查询日志

常见Mysql的慢查询优化方式

如何动态开启mysql的慢查询日志记录