中 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
列并更改了languageIdentifier
、partOfSpeech
和lexiconid
的类型):
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
此外,我还创建了四个用于加入的表:writtenForm
、languageIdentifier
、partOfSpeech
和 lexiconid
。其中三个表非常小(dedict_lang
有 2 条记录,dedict_partOfSpeech
有 37 条记录,dedict_lexicon
有 4 条记录),而 dedict_writtenForm
仅包含 id
、writtenForm
本身和writtenForm
的长度为 100 万条记录,但已正确编入索引。
【讨论】:
以上是关于中 MySQL 表的慢查询(100 万行)的主要内容,如果未能解决你的问题,请参考以下文章