优化MySQL数据库的方法


Ways to optimize my MySQL database

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

  • "Word"列:此列是主键,类型为char(12),不接受null值
  • "Length"列:此列包含一个无符号的tinyint值,不接受null值

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

// 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的自动优化功能,但没有明显提高速度。

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

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

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') 

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

(在Crossword和Jumble谜题中,没有任何空白方块)

因此,这可能不是最适合拼字游戏的算法。


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

一种方法是建造一棵树。

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

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

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

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

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

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

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

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

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

很抱歉,如果这完全无关。