简体   繁体   English

MySQL查询与几个子查询的优化

[英]mysql query with several subquery optimization

Considering that analisi_campo_free is a table with about 1 million rows, is there a lighter way to write this query for mysql? 考虑到analisi_campo_free是一个约有100万行的表,是否有更简便的方法来编写针对mysql的查询?

    select distinct ID_ANALISI from analisi_campo_free 
    where 1=1
    and ID_ANALISI IN ( select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 1 and valore = '06/11/2015')
    and ID_ANALISI IN ( select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 3 AND valore='vvvvvv');

Thanks 谢谢


The query 查询

select distinct ID_ANALISI from analisi_campo_free 
where 1=1
and ID_ANALISI IN ( select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 1 and valore like 'irene%') 
and ID_ANALISI IN ( select ID_ANALISI from analisi_campo_free acf inner join campo_free cf on acf.id_campo_free = cf.id_campo_free where posizione = 3 AND valore like 'antonio%');

require about 2.3 seconds with this explain 大约需要2.3秒

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  cf      index   PRIMARY ID_LABORATORIO  4       6   16.67   Using where; Using index; Using temporary; Start temporary
1   SIMPLE  cf      index   PRIMARY ID_LABORATORIO  4       6   16.67   Using where; Using index; Using join buffer (Block Nested Loop)
1   SIMPLE  acf     ALL ID_ANALISI,FK_ANALISI_CAMPO_FREE_CAMPO_FREE             1054163 11.11   Using where; Using join buffer (Block Nested Loop)
1   SIMPLE  acf     eq_ref  ID_ANALISI,FK_ANALISI_CAMPO_FREE_CAMPO_FREE ID_ANALISI  5   elettroforesi.acf.ID_ANALISI,elettroforesi.cf.ID_CAMPO_FREE 1   11.11   Using where
1   SIMPLE  analisi_campo_free      ref ID_ANALISI  ID_ANALISI  4   elettroforesi.acf.ID_ANALISI    1   100 Using index; End temporary

The query 查询

SELECT acf.ID_ANALISI, COUNT(DISTINCT cf.posizione, acf.valore) AS matches 
FROM analisi_campo_free AS acf 
INNER JOIN campo_free AS cf ON acf.id_campo_free = cf.id_campo_free 
WHERE (posizione = 1 AND valore like 'irene%')
   OR (posizione = 3 AND valore like 'antonio%')
GROUP BY acf.ID_ANALISI
HAVING matches = 2; 

requires about 1.3 seconds with this explain 大约需要1.3秒

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  cf      index   PRIMARY ID_LABORATORIO  4       6   30.56   Using where; Using index; Using temporary; Using filesort
1   SIMPLE  acf     ALL ID_ANALISI,FK_ANALISI_CAMPO_FREE_CAMPO_FREE             1054163 20.99   Range checked for each record (index map: 0x6)

The index are: 索引是:

Table   Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Sub_part    Packed  Null    Index_type  Comment Index_comment
analisi_campo_free  0   PRIMARY 1   ID_ANALISI_CAMPO_FREE   A   1054159             BTREE       
analisi_campo_free  0   ID_ANALISI  1   ID_ANALISI  A   1049622             BTREE       
analisi_campo_free  0   ID_ANALISI  2   ID_CAMPO_FREE   A   1049622             BTREE       
analisi_campo_free  1   FK_ANALISI_CAMPO_FREE_CAMPO_FREE    1   ID_CAMPO_FREE   A   1               BTREE       


Table   Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Sub_part    Packed  Null    Index_type  Comment Index_comment
campo_free  0   PRIMARY 1   ID_CAMPO_FREE   A   6               BTREE       
campo_free  0   DESCRIZIONE 1   DESCRIZIONE A   6               BTREE       
campo_free  0   ID_LABORATORIO  1   ID_LABORATORIO  A   1               BTREE       
campo_free  0   ID_LABORATORIO  2   POSIZIONE   A   6               BTREE       
campo_free  0   ID_LABORATORIO  3   UTILIZZATO  A   6           YES BTREE       

I have not considered the query with couples because now I know I need a like. 我没有考虑过夫妇的问题,因为现在我知道我需要一个喜欢的人。 At the end maybe I will use my first query because is simplier to translate in querydsl. 最后,也许我将使用我的第一个查询,因为这样可以更轻松地在querydsl中进行翻译。 Thanks for your help 谢谢你的帮助

You could use: 您可以使用:

SELECT ID_ANALISI 
FROM analisi_campo_free acf 
JOIN campo_free cf 
  ON acf.id_campo_free = cf.id_campo_free 
WHERE (posizione,valore) IN ((1,'06/11/2015'),(3,'vvvvvv'))
GROUP BY ID_ANALSI
HAVING SUM(posizione = 1 AND valore = '06/11/2015') > 0
   AND SUM(posizione = 3 AND valore='vvvvvv') > 0;

Subqueries in WHERE clauses are usually poor performers in MySQL, especially CORRELATED subqueries. WHERE子句中的子查询通常在MySQL中表现不佳,尤其是CORRELATED子查询。 This finds the associated campo_free records and counts the distinct posizone, valore pairs that match the criteria. 这将找到相关的campo_free记录,并计算与条件匹配的不同的posizone,valore对。 The HAVING insures only the ID_ANALISI that have both are in the results. HAVING确保仅ID_ANALISI都包含在结果中。

SELECT acf.ID_ANALISI, COUNT(DISTINCT cf.posizone, cf.valore) AS matches 
FROM analisi_campo_free AS acf 
INNER JOIN campo_free AS cf ON acf.id_campo_free = cf.id_campo_free 
WHERE (posizione = 1 AND valore = '06/11/2015')
   OR (posizione = 3 AND valore='vvvvvv');
GROUP BY acf.ID_ANALISI
HAVING matches = 2
;

Without the DISTINCT in COUNT; COUNT中没有DISTINCT; if posizone, valore pairs are not unique for each id_campo_free values, ID_ANALISI with two (1,'6/11/2015') or (3,'vvvvvv') matches could also be included in the final results. 如果对于每个id_campo_free值,posiozone,valore对不是唯一的,则具有两个(1,'6/11/2015')或(3,'vvvvvv')匹配的ID_ANALISI也可以包含在最终结果中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM