【问题标题】:Mysql unique index for voting system投票系统的mysql唯一索引
【发布时间】:2012-02-21 12:01:25
【问题描述】:

在用于记录帖子投票的表格中

CREATE TABLE votes
(
vote_id int(11) NOT NULL AUTO_INCREMENT,
post_id int(11) REFERENCES posts(post_id) ON DELETE CASCADE,
user_id int(11) REFERENCES users(user_id) ON DELETE SET NULL,
vote ENUM('Up', 'Down'),
ip varchar(255),
UNIQUE INDEX (on which???)
PRIMARY KEY(vote_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci

如何添加UNIQUE INDEX以避免重复投票?如果投票者是用户,UNIQUE INDEX 应该适用于 (post_id, user_id);如果不是用户,UNIQUE INDEX 应该适用于 (post_id, ip)。

其实我只需要UNIQUE INDEX for (post_id, user_id) OR (post_id, ip);但不是两者兼而有之。

【问题讨论】:

    标签: mysql sql unique unique-constraint


    【解决方案1】:

    修订后的更多信息 具体按照您的要求,我建议如下。添加源表以进一步规范化

    CREATE TABLE vote_sources (
        source_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
        // 0 will be treated as anonymous, as NULL can have issues on UNIQUE indexes
        user_id INT(11) UNSIGNED NOT NULL REFERENCES users(user_id) ON DELETE SET 0,
        ip VARCHAR(15) NOT NULL,
        dupeCheck VARCHAR(15) NOT NULL,
        PRIMARY KEY(source_id),
        UNIQUE INDEX (dupeCheck)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
    
    CREATE TABLE votes
    (
        vote_id int(11) NOT NULL AUTO_INCREMENT,
        post_id int(11) REFERENCES posts(post_id) ON DELETE CASCADE,
        source_id int(11) NOT NULL REFERENCES vote_sources(source_id) ON DELETE CASCADE,
        vote ENUM('Up', 'Down'),
        PRIMARY KEY(vote_id),
        UNIQUE INDEX(post_id,source_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci
    

    然后处理欺骗检查这个触发器

    CREATE TRIGGER dupeSourceCheck
    BEFORE INSERT ON vote_sources
    FOR EACH ROW SET NEW.dupeCheck = IF(NEW.user_id>0,CAST(NEW.user_id AS CHAR),NEW.ip)
    

    如果详细说明了重复源,这又会导致重复键错误,同时仍会公开数字 user_id 以获得更有效的连接。

    【讨论】:

    • 1) 第一种情况只索引用户的重复投票,第二种情况不考虑user_id。 2) varchar(15) 和 varchar(255) 的存储大小相等。
    • VARCHAR(15) 和 VARCHAR(255) 的存储大小是相等的,因为字段存储大小是 StringLength+1 字节,字符串最多 255 个字节,但是 IP 不会超过 15 个字符和所以没有必要有一个比你需要的更大的字段,因为它会导致索引出现问题。
    • 当然,当不需要更长的字段时,最好使用 varchar(15)。感谢您提醒我,我一定会更新我的代码;我只是说这不是我现在最关心的问题:)
    • 你离开它的时间越长,它就越难改变,最好在进行其他更改的同时进行优化,而不是推迟到另一天;)
    • 下来了?我?我一直很感激人们花时间回答问题!
    【解决方案2】:

    我建议规范化:创建另一个字段,如 vote_src VARCHAR(15),从您的代码中获取用户或 IP,并在此创建唯一索引。

    【讨论】:

    • 非常好的技巧;虽然它会由于重复列而增加存储量!
    • 当然会,但是在存储和所有其他可能性的丑陋之间进行选择,我会选择存储。请记住,VARCHAR(15) 最大为 18 字节,因此 100 万票将是 18 兆字节 ...
    • 你说的很对!但我希望找到另一种方式,因为投票栏迅速增加(以百万计,每票投一次)。
    • @Ali 如果您每天有数百万票,那么性能比存储重要得多——在这种情况下,带有附加列的“简单”索引将比任何“棘手”索引执行得更好索引。
    【解决方案3】:

    你有 PHPMyAdmin 吗?在那里很容易做到这一点。你想让一个字段成为 PRIMARY KEY 还是你真的只想要一个 UNIQUE 索引?如果您有 PHPMyAdmin 作为选项,您可以转到您的结构选项卡,在底部您将看到一个索引表,其中可以选择添加索引。点击“GO”,然后哇!你有你的索引。

    【讨论】:

    • 你在说什么?怎么编辑都无所谓,我说的是表结构。附言我从不使用 PHPMyAdmin,因为命令行是我的老朋友 ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 2015-05-18
    • 1970-01-01
    • 2012-07-14
    • 2015-01-08
    相关资源
    最近更新 更多