2011-04-08 22 views
0

我在MYSQL中有一個很大的基礎 - 300 MB,其中有4個表格:第一個約200MB,第二個約80. 第一個表中有150 000個記錄,第二個表中有200 000個記錄。選擇需要很長時間。如何解決這個問題呢?

同時我在那裏使用inner join。

選擇需要3秒,當我使用優化和indeces(在此之前,它需要大約20-30秒)。 這是足夠好的結果。但我需要更多,因爲頁面加載7-8秒(選擇3-4,計數1,另一個小查詢1秒,頁面生成1-2)。

那麼,我該怎麼做呢?可能是postgres比mysql更少花費時間?或者使用memcaches可能會更好,但在這種情況下,它可能需要大量內存(排序的變體太多)。

可能任何人有另一個想法?我會很高興聽到新的:)


好的。我看到我們需要查詢:) 我重命名了table_1的字段。

 CREATE TABLE `table_1` (
     `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
     `field` varchar(2048) DEFAULT NULL, 
     `field` varchar(2048) DEFAULT NULL, 
     `field` int(10) unsigned DEFAULT NULL, 
     `field` text, 
     `field` text, 
     `field` text, 
     `field` varchar(128) DEFAULT NULL, 
     `field` text, 
     `field` text, 
     `field` text, 
     `field` text, 
     `field` text, 
     `field` varchar(128) DEFAULT NULL, 
     `field` text, 
     `field` varchar(4000) DEFAULT NULL, 
     `field` varchar(4000) DEFAULT NULL, 
     `field` int(10) unsigned DEFAULT '1', 
     `field` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
     `field` text, 
     `new` tinyint(1) NOT NULL DEFAULT '0', 
     `applications` varchar(255) DEFAULT NULL, 
     PRIMARY KEY (`id`), 
     KEY `indexNA` (`new`,`applications`) USING BTREE 
    ) ENGINE=InnoDB AUTO_INCREMENT=153235 DEFAULT CHARSET=utf8; 

CREATE TABLE `table_2` (
    `id_record` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `catalog_name` varchar(512) NOT NULL, 
    `catalog_url` varchar(4000) NOT NULL, 
    `parent_id` int(10) unsigned NOT NULL DEFAULT '0', 
    `checked` tinyint(1) NOT NULL DEFAULT '0', 
    `level` int(10) unsigned NOT NULL DEFAULT '0', 
    `work` int(10) unsigned NOT NULL DEFAULT '0', 
    `update` int(10) unsigned NOT NULL DEFAULT '1', 
    `type` int(10) unsigned NOT NULL DEFAULT '0', 
    `hierarchy` varchar(512) DEFAULT NULL, 
    `synt` tinyint(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id_record`,`type`) USING BTREE, 
    KEY `rec` (`id_record`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=14504 DEFAULT CHARSET=utf8; 

CREATE TABLE `table_3` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `id_table_1` int(10) unsigned NOT NULL, 
    `id_category` int(10) unsigned NOT NULL, 
    `work` int(10) unsigned NOT NULL DEFAULT '1', 
    `update` int(10) unsigned NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    KEY `site` (`id_table_1`,`id_category`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=203844 DEFAULT CHARSET=utf8; 

有查詢是: 1)得到一般計數(需要不到1秒):

SELECT count(table_1.id) FROM table_1 
INNER JOIN table_3 ON table_3.id_table_id = table_1.id 
INNER JOIN table_2 ON table_2.id_record = table_3.id_category 
WHERE ((table_2.type = 0) 
AND (table_3.work = 1 AND table_2.work = 1) 
AND (table_1.new = 1))AND 1 IN (table_1.applications) 

2)獲取列表用於與限制頁(它從3到7秒,取決於on count):

SELECT table_1.field, table_1.field, table_1.field, table_1.field, table_2.catalog_name FROM table_1 
INNER JOIN table_3 ON table_3.id_table_id = table_1.id 
INNER JOIN table_2 ON table_2.id_record = table_3.id_category 
WHERE ((table_2.type = 0) 
AND (table_3.work = 1 AND table_2.work = 1) 
AND (table_1.new = 1))AND 1 IN (table_1.applications) LIMIT 10 OFFSET 10 
+0

也許你可以縮小問題到特定的表,他們是如何設置的,你有多少行從他們回來?通過適當的索引和精心設計的表架構,您可以顯着提高性能。 – 2011-04-08 17:57:46

+0

如果您將此查詢降至0秒 - 總共5秒的加載時間仍然不可接受? – Randy 2011-04-08 17:58:04

+0

你給了我們幾乎沒有什麼可用的......我們不知道查詢是什麼。我們不知道你有什麼指數。你必須給我們一些東西。 – tster 2011-04-08 17:58:46

回答

2

除了別人提供的所有其他建議外,我對MySQL下的性能影響稍微改動了一下,並沒有給出正面評價。但是,我添加了STRAIGHT_JOIN,因此優化器不會嘗試考慮爲您加入哪個訂單或表。

接下來,我將「AND」條件移入表2 & 3的相應JOIN子句中。

最後,從表1加盟3有(在您的文章)

table_3.id_table_id = table_1.id 

,而不是

table_3.id_table_1 = table_1.id 

此外,我不能告訴表現,但也許有一項獨立僅在「新」列中進行單獨索引,以便首先完全匹配,而不考慮「應用程序」列。我不知道複合索引是否會引起問題,因爲您正在使用「IN」作爲應用程序,而不是真正的可索引搜索基礎。

下面是修改後的結果

SELECT STRAIGHT_JOIN 
     count(table_1.id) 
    FROM 
     table_1 
      JOIN table_3 
       ON table_1.id = table_3.id_table_1 
        AND table_3.work = 1 
       JOIN table_2 
        ON table_3.id_category = table_2.id_record 
        AND table_2.type = 0 
        AND table_2.work = 1 
    WHERE 
      table_1.new = 1 
     AND 1 IN table_1.applications 


SELECT STRAIGHT_JOIN 
     table_1.field, 
     table_1.field, 
     table_1.field, 
     table_1.field, 
     table_2.catalog_name 
    FROM 
     table_1 
      JOIN table_3 
       ON table_1.id = table_3.id_table_1 
       AND table_3.work = 1 
       JOIN table_2 
        ON table_3.id_category = table_2.id_record 
        AND table_2.type = 0 
        AND table_2.work = 1 
    WHERE 
      table_1.new = 1 
     AND 1 IN table_1.applications 
    LIMIT 10 OFFSET 10 
+0

@Anthony,順便說一句,WAS在它上面獲得了多少性能,因爲它顯然是從「接受」的答案中獲得的。 – DRapp 2011-04-08 19:50:50

2

您應該查看特定於您使用的最頻繁/耗時的查詢的索引。檢查this post爲mysql建立索引。

0

您還應該優化您的查詢。

+0

如果只有他告訴我們這是什麼! – dlev 2011-04-08 18:05:19

0

沒有看看這個陳述,只能用理論方法來回答這個問題。只是一些想法考慮到...

的select語句...

首先,請確保您的查詢是「好」,因爲它可以。你有可能錯過了什麼?這些獨立的字段類型是否相同?你可以縮小查詢範圍嗎?這樣數據庫就可以少用了嗎?

查詢緩存...

如果反覆查詢是相當的時候,它可能有助於使用Query cache或 - 如果你已經在使用它 - 給它更多的內存。

硬件...

當然不同的RDBMS的是比別人慢或更快,這取決於他們的實力和弱點,但如果你的查詢優化被遺忘,你只可以更快地得到它,而縮放數據庫服務器(更好的CPU,更好的I/O等等,取決於瓶頸在哪裏)。

其他因素...

如果這一切都已經超出,也許嘗試加快其他組件(1-2秒的頁面生成看起來很慢)。

對於所有這些因素,在stackoverflow.com有大量的想法和帖子。

3

不要更改DBMS

我不會建議改變你的DBMS,它可能是非常具有破壞性的。如果您使用了與Postgres不兼容的MySQL特定查詢,您可能需要重做整個索引等,即使這樣也不能保證性能改進。

緩存是一個不錯的選擇

緩存是很好的主意。它需要從您的DBMS中取出負載。如果您有重讀,輕寫,這是最適合的。這樣對象會在Cache中保留更多時間。 MemcacheD是非常好的緩存機制,而且非常簡單。快速擴展站點(如Facebook等)大量使用MemcacheD來緩解數據庫的負載。

如何規模化發展真正的大時代

雖然你沒有很重的數據..所以最有可能的緩存會幫助你。但緩存之前的下一步是基於noSQL的解決方案,如Cassandra。我們在我們的一個應用程序中使用cassandra,在這個應用程序中,我們有大量的讀寫操作(50:50),並且數據庫真的很大,而且速度很快。卡桑德拉表現出色。但是,我想你的情況,卡桑德拉是一個矯枉過正

但是...

之前,你潛入任何重大變化,我建議要真正考慮指標。嘗試垂直縮放。研究慢速查詢。 (搜索slow query logging指令)。希望MySQL在優化這些東西后會更快,而且你不需要額外的工具。

0

這實際上並不是這麼大的數據庫,對於你的數據庫系統來說肯定不會太多。作爲比較,我們正在使用的數據庫目前大約爲40GB。但它是一個MS SQL Server,因此它不是直接可比較的,但數據庫系統之間沒有顯着差異。

我的猜測是,你還沒有完全成功地使用索引來加快查詢。您應該查看查詢的執行計劃並查看是否可以發現大部分時間內執行的部分執行。

相關問題