2013-10-30 56 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

伟大的洞察力,非常感谢。现在做出总体感觉。 –