Mysql索引视图无法正常工作

时间:2016-07-15 08:45:18

标签: mysql performance indexing view union

我创建了一个名为' myview'如下。

create view myview
as select 'a' source,col1,col2
     from table_a
   union
   select source,col1,col2
     from table_b
;

table_a的索引位于col1table_b的索引位于sourcecol1。当我在myview上查询如下时,不使用索引。

select *
  from myview
 where source = a
   and col1 = 'xxx'
 ;

如何使索引适用于此查询?

创建代码

CREATE TABLE `table_a` (
    `col1` VARCHAR(50) NULL DEFAULT NULL,
    `col2` VARCHAR(50) NULL DEFAULT NULL,
    INDEX `table_a_idx01` (`col1`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM
;

CREATE TABLE `table_b` (
    `source` VARCHAR(50) NULL DEFAULT NULL,
    `col1` VARCHAR(50) NULL DEFAULT NULL,
    `col2` VARCHAR(50) NULL DEFAULT NULL,
    INDEX `table_b_idx01` (`source`, `col1`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM
;

create view myview
as select 'a' source,col1,col2
     from table_a
   union
   select source,col1,col2
     from table_b  

INSERT INTO table_a (col1, col2) 
VALUES 
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2');

INSERT INTO table_b (source,col1, col2) 
VALUES 
('b','test2', 'testcol2'),
('b','test2', 'testcol2'),
('b','test2', 'testcol2'),
('b','test2', 'testcol2'),
('b','test2', 'testcol2'),
('b','test2', 'testcol2');

解释

explain
select *
  from table_a
 where col1 = 'test'
id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,SIMPLE,table_a,ref,table_a_idx01,table_a_idx01,153,const,5,Using index condition
explain
select *
  from table_b
 where source = 'b'
   and col1 = 'test'
id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,SIMPLE,table_b,ref,table_b_idx01,table_b_idx01,306,const,const,1,Using index condition

解释我的观点

explain
select *
  from myview
 where source = 'b'
   and col1 = 'test'
id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,PRIMARY,<derived2>,ref,<auto_key0>,<auto_key0>,306,const,const,1,Using where
2,DERIVED,table_a,ALL,\N,\N,\N,\N,6,\N
3,UNION,table_b,ALL,\N,\N,\N,\N,6,\N
\N,UNION RESULT,<union2,3>,ALL,\N,\N,\N,\N,\N,Using temporary

如您所见,在视图选择上没有调整索引。

1 个答案:

答案 0 :(得分:2)

您无法在视图上创建索引:http://dev.mysql.com/doc/refman/5.7/en/view-restrictions.html,因此您必须希望使用索引。 https://stackoverflow.com/a/7922711/3595565

解决方法

在文档的另一部分的注释中提到了一种解决方法:https://dev.mysql.com/doc/refman/5.5/en/create-view.html您可以在其中创建常规表并设置专用索引并将视图中的数据加载到表中。

  

如上所述创建物化视图仿真看起来不错,   唯一的问题是我们继承了缺少索引的MySQL   观点曝光。

     

我的解决方案是根据我的方法创建一个正确索引的表   需要,具有与视图完全相同的结构,然后运行   像这样的东西:

LOCK TABLES materializedView WRITE; 
TRUNCATE materializedView; 
INSERT INTO materializedView SELECT * FROM regularView;
UNLOCK TABLES;
  

这样,来自materializedView的所有索引都会保留在每个索引上   “刷新”。

     

我打算在我正在做的应用程序中使用它,在那里   我们将有比插入/更新更多的SELECT。如果我保持一个   我的SELECT的常规视图,我会要求服务器做大量的   每当有人需要知道有多少项目时,计算   股票的产品“A”,相反,我将有所有SELECTs朝向   “materializedView”具有正确的SKU,存储和期间索引。

     

每次有人运行INSERT或时,都会出现“刷新”视图   更新,将以20比1的比例。 (每次更新时选择20个   或插入)

     

我希望事情能像我一样顺利进行。问候; - )

为什么您的查询不使用索引?

UNION mysql中使用SELECT时,会创建一个临时表来保存数据。因此,视图是更复杂查询的“快捷方式”,在调用select时它将再次执行union,使用临时表...使用temptable alghorithm处理数据。

再次查看手册:http://dev.mysql.com/doc/refman/5.7/en/view-restrictions.html

  

索引可用于使用合并算法处理的视图。   但是,使用临时算法处理的视图是   无法利用其基础表上的索引(尽管如此)   在生成临时表时可以使用索引。

结论:查询中的UNION会阻碍视图使用索引。

来源

question in mysql forum for the same problem回答:

  

我猜联盟会导致视图使用temptable算法,它会创建一个临时表,然后将where条件应用于临时表。

bugreport "DO NOT CREATE TEMPORARY TABLES FOR UNION ALL"

  

目前,union查询总是使用临时表来存储   返回给用户之前的结果。 [...]

修正了MySQL 5.7 http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-3.html

  

服务器不再为UNION语句使用临时表   符合某些资格。相反,它保留在临时表中   仅创建执行结果列所必需的数据结构   类型转换。[...]

检查分析器的一些testdata

CREATE TABLE test1 (
    id int auto_increment PRIMARY KEY,
  col1 varchar(50),
  col2 varchar(50)
);

CREATE TABLE test2 (
    id int auto_increment PRIMARY KEY,
  col1 varchar(50),
  col2 varchar(50)
);

INSERT INTO test1 (col1, col2) 
VALUES 
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2'),
('test', 'testcol2');


INSERT INTO test2 (col1, col2) 
VALUES 
('test2', 'testcol2'),
('test2', 'testcol2'),
('test2', 'testcol2'),
('test2', 'testcol2'),
('test2', 'testcol2'),
('test2', 'testcol2');

CREATE VIEW testview AS
SELECT * FROM test1
UNION
SELECT * FROM test2;

检查分析器:

SET PROFILING = 1;
SELECT * FROM testview WHERE id = 1;
+----+-------+----------+
| id | col1  | col2     |
+----+-------+----------+
|  1 | test  | testcol2 |
|  1 | test2 | testcol2 |
+----+-------+----------+
SHOW PROFILE;
+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000017 |
| Waiting for query cache lock   | 0.000004 |
| checking query cache for query | 0.000029 |
| checking permissions           | 0.000006 |
| Opening tables                 | 0.000121 |
| System lock                    | 0.000012 |
| checking permissions           | 0.000014 |
| checking permissions           | 0.000032 |
| optimizing                     | 0.000004 |
| statistics                     | 0.000007 |
| preparing                      | 0.000006 |
| executing                      | 0.000003 |
| Sending data                   | 0.000046 |
| optimizing                     | 0.000003 |
| statistics                     | 0.000004 |
| preparing                      | 0.000003 |
| executing                      | 0.000002 |
| Sending data                   | 0.000023 |
| optimizing                     | 0.000003 |
| statistics                     | 0.000003 |
| preparing                      | 0.000003 |
| executing                      | 0.000002 |
| Sending data                   | 0.000008 |
| removing tmp table             | 0.000005 |
| Sending data                   | 0.000005 |
| Waiting for query cache lock   | 0.000002 |
| Sending data                   | 0.000024 |
| init                           | 0.000011 |
| optimizing                     | 0.000006 |
| statistics                     | 0.000004 |
| preparing                      | 0.000006 |
| executing                      | 0.000002 |
| Sending data                   | 0.000021 |
| end                            | 0.000003 |
| query end                      | 0.000004 |
| closing tables                 | 0.000002 |
| removing tmp table             | 0.000004 |
| closing tables                 | 0.000006 |
| freeing items                  | 0.000005 |
| Waiting for query cache lock   | 0.000003 |
| freeing items                  | 0.000013 |
| Waiting for query cache lock   | 0.000002 |
| freeing items                  | 0.000002 |
| storing result in query cache  | 0.000003 |
| logging slow query             | 0.000002 |
| cleaning up                    | 0.000003 |
+--------------------------------+----------+

我不能从个人资料中获取太多信息,但它确实提到了临时表,足以(对我来说)验证我的结论。