2012-06-20 22 views
1

我們有一個'訪問者'跟蹤模式正在進行 - 當推送時,似乎在DB服務器上造成一些壓力。正確的索引(或刪除)來優化大型數據集表

VISITORS表通過HASH標識唯一用戶(當前記錄310,000)。在散列上執行搜索,如果未找到,則會添加它。需要使用下面的兩個表,當用戶訪問,只有當我們可以識別某些引薦來源(當前計數142000)

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表標識ID。執行搜索查找visitor_id,類型和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); 

上週,我們的網站得到的人流入,由於新聞文章,這訪客識別曼仕龍瓶頸的性能。我想知道是否有明顯的優化。它可能是外鍵約束嗎?超過索引?需要更好的索引?

回答

0

試試這個:: 1)varchar上的索引沒有太大的提高性能。 2)嘗試在日期範圍內對錶格進行分區。

+0

你的意思是根據日期範圍創建兩個(或多個)表嗎? – cgmckeever

+0

無需創建表,創建具有大量數據的單個表的多個分區 –

+0

有沒有辦法讓動態分區?還是必須根據需要添加分區?例如,是否可以無限地添加基於月份組合的分區,而不是定義每個分區的組合範圍? http://dev.mysql.com/doc/refman/5.1/en/partitioning-overview.html http://forums.mysql.com/read.php?106,264106,264110 – cgmckeever

0

你沒有告訴我們什麼是瓶頸你的數據庫,所以我只是猜測它是InnoDB併發寫入。如果不是這樣,問題只在於SELECT(我懷疑),你應該向我們顯示確切的查詢。你可以儘量減少通過創建臨時表,然後批量移動從主表的東西打在寫入性能:

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;