我有一个MySQL数据库,其中包含标准英文字母表中的所有单词,我用它来创建一个简单的Scrabble单词生成器。数据库分为26个表:一个用于字母表中的每个字母。每个表包含两列:
在我的应用程序中,用户输入任意数量的字母到文本框中(表示他们的图块),我使用以下代码查询数据库:
// 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的自动优化功能,但没有提供明显的速度提升。
答案 0 :(得分:3)
我不认为性能问题确实是数据库。数据存储的结构将对算法的性能产生最显着的影响。
解决问题的一个相当容易理解的方法是将问题作为字谜来处理。您可以按字母顺序排列每个单词中的所有字母,并将其存储为带有索引的列。
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谜题中,没有任何空白的瓷砖)
因此,这可能不是Scrabble最合适的算法。
还有其他算法可能更有效,特别是在首先返回较短的单词时。
一种方法是建树。
根节点是一个“零”字母单词。作为根节点的子节点,将是所有单字母单词的节点。将标记每个节点是否表示有效单词。作为这些节点的子节点,您将拥有所有可能的三个字母的单词,再次标记为是否有效。
这将是很多节点。对于长度不超过12个字母的单词,这可能是1 + 26 + 26**2 + 26**3 + 26**4 + ...
但是你不需要存储每个可能的节点,你只存储那些产生有效单词的分支。你不会在下面有分支 - &gt; Z-&gt; Z或 - &gt; X-&gt; Q
但是,你会在 - > X-&gt; Y-> L之下有一个分支,即使XYL不是单词,它也会是导致'XYLOPHONE'的分支的开头
但这是一个树遍历算法,它根本不同。
答案 1 :(得分:2)
听起来你需要了解indexes。如果您在数据库中创建了索引,即使所有数据都在一个表中,它也不会查询“无用的字母”。
您应该提供更多信息,如果您从mysql控制台运行它,返回结果需要多长时间,将结果从数据库移动到PHP引擎需要多长时间。例如,您可能会为正在运行的每个查询带回100兆的结果集,如果是这种情况,请将结果限制为第一个或许多可能的结果。
要查看返回的数据量,请在控制台中手动运行其中一个查询,并查看返回的记录数。如果数字很高,数据将花费更长的时间传递给PHP,但这也意味着您的代码必须迭代更多的结果。在找到可以接受的第一个单词后,您可能需要考虑删除for
循环。如果至少有一个单词是可能的,则在放置另一个字母之前不要再检查它。
答案 2 :(得分:1)
我知道这个问题是关于优化数据库但是如果我这样做,我只会读取数据库中的单词一次,初始化一些数据结构并搜索该结构而不是不断查询数据库。
对不起,如果这完全无关紧要。