适当的索引(或删除)来优化大型数据集表

时间:2012-06-20 16:30:58

标签: mysql sql optimization query-optimization

我们正在进行“访问者”跟踪架构 - 推送时,似乎会对数据库服务器造成一些压力。

VISITORS表通过HASH识别唯一用户(当前记录310,000)。对散列执行搜索,如果未找到,则添加。以下两个表需要ID

CREATE TABLE  visitors (
    id int(10) UNSIGNED NOT NULL auto_increment,
    ip varchar(25) NOT NULL,
    hash varchar(64) NOT NULL,
    first_visit varchar(32) NOT NULL,
    created_at datetime NOT NULL default '0000-00-00 00:00:00',
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;   

ALTER TABLE visitors ADD UNIQUE INDEX (hash);
ALTER TABLE visitors ADD INDEX (created_at);

VISITOR_VISITS表仅在我们可以识别某些推荐来源(当前计数为142,000)时识别用户何时访问。执行搜索以查找visitor_id,type和visit_date。如果找不到任何东西 - 它会被添加。该ID用于下表。

CREATE TABLE  visitor_visits (
    id int(10) UNSIGNED NOT NULL auto_increment,
    visitor_id int(10) UNSIGNED NOT NULL,
    source varchar(64) NULL DEFAULT NULL DEFAULT NULL,
    medium varchar(64) NULL DEFAULT NULL,
    campaign varchar(256) NULL DEFAULT NULL,
    page varchar(32) NULL DEFAULT NULL,
    landing varchar(32) NULL DEFAULT NULL,
    type enum('fundraiser_view') NULL DEFAULT NULL,
    visit_date date NOT NULL default '0000-00-00',
    created_at datetime NOT NULL default '0000-00-00 00:00:00',
    PRIMARY KEY (id)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

ALTER TABLE visitor_visits ADD UNIQUE INDEX (visitor_id,type,visit_date);
ALTER TABLE visitor_visits ADD CONSTRAINT FK_visits_visitor_id FOREIGN KEY (visitor_id) REFERENCES visitors(id);

PAGE_VIEWS记录单个页面视图(不是所有页面,只记录我们正在跟踪的页面)。它可以链接到访问者并且可以引用visitor_visit(当前计数为240万 - 因为它更高的是我们在记录单个页面后开始微访问者记录)。插入/重复查询用于基于所标识用户的view_date将记录添加到此。由于不需要ID,因此不需要纯查询查询

CREATE TABLE page_views (
  id int(10) UNSIGNED NOT NULL auto_increment,
  page_id int(10) UNSIGNED NOT NULL,
  current_donations decimal(10,2) NOT NULL DEFAULT 0,
  ip varchar(25) NOT NULL,
  hash varchar(32) NOT NULL,
  visitor_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
  visitor_visit_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
  page_views int(10) UNSIGNED NOT NULL DEFAULT 0,
  widget_views int(10) UNSIGNED NOT NULL DEFAULT 0,
  view_date date NOT NULL,
  viewed_at datetime NOT NULL default '0000-00-00 00:00:00',
  created_at datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

ALTER TABLE page_views ADD UNIQUE INDEX (page_id,view_date,visitor_id,hash);
ALTER TABLE page_views ADD INDEX (visitor_id);
ALTER TABLE page_views ADD INDEX (visitor_visit_id);
ALTER TABLE page_views ADD CONSTRAINT FK_page_views_page_id FOREIGN KEY (page_id)    REFERENCES pages(id);
ALTER TABLE page_views ADD CONSTRAINT FK_page_views_visitor_id FOREIGN KEY (visitor_id)    REFERENCES visitors(id);
ALTER TABLE page_views ADD CONSTRAINT FK_page_views_visit_id FOREIGN KEY (visitor_visit_id) REFERENCES visitor_visits(id);

上周,由于一篇新闻文章,我们的网站引起了人们的流入,这位访问者发现了一些瓶颈性能。我想知道那里是否有明显的优化。可能是外键限制吗?过索引?需要更好的索引?

2 个答案:

答案 0 :(得分:0)

试试这个:: 1)varchar上的索引并没有太大改善性能。 2)尝试在日期范围内对表进行分区。

答案 1 :(得分:0)

你没有告诉我们是什么是你数据库的瓶颈,所以我猜它是InnoDB并发写入。如果不是这样,问题只出现在SELECTs(我怀疑),你应该向我们展示确切的查询。您可以尝试通过创建临时表然后将内容从主表移动到主表来降低写入性能:

CREATE TABLE page_views_tmp (
  id int(10) UNSIGNED NOT NULL auto_increment,
  page_id int(10) UNSIGNED NOT NULL,
  current_donations decimal(10,2) NOT NULL DEFAULT 0,
  ip varchar(25) NOT NULL,
  hash varchar(32) NOT NULL,
  visitor_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
  visitor_visit_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
  page_views int(10) UNSIGNED NOT NULL DEFAULT 0,
  widget_views int(10) UNSIGNED NOT NULL DEFAULT 0,
  view_date date NOT NULL,
  viewed_at datetime NOT NULL default '0000-00-00 00:00:00',
  created_at datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY (id)
) ENGINE=MEMORY DEFAULT CHARSET=utf8; 

然后,每隔几秒或在此表中有相当多的行之后:

START TRANSACTION;

INSERT INTO page_views SELECT * FROM page_views_tmp;
DELETE FROM page_views_tmp;

COMMIT;