1

我正在使用 MySql 和 PHP 向轮询系统添加标签功能。用户将单击一个标签以列出所有带有相应标签的民意调查(AKA 命题)。链接看起来像这样,“/propositions/tagged/baseball”。

我使用 mod_rewrite 将“棒球”标签分配给名为 $tag 的变量。

RewriteRule ^propositions/tagged/(.*)$ /propositions/index.php?tag=$1 [L]

它不返回与投票关联的标签的标签名称。我怎么会得到这些名字?

下面的查询有效,但它不返回与投票关联的标签的标签名称。我怎么会得到这些名字?另外,是否可以更有效地完成它。还有一件事,将标签与投票数据一起存储会更好吗?不久前,我看到 SO 这样做喜欢将标签包含在带有问题的表格列中。不知道他们是否仍然这样做或曾经这样做过,但不久前在某个地方看到或读过它。

非常感谢!

==================================================== =====

pb_prop (
  id int(11) NOT NULL auto_increment,
  active tinyint(1) NOT NULL default '1',
  submit_by int(11) NOT NULL,
  total_votes int(11) NOT NULL default '0',
  removed tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (id)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Described below as ".PROP_TABLE." p

==================================================== =====

pb_prop_tags (
  id int(11) NOT NULL auto_increment,
  prop_id int(11) NOT NULL,
  tag_id int(11) NOT NULL,
  PRIMARY KEY  (id)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Described below as ".PROP_TAGS_TABLE." pt

==================================================== =====

pb_tags (
  tag_id int(11) NOT NULL auto_increment,
  tag_name varchar(64) NOT NULL,
  PRIMARY KEY  (tag_id)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Described below as ".TAGS_TABLE." t

==================================================== =====

pb_prop_answers (
  id int(11) NOT NULL auto_increment,
  prop_id int(11) NOT NULL,
  num_votes int(11) NOT NULL default '0',
  PRIMARY KEY  (id),
  KEY poll_id (prop_id)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

Described below as ".PROP_ANSWERS_TABLE." a

==================================================== =====

下面的工作 SQL ...可以改进吗?自从发布原始 SQL 以来,我在 select 中添加了特定的列...去掉了一些通配符。此外,在 WHERE 中添加了更多内容以更好地过滤结果。

后显示原始 SQL。

        SELECT
                u.username, u.userid,
                p.*,
                pt.prop_id,
                pt.tag_id,
                t.*,
                (
                    SELECT
                            SUM(num_votes)
                    FROM
                            ".PROP_ANSWERS_TABLE." a
                    WHERE
                            a.prop_id = p.id
                ) AS total_votes,
                (
                    SELECT
                            count(*)
                    FROM
                            ".PROP_ANSWERS_TABLE." a
                    WHERE
                            a.prop_id = p.id
                ) AS total_answers
        FROM
                ".PROP_TABLE." p
        INNER JOIN 
                ".TAGS_TABLE." t
            ON 
                t.tag_name LIKE '%".$tag."%'
        INNER JOIN 
                ".PROP_TAGS_TABLE." pt
            ON 
                pt.tag_id = t.tag_id
        LEFT JOIN
                ".USERS_TABLE." u
            ON
                u.userid = p.submit_by
        WHERE
                pt.tag_id = t.tag_id
            AND
                pt.prop_id = p.id
            AND
                p.removed = 0
            AND
                p.active = 1
            AND
                t.tag_id = pt.tag_id
        ORDER BY
                {$sort} {$dir}

原贴SQL:

    SELECT
            u.username, u.userid,
            p.*,
            pt.*,
            (
                SELECT
                        SUM(num_votes)
                FROM
                        ".PROP_ANSWERS_TABLE." a
                WHERE
                        a.prop_id = p.id
            ) AS total_votes,
            (
                SELECT
                        count(*)
                FROM
                        ".PROP_ANSWERS_TABLE." a
                WHERE
                        a.prop_id = p.id
            ) AS total_answers
    FROM
            ".PROP_TABLE." p
    INNER JOIN 
            ".PROP_TAGS_TABLE." pt
            ON 
            pt.tag_id = p.id
    INNER JOIN 
            ".TAGS_TABLE." t
            ON 
            t.tag_name LIKE '%".$tag."%'
    LEFT JOIN
            ".USERS_TABLE." u
            ON
            u.userid = p.submit_by
    WHERE
            p.removed = 0
        AND
            p.active = 1
        AND
            t.tag_id = pt.tag_id
    ORDER BY
            {$sort} {$dir}
4

2 回答 2

0

我认为您可以在没有子查询的情况下执行此操作,只需加入子查询中使用的表并使用主选择中的聚合函数即可。您将需要一个合适的(并且可能很长!) GROUP BY 子句来配合它。

像这样的东西(毫无疑问有错别字)

SELECT u.username, u.userid,
    p.*,
    pt.*,
    SUM(pat.num_votes) AS calc_total_votes,
    COUNT(pat.num_votes) AS calc_total_answers
FROM ".PROP_TABLE." p
INNER JOIN ".PROP_TAGS_TABLE." pt ON pt.tag_id = p.id
INNER JOIN  ".TAGS_TABLE." t ON t.tag_id = pt.tag_id AND t.tag_name LIKE '%".$tag."%'
LEFT JOIN ".PROP_ANSWERS_TABLE." pat ON pat.prop_id = p.id
LEFT JOIN ".USERS_TABLE." u ON u.userid = p.submit_by
WHERE p.removed = 0
AND p.active = 1
GROUP BY u.username, u.userid, p.id, p.active, p.submit_by, p.total_votes , p.removed, pt.id, pt.prop_id, pt.tag_id
ORDER BY {$sort} {$dir}

下面根据您更新的 SQL 修改了 SQL。这是针对子选择执行 JOIN,它应该比每行的子选择更有效。

SELECT u.username, u.userid, p.*, pt.prop_id, pt.tag_id, t.*, Sub1.total_votes, Sub1.total_answers
FROM ".PROP_TABLE." p
INNER JOIN ".PROP_TAGS_TABLE." pt ON pt.prop_id = p.id
INNER JOIN ".TAGS_TABLE." t ON pt.tag_id = t.tag_id
LEFT OUTER JOIN (SELECT prop_id, SUM(num_votes) AS total_votes, count(*) AS total_answers
FROM ".PROP_ANSWERS_TABLE." 
GROUP BY prop_id ) AS Sub1 ON p.id = Sub1.prop_id
LEFT OUTER JOIN ".USERS_TABLE." u ON u.userid = p.submit_by
WHERE t.tag_name LIKE '%".$tag."%'
AND p.removed = 0
AND p.active = 1
ORDER BY {$sort} {$dir}

然而,应该可以只用一个整体 group by 来做这个选择,而不需要一个子选择。

于 2012-10-16T11:43:44.920 回答
0

使用 EXPLAIN 检查您的性能以及在进行 mysql 性能分析时使用了哪些索引。 http://dev.mysql.com/doc/refman/5.0/en/explain.html

如何解释 EXPLAIN 的结果可以在这里看到:http: //dev.mysql.com/doc/refman/5.0/en/explain-output.html 避免这样的事情:

  • 可能的键是“空”
  • 类型列显示“全部”
  • 额外的列显示“使用文件排序”或“使用临时”

我注意到“使用临时”或“使用文件排序”通常是查询末尾附加 SORT BY 语句的结果。

检查索引是否用于所有连接。如果排序方向不反映所用索引的排序方向,则删除 SORT BY 也可能会加快该过程。但是,您必须检查在您的代码或 mysql 中对(小?)结果集进行排序是否更快。

于 2012-10-16T13:31:11.213 回答