MySQL从多个结构相同的表中选择

时间:2016-01-16 02:07:25

标签: mysql sql aggregate

让我先说明是的,我知道即使初学DBA也应该知道这个问题的答案,但我从来没有接受过任何正式的培训,而且经过相当多的谷歌搜索后我找不到答案所以请放轻松我:)

我有一个包含88个相同(在结构中,而不是数据中)表的数据库,总共20465行。我正在寻找一种方法来聚合这些,所以我可以:

SELECT * FROM [aggregate] WHERE id = 'some unique value';

我提出的(工作但非常慢)解决方案是从每个表格中select *创建一个视图,然后union将它们放在一起,但是在进行搜索时我很明显这不是正确的方法。例如,选择约200条记录需要一分多钟。

这似乎不是连接的用例,因为表彼此无关,它们只包含相同类型的数据。

我感觉索引是我正在寻找的,但我不确定我是否应该索引视图(我的谷歌搜索似乎表明这是不可能的?)或者如果我可能不正确理解索引

任何有关正确方向的提示都将不胜感激! (即使它只是一些文档的链接)。

2 个答案:

答案 0 :(得分:0)

评论者是对的。使用UNION ALL而不是UNIONUNION ALL并未尝试对UNION所执行的行进行重复数据删除。即使没有任何重复,重复数据删除也是很多工作。

您需要使用一系列UNION ALL操作将所有这些表视为一个表。这就是你如何做到的。

如果是我,我将运行此查询一次:

  CREATE new_table AS
             SELECT 1 source, * FROM table1
  UNION ALL  SELECT 2 source, * FROM table2
  UNION ALL  SELECT 3 source, * FROM table3
       etc etc ad nauseam
  UNION ALL  SELECT 88 source, * FROM table88

然后使用new_table进行所有未来的工作。之后,我放弃了88张桌子。

答案 1 :(得分:0)

可以为视图定义声明索引。 (谷歌是对的。)

但是,您可以在88个表中的每个表上添加索引。要创建哪些索引实际上取决于数据分布,基数以及最重要的是针对这些表运行的查询。索引不是灵丹妙药。对于某些查询模式,没有索引可以提供帮助。所以,在我们开始创建索引之前......

视图在MySQL中的工作方式通知观察到的性能问题

了解如何在MySQL中处理引用视图定义的查询是理解为什么视图可能导致性能问题的关键,这些性能问题可以捕获未经意识到的未知。

过于简单的回答跳过"视图很糟糕"浪潮。并且它并没有真正回答为什么观看视频的表现很糟糕"。

以下是一些絮絮叨叨......并且可以使用一个很好的编辑。

对于旧版本的MySQL,视图定义始终具体化。在MySQL白话中,它被称为派生表。当您了解操作顺序时,他们使用它的名称是有意义的。无论它是内联视图(在查询中用作行源的SELECT语句),还是对存储视图的引用(作为对象存储的SELECT语句),都会观察到相同的行为。数据库。)

性能问题伴随着外部查询中谓词的处理。在旧版本的MySQL中,外部查询中的谓词从不被推送到视图定义中。如果视图是内联的或存储的,则无关紧要。

作为简化演示,请考虑以下问题:

SELECT v.mycol
  FROM ( SELECT t.mycol 
           FROM bigtable t
       ) v
 WHERE v.mycol = 'foo'

MySQL中的操作顺序是首先在parens之间运行查询,并将其具体化为派生表。表现是按照

的顺序进行的
CREATE TEMPORARY TABLE v (mycol mydatatype);
INSERT INTO v (mycol) SELECT t.mycol FROM bigtable t; 

对于满足某些特定要求的小型表,MySQL将使用MEMORY引擎。如果表格不符合要求或超过一定的大小,那么MySQL会将其作为MyISAM表格转移到磁盘上。

完成该操作后,可以运行外部查询。运行时,可以像常规表一样访问v

SELECT v.mycol
  FROM v
 WHERE v.mycol = 'foo'

使用该查询,MySQL必须为mycol(派生表)中的每个行评估v,以确定行是否匹配。就性能而言,这很痛苦。

(使用MySQL 5.7的最新版本,优化器将(在某些情况下)实际上在派生表上创建索引。在旧版本中,MySQL 永远不会在派生表上创建索引。哎哟。

如果我们的视图查询执行SELECT * FROM bigtable(选择每一列,那么视图实际上是复制整个表。如果bigtable中的行很大,并且表包含大量的行,这可能是一项昂贵的操作。

如果我们将查询定义存储为数据库中的VIEW,那么在我们查询视图的每个时间内都会发生同一组操作。

我的意思是"推动"谓词"进入"视图查询。

将上述内容与此类查询的内容进行对比:

 SELECT v.mycol
   FROM (
          SELECT t.mycol
            FROM bigtable t
           WHERE t.mycol = 'foo'
         ) v
   WHERE v.mycol = 'foo'

请注意,我们在parens之间的内部查询中有一个WHERE子句。 MySQL运行该内部查询,它只检索满足bigtable子句中该条件的WHERE行。如果它具有相当的选择性,那么行数可能是一个非常小的集合。使用该内部查询,MySQL优化器可以利用具有前导列mycol的索引来有效地满足查询。如果mycol是PRIMARY KEY或bigtable的唯一键,那么查询最多将返回一行。这是一个小得多的派生表来实现。

在此示例中,外部查询的谓词是多余的。可以删除外部查询中的WHERE子句,我们仍然可以保证获得相同的结果。

在您的特定情况下,MySQL必须打开88个表,获取元数据锁,并获取表锁(如果它是MyISAM)等。

正如其他答案(正确地)指出的那样,查询中的UNION运算符会导致"唯一排序"用于识别和删除整个集合中的重复行的操作。这可能很昂贵。

TL; DR

BOTTOM LINE

创建视图定义更有可能产生比通过创建视图定义解决的任何问题更大且更有问题的性能问题。

就性能而言,使用包含每个表查询的谓词的查询会更好。假设你需要每一列(你真的需要返回每一列,或者你真的只需要它们的一部分)

此查询运行得更快:

  SELECT t01.* FROM mytable01 t01 WHERE t01.mycol = 'foo'
  UNION ALL
  SELECT t02.* FROM mytable02 t02 WHERE t02.mycol = 'foo'
  UNION ALL
  SELECT t03.* FROM mytable03 t03 WHERE t03.mycol = 'foo'
  ... 
  UNION ALL
  SELECT t88.* FROM mytable88 t88 WHERE t88.mycol = 'foo'

特别是如果在88个表中的mycol中都有适当的索引可用。

当我有一个结合多个查询结果的语句(但不包含88个表!)时,我通常会包含一个 discriminator列,它允许我识别返回行的查询

  SELECT 't01' AS q, t01.* FROM mytable01 t01 WHERE t01.mycol = 'foo'
  UNION ALL
  SELECT 't02' AS q, t02.* FROM mytable02 t02 WHERE t02.mycol = 'foo'
  UNION ALL
  SELECT 't03' AS q, t03.* FROM mytable03 t03 WHERE t03.mycol = 'foo'
  ... 
  UNION ALL
  SELECT 't88' AS q, t88.* FROM mytable88 t88 WHERE t88.mycol = 'foo'

从结果集中的第一列(q)开始,我可以确定哪一个查询返回了一行。

问题是什么?我想你要求一些提示。我希望我能给你一些值得考虑的事情。