问题:编写MySQL解析器来拆分JOIN并将它们作为单独的查询运行(动态地对查询进行非规范化)

fir*_*ire 2 php mysql sql dynamic-sql denormalization

我试图找出一个脚本来获取MySQL查询并将其转换为单独的查询,即动态地对查询进行非规范化.

作为一个测试我构建了一个简单的文章系统,有4个表:

  • 用品
    • article_id的
    • article_format_id
    • ARTICLE_TITLE
    • article_body
    • ARTICLE_DATE
  • article_categories
    • article_id的
    • CATEGORY_ID
  • 类别
    • CATEGORY_ID
    • category_title
  • 格式
    • 业态编号
    • format_title

一篇文章可以在多个类别中,但只有一种格式.我觉得这是现实生活中的一个很好的例子.

在列出所有文章的类别页面上(同时提取format_title),可以使用以下查询轻松实现:

SELECT articles.*, formats.format_title 
FROM articles 
INNER JOIN formats ON articles.article_format_id = formats.format_id 
INNER JOIN article_categories ON articles.article_id = article_categories.article_id 
WHERE article_categories.category_id = 2 
ORDER BY articles.article_date DESC
Run Code Online (Sandbox Code Playgroud)

但是,我尝试构建的脚本将接收此查询,解析它并单独运行查询.

所以在这个类别的页面示例中,脚本将有效地运行它(动态计算):

// Select article_categories
$sql = "SELECT * FROM article_categories WHERE category_id = 2";
$query = mysql_query($sql);
while ($row_article_categories = mysql_fetch_array($query, MYSQL_ASSOC)) {

    // Select articles
    $sql2 = "SELECT * FROM articles WHERE article_id = " . $row_article_categories['article_id'];
    $query2 = mysql_query($sql2);
    while ($row_articles = mysql_fetch_array($query2, MYSQL_ASSOC)) {

        // Select formats
        $sql3 = "SELECT * FROM formats WHERE format_id = " . $row_articles['article_format_id'];
        $query3 = mysql_query($sql3);
        $row_formats = mysql_fetch_array($query3, MYSQL_ASSOC);

        // Merge articles and formats
        $row_articles = array_merge($row_articles, $row_formats);

        // Add to array
        $out[] = $row_articles;
    }
}

// Sort articles by date
foreach ($out as $key => $row) {
    $arr[$key] = $row['article_date'];
}

array_multisort($arr, SORT_DESC, $out);

// Output articles - this would not be part of the script obviously it should just return the $out array
foreach ($out as $row) {
    echo '<p><a href="article.php?id='.$row['article_id'].'">'.$row['article_title'].'</a> <i>('.$row['format_title'].')</i><br />'.$row['article_body'].'<br /><span class="date">'.date("F jS Y", strtotime($row['article_date'])).'</span></p>';
}
Run Code Online (Sandbox Code Playgroud)

这样做的挑战是按照正确的顺序计算正确的查询,因为您可以在查询中以任何顺序放置SELECT和JOIN的列名(这是MySQL和其他SQL数据库转换得如此之好)并编制信息逻辑用PHP.

我目前正在使用SQL_Parser解析查询,它可以很好地将查询拆分成多维数组,但是解决上面提到的问题很麻烦.

任何帮助或建议将不胜感激.

A. *_*nce 13

从我收集到的内容中,您试图在第三方论坛应用程序(可能无法修改代码?)和MySQL之间添加一层.该层将拦截查询,将它们重新编写为可单独执行,并生成PHP代码以对数据库执行它们并返回聚合结果.这是一个非常糟糕的主意.

你暗示不可能添加代码并同时建议生成要添加的代码,这似乎很奇怪.希望你不打算使用像funcall之类的东西来注入代码.这是一个非常糟糕的主意.

其他人要求避免您的初始方法并专注于数据库是非常合理的建议.我会把自己的声音添加到希望不断增长的合唱中.

我们假设一些限制:

  • 你正在运行MySQL 5.0或更高版本.
  • 查询无法更改.
  • 无法更改数据库表.
  • 您已经为麻烦的查询引用的表准备了适当的索引.
  • 您已经三次检查慢速查询(并运行EXPLAIN)命中数据库,并尝试设置可帮助它们更快运行的索引.
  • 内部联接对MySQL安装的负载是不可接受的.

三种可能的解决方

  1. 通过将运行的硬件升级到具有更多内核,更多(尽可能多的)RAM和更快磁盘的内容,您可以轻松地将资金投入到当前数据库中来处理这个问题.如果你有钱,Fusion-io的产品会被强烈推荐用于此类产品.这可能是我提供的三个选项中更简单的一个
  2. 设置第二个主MySQL数据库并将其与第一个配对.确保你有能力强制AUTO_INCREMENT id交替(一个DB使用偶数id,另一个奇数).这不会永远扩展,但它确实为您提供了硬件和机架空间价格的喘息空间.再次,加强硬件.你可能已经这样做了,但如果没有,那就值得考虑了.
  3. 使用像dbShards这样的东西.你仍然需要投入更多的硬件,但是你可以扩展到两台机器之外的额外好处,你可以随着时间的推移购买更低成本的硬件.