【问题标题】:MySQL query stuck at "Sorting Result" for a single row result setMySQL 查询停留在单行结果集的“排序结果”
【发布时间】:2013-11-02 01:54:43
【问题描述】:

我正在构建一个星型模式,作为我正在构建的分析应用程序的后端。我的查询生成器正在使用常规星型连接模式构建查询。下面是一个示例查询,其中一个事实表连接到两个维度表,维度表由最终用户选择的常量值过滤。

我使用的是 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 命令的工具会很昂贵,因此即使查询是以原始格式编写的,我也想避免这种文件排序。

我的问题是,即使索引上的第一个键是常量(通过 INNER JOIN)并且索引以正确的顺序排序,为什么 MySQL 仍选择进行文件排序?有没有办法解决这个问题?

【问题讨论】:

  • 。 .作为观察,这两个查询并不相同。第一个是从三个表中返回值。第二种是只从一个表中返回值。
  • 谢谢,这只是我为帖子混淆表名时的一个错误。我已经修好了。

标签: mysql sql query-optimization data-warehouse star-schema


【解决方案1】:

我的问题是,即使索引上的第一个键是常量(通过 INNER JOIN)并且索引以正确的顺序排序,为什么 MySQL 仍选择进行文件排序?有没有办法解决这个问题?

因为结果集的顺序取决于用于读取 JOIN 中第一个表的索引,但是,正如您在 EXPLAIN 中看到的,JOIN 实际上是从 dim1 表开始的。

这可能看起来很奇怪,但是要隐式强制 MySQL 从 fact_table 开始,您需要将维度表中的索引更改为 (pkey, constantvalue) 而不是 (constantvalue),否则 MySQL 优化器将从一个表开始条件constantvalue=some_value 返回最小行数。问题是您可能需要这些索引来进行其他查询。

相反,您可以尝试将 STRAIGHT_JOIN 选项添加到 SELECT 并显式强制排序。

【讨论】:

    猜你喜欢
    • 2017-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多