【问题标题】:Ways to optimize my MySQL database优化我的 MySQL 数据库的方法
【发布时间】:2012-07-07 12:01:35
【问题描述】:

我有一个 MySQL 数据库,其中包含标准英文字母表中的所有单词,我用它来创建一个简单的 Scrabble 单词生成器。该数据库分为 26 个表:字母表中的每个字母对应一个表。每个表包含两列:

  • “Word”列:该列为主键,char(12)类型,不接受空值。
  • “长度”列:此列包含无符号 tinyint 值,不接受空值。

在我的应用程序中,用户在文本框中输入任意数量的字母(表示他们的图块),然后我使用以下代码查询数据库:

// this is looped over 26 times, and $char is a letter between 'A' and 'Z'
// check if the user entered in character $char or a blank tile (signified by ? in app)
// this check prevents me from having to query useless tables
if (in_array($char, $lettersArray) || $blanks)
{
    // if so, select all words that have a length that's possible to make
    $query = 'SELECT Word FROM '.$char.'Words WHERE Length <= '.strlen($letters);
    $result = $db->query($query);
    $num_results = $result->num_rows;

    for ($j = 0; $j < $num_results; $j++)
    {
        // determine if it's possible to create word based on letters input
        // if so, perform appropriate code
    }
}

一切正常,但与竞争对手相比,我的应用程序需要很长时间(即理论上的竞争;这更像是我为自己创建的一个学习项目,我怀疑我会在互联网上发布它),尽管该应用程序在我的本地计算机上的事实。我尝试使用 phpMyAdmin 的自动优化功能,但速度没有明显提升。

【问题讨论】:

  • 一个表或一个 联合 会比 26 个分隔查询快得多。长度也应该被索引

标签: php mysql database optimization database-design


【解决方案1】:

我不认为性能问题真的是数据库。数据存储的结构将对算法的性能产生最显着的影响。

解决问题的一种相当容易理解的方法是将问题作为字谜来处理。您可以按字母顺序排列每个单词中的所有字母,并将其存储为带有索引的列。

word      dorw
--------  -------
DALE      ADEL
LEAD      ADEL
LED       DEL
HELLO     EHLLO
HELP      EHLP

然后,给定一组字母,您可以在数据库中查询所有匹配的字谜。只需按字母顺序排列传入的字母集,然后运行查询。

SELECT word FROM dictionary WHERE dorw = 'AERT'

RATE
TARE
TEAR

然后,您可以查询字母的子集:

SELECT word FROM dictionary WHERE dorw IN ('AER','AET','ART','ERT')

这种方法会让你首先返回最长的单词。

这不是最有效的方法,但它是可行的。

处理“空白”图块将是更多工作,您需要用一个可能的字母代替它,并且可以在一个查询中检查所有 26 种可能性,

如果他们有字母 ABCD 和空白拼贴,例如...

SELECT word FROM dictionary WHERE dorw IN ('AABCD','ABBCD', 'ABCCD'
 , 'ABCDD', 'ABCDE', 'ABCDE', 'ABCDF', ..., 'ABCDZ') 

当您开始处理子集时,这会变得更加痛苦......

(在填字游戏和拼图游戏中,没有任何空白图块)

所以这可能不是最适合拼字游戏的算法。


还有其他算法可能更有效,尤其是在首先返回较短的单词时。

一种方法是构建一棵树。

根节点是一个“零”字母词。作为根节点的子节点,将是所有单字母单词的节点。每个节点都将被标记它是否代表一个有效的单词。作为这些节点的子节点,您将拥有所有可能的三字母词,再次标记为它是否有效。

这将是很多节点。对于长度不超过 12 个字母的单词,可能的总空间为 1 + 26 + 26**2 + 26**3 + 26**4 + ...

但是您不需要存储每个可能的节点,您只需存储那些产生有效单词的分支。你不会在下面有分支 ->Z->Z 或 ->X->Q

然而,你会在 ->X->Y->L 下有一个分支,即使 XYL 不是一个词,它也会是通往 'XYLOPHONE' 的分支的开始

但这是一种树遍历算法,根本不同。

【讨论】:

    【解决方案2】:

    听起来你需要了解indexes。如果在数据库中创建索引,即使所有数据都在一个表中,也不会查询到“无用的字母”。

    您应该提供更多信息,如果从 mysql 控制台运行查询需要多长时间才能返回结果,将结果从数据库移动到 PHP 引擎需要多长时间。例如,您可能会为正在运行的每个查询带回一个 100 兆的结果集,如果是这种情况,请将结果限制为第一个或多个可能的结果。

    要查看返回了多少数据,请在控制台中手动运行一个查询,然后查看返回了多少记录。如果数字很大,数据将需要更长的时间才能传递给 PHP,但这也意味着您的代码必须遍历更多的结果。在找到第一个可以接受的单词后,您可能需要考虑删除我们的 for 循环。如果至少有一个单词是可能的,则在放置另一个字母之前不要再次检查。

    【讨论】:

    • 感谢您提供有关索引的信息。我目前在“Word”列上有一个,但在“Length”列上没有。但是,如果我将所有数据放入一个表中,为什么数据库不会查询无用信息,我对此感到困惑。例如,即使用户输入不允许创建任何“a”词,它是否也会提取所有以“a”开头的词?此外,从 MySQL 控制台运行查询平均每个表大约需要 0.0009 秒,但我不确定如何测试将结果从数据库移动到 PHP 引擎需要多长时间。
    • 您应该在where 子句中使用的字段中或在指向其他表的链接中使用的列中具有索引。这基本上告诉数据库在哪里查看,而无需对所有数据行进行排序。如果将所有数据放在一个表中,则可以添加单个字符并在其上弹出索引。一个索引和长度真的会帮助你的数据库找到正确的数据行。
    【解决方案3】:

    我知道这个问题是关于优化数据库的,但如果我这样做,我只会从数据库中读取一次单词,初始化一些数据结构并搜索该结构,而不是不断地查询数据库。

    对不起,如果这完全无关紧要。

    【讨论】:

      猜你喜欢
      • 2012-07-20
      • 2010-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 2015-12-23
      • 2011-01-23
      • 1970-01-01
      相关资源
      最近更新 更多