我有一张这样的表
field_1 field_2 field_3
------- ------- -------
3 1 5
2 1 1
1 2 1
1 4 1
我有这3个问题:
select count(*) as field_1_is_2 from my_table where field_1 = 2;
select count(*) as field_2_is_4 from my_table where field_2 = 4;
select count(*) as field_3_is_5 from my_table where field_3 = 5;
select count(*) as fields_combined from my_table where field_3 != 2 and field_2 != 2;
如何在一个查询中组合上述查询?
一个选项可能是:
select
sum(if(field_1 = 2, 1, 0)) as field_1_is_2,
sum(if(field_2 = 4, 1, 0)) as field_2_is_5,
sum(if(field_3 = 5, 1, 0)) as field_3_is_5,
sum(if(field_3 != 2 and field_2 != 2, 1, 0)) as fields_combined
from my_table;
但表格非常大,我想使用正确的索引,这种方法没有使用它们。
这是表格描述:
CREATE TABLE `my_table` (
`field_1` int(11) DEFAULT NULL,
`field_2` int(11) DEFAULT NULL,
`field_3` int(11) DEFAULT NULL,
KEY `index_field_1` (`field_1`),
KEY `index_field_2` (`field_2`),
KEY `index_field_3` (`field_3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
所以,问题是,如何在一个查询中组合(如果可能)上述查询并正确使用索引?
作为@ ralf.w is mentioning,表格中缺少一个索引:
ALTER TABLE `my_table` ADD KEY `index_field_2_and_3` (`field_2`,`field_3`);
答案 0 :(得分:1)
我的版本看起来像这样:
select
(select count(*) as field_1_is_2 from my_table where field_1 = 2) as field_1_is_2,
(select count(*) as field_2_is_4 from my_table where field_2 = 4) as field_2_is_4,
(select count(*) as field_3_is_5 from my_table where field_3 = 5) as field_3_is_5,
(select count(*) as fields_combined from my_table
where field_3 != 2 and field_2 != 2) as fields_combined;
让优化器对其余部分进行优化和组合。
由EXPLAIN预先执行,我们看到了这一点:
1,PRIMARY ,,,,,,,,,没有使用的表
5,SUBQUERY,my_table,ALL,index_field_2,index_field_3 ,,, 4,使用位置
4,SUBQUERY,my_table,ref,index_field_3,index_field_3,5,const,1,使用索引
3,SUBQUERY,my_table,ref,index_field_2,index_field_2,5,const,1,使用索引
2,SUBQUERY,my_table,ref,index_field_1,index_field_1,5,const,1,使用索引
这里真的缺少的是field_3和field_2的索引:
ALTER TABLE `my_table` ADD KEY `index_field_2_and_3` (`field_2`,`field_3`);
将双字段索引“使用位置”更改为“使用位置; 使用索引”
答案 1 :(得分:1)
我无法想象你能比单独查询每个索引更有效地做到这一点。在突然出现在我脑海中的场景中,我会使用以下几点:
select "field_1_is_2" as criteria, count(*) from my_table where field_1 = 2
union all
select "field_2_is_4" as criteria, count(*) from my_table where field_2 = 4
union all
select "field_3_is_5" as criteria, count(*) from my_table where field_3 = 5
union all
select "fields_combined" as criteria, count(*) from my_table where field_3 != 2 and field_2 != 2;
在单独的行中返回每个值:
criteria count(*)
field_1_is_2 1
field_2_is_4 1
field_3_is_5 1
fields_combined 3
答案 2 :(得分:1)
使用where field_3 != 2 and field_2 != 2
,您的某个索引将被使用的可能性非常小。对于大量的记录,field_3 != 2
应该是真的。 field_2 != 2
也是如此。 DBMS不扫描索引,例如,80%的记录使用一个标准,另一个70%使用另一个标准,然后与集合相交。它宁愿简单地从头到尾读取一次表,即执行全表扫描。
因为它将读取整个表的计数,所以不应该在单独的查询中获得其他计数,而是在运行中获取计数。所以带条件和的选项是要走的路。在标准SQL中:
select
count(case when field_1 = 2 then 1 end) as field_1_is_2,
count(case when field_2 = 4 then 1 end) as field_2_is_4,
count(case when field_3 = 5 then 1 end) as field_3_is_5,
count(case when field_3 != 2 and field_2 != 2 then 1 end) as fields_combined
from my_table;
在MySQL中:
select
sum(field_1 = 2) as field_1_is_2,
sum(field_2 = 4) as field_2_is_4,
sum(field_3 = 5) as field_3_is_5,
sum(field_3 != 2 and field_2 != 2) as fields_combined
from my_table;
答案 3 :(得分:-1)
您可以使用MYSQL Union All command。我创建了一个simillar表并插入了测试数据。
+---------+---------+---------+
| field_1 | field_2 | field_3 |
+---------+---------+---------+
| 3 | 1 | 5 |
| 2 | 1 | 1 |
| 1 | 2 | 1 |
| 1 | 4 | 1 |
| 1 | 4 | 2 |
| 1 | 4 | 3 |
| 1 | 4 | 4 |
+---------+---------+---------+
现在我正在使用的sql查询是
从my_table中选择count()作为field_1_is_2,其中field_1 = 2 union 所有选择计数()为my_table的field_2_is_4,其中field_2 = 4 union all 从my_table中选择count(*)作为field_3_is_5,其中field_3 = 5;
这给出了像
这样的结果+--------------+
| field_1_is_2 |
+--------------+
| 1 |
| 4 |
| 1 |
+--------------+
您应该能够将结果作为第一行,第二行和第三行。这也将利用索引的力量。