2011-07-04 49 views
3

我有這個標籤系統來標記博客條目等。這些標籤位於一張表中,僅包含標籤名稱和主鍵。然後,我有另一個使用標籤的對象。在表中計數實例

它可能是這個樣子:

_________________________________ 
| tags       | 
--------------------------------| 
| id | name     | 
|-------------------------------| 
| 1 | Scuba diving   | 
| 2 | Dancing     | 
--------------------------------- 

_________________________________ 
| tag_objects     | 
--------------------------------| 
| id | tag | object   | 
|-------------------------------| 
| 1 | 2 | 13    | 
| 2 | 2 | 18    | 
| 3 | 1 | 24    | 
--------------------------------- 

現在,我需要完成的是一列添加到標籤表,被稱爲「事件」或什麼的。對於標籤中的每個標籤,出現次數應設置爲tag_objects中標籤的使用次數。

所以基本上是這樣(顯然僞代碼):

foreach(tags): 
    UPDATE tags 
     SET occurrences = (SELECT COUNT(id) 
          FROM tag_objects 
          WHERE tag = tags.id); 

當人們創造未來的新職位和東西,我只是有一個觸發更新計數,但我有一對夫婦已經有數千行了,我需要先計算一下。我不知道如何做到這一點,所以任何援助將不勝感激。

回答

4

要做到這一點,最簡單的方式提供的SQL,沒有任何多餘的表格,將是:

首先添加額外的字段:

mysql> alter table標籤添加發生int 默認爲0;

然後,只需更新此新字段的出現次數。

的MySQL>更新代碼左加入(選擇標籤, 計數(ID),如從tag_objects 組按標籤CNT)作爲SUBQ上 tags.id = subq.tag設置 發生聚結=(subq.cnt ,0);

請注意使用左連接來確保所有標記都被計數,即使是未使用的標記也是如此。合併函數將NULL轉換爲0.

+0

這很好用。謝謝! –

0

我想你會得到更好的表現,如果你將遞增和遞減表tag_objects插入/刪除觸發器occurrences的值。

+0

當然,我將在未來做到這一點。不過,我正在一個已經有幾千行的相當老的數據庫上實現它。我只打算運行一次,然後添加一個觸發器來更新它。 –

+0

這不一定是真的。這一切都取決於更新/插入/刪除的數量!如果這個數字很大,那麼觸發器可能實際上鎖定標籤表的時間太長了,以至於事情變慢了很多! – Eljakim

+0

在標準情況下,讀取的標籤數據不止變化。如果不是,標籤的使用是有問題的。 – Gedrox

0

你的psuedeo代碼將完全按照書面形式工作(沒有foreach循環)。至少在oracle中,我假設MySQL允許您使用相關的子查詢作爲值。

1

你已經做了一個很好的工作,你的查詢必須工作。

但是,這會導致可怕的表現。我建議你重新創建一個表格:

CREATE TABLE newTags AS 
SELECT t.id, t.name, COUNT(*) AS occurrences 
FROM tags t 
    INNER JOIN tag_objects to 
     ON to.tag = tags.id 
GROUP BY t.id, t.name 

這將是非常快的。

0

對於插入新行,您可以使用如下查詢: INSERT INTO tags VALUES(x,y,z,1) ON DUPLICATE KEY UPDATE occurrences = occurrences+1; 我沒有檢查語法,但類似的東西。

1

除非您確實需要對數據進行非規範化處理,否則您應該遠離這一點。在索引列上計數通常非常快。我是清潔和標準化的數據;-)

+0

它也傷害了我的靈魂,但是這個數據庫已經癱瘓了,而且它已經經歷了很多,比這更糟糕的事情。我們也有相當一部分流量,因此減少數據庫在每個頁面加載時所做的工作的任何方式都是需要的。 –

+0

啊!我看到...... ;-)在之前的工作中,我處於這種情況。我們花了幾個月的時間進行優化,可以說它的工作效率爲50%。我們通過chyanging硬件和升級(這是一個Oracle數據庫)真正糾正了這個問題。 GL! –

1

我一般不想計算的值存儲在數據庫中列的大風扇 - 這是凌亂的,很容易不同步的,並違背正常化的神靈。但是,如果你真的必須有一個數據庫實體,而不是實時計算,我會創建一個視圖(http://dev.mysql.com/doc/refman/5.0/en/)。創建-view.html),其存儲預先計算的值,使用由天蠍座

CREATE view tag_occurences AS 
SELECT t.id, t.name, 
COUNT(*) AS occurrences 
FROM tags t 
    INNER JOIN tag_objects to 
     ON to.tag = tags.id 
GROUP BY t.id, t.name 
+0

MySQL不支持物化視圖,所以這不會存儲任何東西。它會每次運行查詢。 –

+0

它不需要實現 - 只是將查詢填充到視圖中,而不是每次都運行它。但是,像你一樣,我只是運行查詢,而不是通過視圖。...... –

+0

你誤會了。在MySQL中,查詢視圖與直接運行查詢完全相同。它不預先計算任何值。使用視圖不會影響優化,執行或表I/O。 –