2013-10-30 58 views
1

我建立一個星型模式作爲後端爲分析應用程序我建立。我的查詢生成器使用常規星形連接模式構建查詢。下面是一個示例查詢,其中事實表連接到兩個維度表,維度表由最終用戶選擇的常量值過濾。MySQL查詢設置

我使用MySQL 5.5和所有的表都是MyISAM數據。

在這個問題中,我只是試圖拉動第一N行(在此情況下,第一行1)

EXPLAIN 
SELECT fact_table.* 
FROM 
    fact_table 
INNER JOIN 
    dim1 ON (fact_table.dim1_key = dim1.pkey) 
INNER JOIN 
    dim2 ON (fact_table.dim2_key = dim2.pkey)   
WHERE 
    dim1.constant_value = 123 
    AND dim2.constant_value = 456 
ORDER BY 
    measure1 ASC LIMIT 1 

解釋輸出如下。由於有一個唯一的鍵應用於其值,因此這兩個維鍵都解析爲常量值。

*************************** 1. row *************************** 
     id: 1 
select_type: SIMPLE 
    table: dim1 
    type: const 
possible_keys: PRIMARY,dim1_uk 
     key: dim1_uk 
    key_len: 8 
     ref: const 
    rows: 1 
    Extra: Using filesort 
*************************** 2. row *************************** 
     id: 1 
select_type: SIMPLE 
    table: dim2 
    type: const 
possible_keys: PRIMARY,dim2_uk 
     key: dim2_uk 
    key_len: 8 
     ref: const 
    rows: 1 
    Extra: 
*************************** 3. row *************************** 
     id: 1 
select_type: SIMPLE 
    table: fact_table 
    type: ref 
possible_keys: my_idx 
     key: my_idx 
    key_len: 16 
     ref: const,const 
    rows: 50010 
    Extra: Using where 

這裏是在事實表上的索引:

show indexes from fact_table 

*************************** 10. row *************************** 
    Table: fact_table 
Non_unique: 1 
Key_name: my_idx 
Seq_in_index: 1 
Column_name: dim1_key 
Collation: A 
Cardinality: 24 
Sub_part: NULL 
    Packed: NULL 
    Null: 
Index_type: BTREE 
    Comment: 
Index_comment: 
*************************** 11. row *************************** 
    Table: fact_table 
Non_unique: 1 
Key_name: my_idx 
Seq_in_index: 2 
Column_name: dim2_key 
Collation: A 
Cardinality: 70 
Sub_part: NULL 
    Packed: NULL 
    Null: 
Index_type: BTREE 
    Comment: 
Index_comment: 
*************************** 12. row *************************** 
    Table: fact_table 
Non_unique: 1 
Key_name: my_idx 
Seq_in_index: 3 
Column_name: measure1 
Collation: A 
Cardinality: 5643 
Sub_part: NULL 
    Packed: NULL 
    Null: 
Index_type: BTREE 
    Comment: 
Index_comment: 

如果在分析此查詢,看到查詢花費執行文件排序操作「排序結果」它的大部分時間。我的問題是,即使在使用正確的索引時,爲什麼這個查詢不能簡單地提取第一個值而不進行排序呢?如計劃中所示,my_idx已經在右列上排序,並且索引中第一個出現的兩列解析爲常量。

如果我重寫查詢,如下,我能得到我想要的計劃,沒有文件排序。

SELECT fact_table.* 
FROM 
    fact_table 
WHERE 
    dim1_key = (select pkey from dim1 where constant_value = 123) 
    AND dim2_key = (select pkey from dim2 where constant_value = 456) 
ORDER BY 
    measure1 ASC LIMIT 1 

這將是昂貴的改變工具生成這些SQL命令,所以我想避免,即使查詢被寫在原始格式此文件排序。

我的問題是,爲什麼選擇加入的MySQL做文件排序,即使在索引中的第一項是常數(通過INNER JOIN)和索引按正確的順序進行排序?有沒有解決的辦法?

+0

。 。作爲觀察,這兩個查詢是不一樣的。首先是從三個表中返回值。第二個是從一個表中返回值。 –

+0

謝謝,當我爲該帖子混淆表名時,這只是我的錯誤。我修復了它。 –

回答

0

我的問題是,即使索引上的第一個鍵是常量(通過INNER JOIN)並且索引按正確的順序排序,爲什麼MySQL選擇執行文件索引?有沒有解決的辦法?

因爲結果集的順序取決於用於在連接讀取第一個表中的索引,但是,當你看到EXPLAIN,連接實際上是從dim1表開始。

這看起來很奇怪,但要暗中強制MySQL從fact_table開始,您需要將維度表中的索引更改爲(pkey,constantvalue)而不是(constantvalue),否則MySQL優化器將以一個表爲開始條件constantvalue=some_value返回最小行數。問題是你可能需要這些索引來進行其他查詢。

相反,您可以嘗試STRAIGHT_JOIN選項添加到SELECT和明確強制的秩序。

+0

偉大的洞察力,非常感謝。現在做出總體感覺。 –