【问题标题】:mysql index on orderby from 0 to 25 secondsorderby上的mysql索引从0到25秒
【发布时间】:2016-05-19 08:43:10
【问题描述】:

我有这个查询现在需要大约 0.57 秒:

SELECT analisi0_.ID_ANALISI AS col_0_0_,
       paziente5_.ID_PAZIENTE_LAB AS col_1_0_,
       sessione1_.ID_GEL AS col_2_0_,
       patologico8_.patologico AS col_3_0_,
       tipovalida9_.TIPO_VALIDAZIONE AS col_4_0_,
       specie7_.specie AS col_5_0_,
       analisi0_.campione AS col_6_0_,
       analisi0_.tracciato AS col_7_0_,
       paziente5_.cognome AS col_8_0_,
       paziente5_.nome AS col_9_0_,
       paziente5_.DATA_NASCITA AS col_10_0_,
       sesso6_.sesso AS col_11_0_,
       sessione1_.NUMERO_SESSIONE AS col_12_0_,
       sessione1_.DATA_SESSIONE AS col_13_0_,
       metodica4_.metodica AS col_14_0_
FROM Analisi analisi0_
  INNER JOIN Sessione sessione1_ ON analisi0_.ID_SESSIONE = sessione1_.ID_SESSIONE
  INNER JOIN tipo_sessione tiposessio2_ ON sessione1_.ID_TIPO_SESSIONE = tiposessio2_.ID_TIPO_SESSIONE
  INNER JOIN metodica_tipo_metodica metodicati3_ ON tiposessio2_.ID_METODICA_TIPO_METODICA = metodicati3_.ID_METODICA_TIPO_METODICA
  INNER JOIN Metodica metodica4_ ON metodicati3_.ID_METODICA = metodica4_.ID_METODICA
  INNER JOIN Paziente paziente5_ ON analisi0_.ID_PAZIENTE = paziente5_.ID_PAZIENTE
  INNER JOIN Sesso sesso6_ ON paziente5_.ID_SESSO = sesso6_.ID_SESSO
  INNER JOIN Specie specie7_ ON paziente5_.ID_SPECIE = specie7_.ID_SPECIE
  LEFT OUTER JOIN Patologico patologico8_ ON analisi0_.ID_PATOLOGICO = patologico8_.ID_PATOLOGICO
  INNER JOIN tipo_validazione tipovalida9_ ON analisi0_.ID_TIPO_VALIDAZIONE = tipovalida9_.ID_TIPO_VALIDAZIONE
WHERE 1 = 1
AND   (paziente5_.nome LIKE 'MARIA%')
AND   (paziente5_.DATA_NASCITA IS NOT NULL OR paziente5_.DATA_NASCITA > 0)
LIMIT 20;

问题是通过以下方式添加此默认顺序:

ORDER BY sessione1_.DATA_SESSIONE ASC 

查询在 25 秒内执行。

未排序的解释是:

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  specie7_        index   PRIMARY SPECIE  137     1   100 Using index
1   SIMPLE  paziente5_      ALL PRIMARY,IDX_DATA_NASCITA,IDX_NOME,FK_PAZIENTE_SPECIE,FK_PAZIENTE_SESSO              690950  5   Range checked for each record (index map: 0x3B)
1   SIMPLE  sesso6_     eq_ref  PRIMARY PRIMARY 1   elettroforesi.paziente5_.ID_SESSO   1   100 
1   SIMPLE  analisi0_       ref FK_ANALISI_PAZIENTE,FK_ANALISI_SESSIONE,FK_ANALISI_TIPO_VALIDAZIONE FK_ANALISI_PAZIENTE 4   elettroforesi.paziente5_.ID_PAZIENTE    1   100 
1   SIMPLE  tipovalida9_        eq_ref  PRIMARY PRIMARY 1   elettroforesi.analisi0_.ID_TIPO_VALIDAZIONE 1   100 
1   SIMPLE  patologico8_        eq_ref  PRIMARY PRIMARY 1   elettroforesi.analisi0_.ID_PATOLOGICO   1   100 
1   SIMPLE  sessione1_      eq_ref  PRIMARY,FK_SESSIONE_TIPO_SESSIONE   PRIMARY 4   elettroforesi.analisi0_.ID_SESSIONE 1   100 
1   SIMPLE  tiposessio2_        eq_ref  PRIMARY,FK_TIPO_SESSIONE_METODICA_TIPO_METODICA PRIMARY 2   elettroforesi.sessione1_.ID_TIPO_SESSIONE   1   100 
1   SIMPLE  metodicati3_        eq_ref  PRIMARY,ID_METODICA PRIMARY 2   elettroforesi.tiposessio2_.ID_METODICA_TIPO_METODICA    1   100 
1   SIMPLE  metodica4_      eq_ref  PRIMARY PRIMARY 2   elettroforesi.metodicati3_.ID_METODICA  1   100 

虽然排序版本的解释是

id  select_type table   partitions  type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  specie7_        index   PRIMARY SPECIE  137     1   100 Using index; Using temporary; Using filesort
1   SIMPLE  paziente5_      ALL PRIMARY,IDX_DATA_NASCITA,IDX_NOME,FK_PAZIENTE_SPECIE,FK_PAZIENTE_SESSO              690950  5   Range checked for each record (index map: 0x3B)
1   SIMPLE  sesso6_     eq_ref  PRIMARY PRIMARY 1   elettroforesi.paziente5_.ID_SESSO   1   100 
1   SIMPLE  analisi0_       ref FK_ANALISI_PAZIENTE,FK_ANALISI_SESSIONE,FK_ANALISI_TIPO_VALIDAZIONE FK_ANALISI_PAZIENTE 4   elettroforesi.paziente5_.ID_PAZIENTE    1   100 
1   SIMPLE  tipovalida9_        eq_ref  PRIMARY PRIMARY 1   elettroforesi.analisi0_.ID_TIPO_VALIDAZIONE 1   100 
1   SIMPLE  patologico8_        eq_ref  PRIMARY PRIMARY 1   elettroforesi.analisi0_.ID_PATOLOGICO   1   100 
1   SIMPLE  sessione1_      eq_ref  PRIMARY,FK_SESSIONE_TIPO_SESSIONE   PRIMARY 4   elettroforesi.analisi0_.ID_SESSIONE 1   100 
1   SIMPLE  tiposessio2_        eq_ref  PRIMARY,FK_TIPO_SESSIONE_METODICA_TIPO_METODICA PRIMARY 2   elettroforesi.sessione1_.ID_TIPO_SESSIONE   1   100 
1   SIMPLE  metodicati3_        eq_ref  PRIMARY,ID_METODICA PRIMARY 2   elettroforesi.tiposessio2_.ID_METODICA_TIPO_METODICA    1   100 
1   SIMPLE  metodica4_      eq_ref  PRIMARY PRIMARY 2   elettroforesi.metodicati3_.ID_METODICA  1   100 

SESSIONE 表上的索引:

Table   Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Sub_part    Packed  Null    Index_type  Comment Index_comment
sessione    0   PRIMARY 1   ID_SESSIONE A   44468               BTREE       
sessione    1   IDX_DATA_SESSIONE   1   DATA_SESSIONE   A   878             BTREE       
sessione    1   IDX_NUMERO_SESSIONE 1   NUMERO_SESSIONE A   168             BTREE       
sessione    1   FK_SESSIONE_TIPO_SESSIONE   1   ID_TIPO_SESSIONE    A   6               BTREE       
sessione    1   FK_SESSIONE_UTENTE_INSERIMENTO  1   ID_UTENTE_INSERIMENTO   A   1               BTREE       

有什么建议可以加快这个默认顺序吗?

编辑:

按照脚本创建表格:

CREATE TABLE PAZIENTE
(
   ID_PAZIENTE          INT           UNSIGNED NOT NULL AUTO_INCREMENT,
   ID_PAZIENTE_LAB      VARCHAR(20),
   COGNOME              VARCHAR(40),
   NOME                 VARCHAR(40),
   DATA_NASCITA         DATE,
   ID_SESSO             TINYINT UNSIGNED NOT NULL,
   RECAPITO             VARCHAR(50),
   CODICE_FISCALE       VARCHAR(30),
   ID_SPECIE            TINYINT UNSIGNED NOT NULL,
   PRIMARY KEY (ID_PAZIENTE), 
   INDEX IDX_DATA_NASCITA (DATA_NASCITA),
   INDEX IDX_COGNOME (COGNOME),
   INDEX IDX_NOME (NOME),
   CONSTRAINT FK_PAZIENTE_SPECIE FOREIGN KEY (ID_SPECIE) REFERENCES SPECIE(ID_SPECIE),  
   CONSTRAINT FK_PAZIENTE_SESSO FOREIGN KEY (ID_SESSO) REFERENCES SESSO(ID_SESSO)   
)
ENGINE=InnoDB;




CREATE TABLE ANALISI
(
   ID_ANALISI               INT             UNSIGNED NOT NULL AUTO_INCREMENT,
   ID_PAZIENTE              INT             UNSIGNED NOT NULL,
   ID_SESSIONE              INT             UNSIGNED NOT NULL,
   TRACCIATO                TINYINT         UNSIGNED NOT NULL,
   CAMPIONE                 VARCHAR(30),
   ID_PATOLOGICO            TINYINT         UNSIGNED,
   REPARTO                  VARCHAR(40),
   TOTALE_PROTEINE          FLOAT,   
   RAPP_AG                  FLOAT,
   ID_ANALISI_LINK          INT             UNSIGNED,
   ID_ANALISI_IFE           INT             UNSIGNED,   
   ID_ANALISI_DATI          INT             UNSIGNED,  
   ID_ANALISI_NOTA          INT             UNSIGNED,
   DATA_MODIFICA            DATETIME,      
   ID_UTENTE_MODIFICA       SMALLINT        UNSIGNED,
   DATA_VALIDAZIONE         DATETIME,
   ID_TIPO_VALIDAZIONE      TINYINT         UNSIGNED NOT NULL,
   ID_UTENTE_VALIDAZIONE    SMALLINT        UNSIGNED,   
   DATA_CANCELLAZIONE       DATETIME,
   ID_UTENTE_CANCELLAZIONE  SMALLINT        UNSIGNED,      
   PRIMARY KEY (ID_ANALISI), 
   INDEX IDX_CAMPIONE (CAMPIONE),
   INDEX IDX_PAZIENTE (ID_PAZIENTE),
   INDEX IDX_SESSIONE (ID_SESSIONE),
   INDEX IDX_REPARTO  (DATA_MODIFICA),   
   CONSTRAINT FK_ANALISI_PAZIENTE             FOREIGN KEY (ID_PAZIENTE)             REFERENCES PAZIENTE(ID_PAZIENTE),
   CONSTRAINT FK_ANALISI_SESSIONE             FOREIGN KEY (ID_SESSIONE)             REFERENCES SESSIONE(ID_SESSIONE),
   CONSTRAINT FK_ANALISI_PATOLOGICO           FOREIGN KEY (ID_PATOLOGICO)           REFERENCES PATOLOGICO(ID_PATOLOGICO),
   CONSTRAINT FK_ANALISI_TIPO_VALIDAZIONE     FOREIGN KEY (ID_TIPO_VALIDAZIONE)     REFERENCES TIPO_VALIDAZIONE(ID_TIPO_VALIDAZIONE),
   CONSTRAINT FK_ANALISI_UTENTE_MODIFICA      FOREIGN KEY (ID_UTENTE_MODIFICA)      REFERENCES UTENTE(ID_UTENTE), 
   CONSTRAINT FK_ANALISI_UTENTE_VALIDAZIONE   FOREIGN KEY (ID_UTENTE_VALIDAZIONE)   REFERENCES UTENTE(ID_UTENTE), 
   CONSTRAINT FK_ANALISI_UTENTE_CANCELLAZIONE FOREIGN KEY (ID_UTENTE_CANCELLAZIONE) REFERENCES UTENTE(ID_UTENTE),    
   CONSTRAINT FK_ANALISI_ANALISI_LINK         FOREIGN KEY (ID_ANALISI_LINK)         REFERENCES ANALISI(ID_ANALISI),
   CONSTRAINT FK_ANALISI_ANALISI_IFE          FOREIGN KEY (ID_ANALISI_IFE)          REFERENCES ANALISI_IFE(ID_ANALISI_IFE),
   CONSTRAINT FK_ANALISI_ANALISI_NOTA         FOREIGN KEY (ID_ANALISI_NOTA)         REFERENCES ANALISI_NOTA(ID_ANALISI_NOTA),
   CONSTRAINT FK_ANALISI_ANALISI_DATI         FOREIGN KEY (ID_ANALISI_DATI)         REFERENCES ANALISI_DATI(ID_ANALISI_DATI)
)
ENGINE=InnoDB;

【问题讨论】:

  • 这是否与显示您的innodb_buffer_pool_size 太小的那个重复?
  • 我仍然有 2GByte 分配给 4GByte 的 i5 上的 mysql 的问题,我还尝试使用表 analisi 上的日期来简化查询,该列也被索引,Analisi 上有 160 万行和 Paziente 上的 0.8M 行,以下查询需要 5 秒没有 order by 和 75 秒有 order by,我想我会尝试使用整数而不是 datetime 来存储我的时间戳 --> SELECT analisi0_.ID_ANALISI FROM Analisi analisi0_ INNER JOIN Paziente paziente1_ ON analisi0_.ID_PAZIENTE = paziente1_.ID_PAZIENTE WHERE paziente1_.ID_SESSO = 1 ORDER BY analisi0_.DATA_MODIFICA DESC ;
  • 我也尝试将 3GByte 分配给 mysql 但没有增强
  • datetime vs timestamp vs int 应该执行相同的操作。
  • 实际上我在任何日期都使用 DATETIME 但我认为结果真的很差,160 万行订单的 75 秒似乎太多了,我希望解决方案不会是插入分析表上的 ID_SESSO :-)

标签: mysql indexing sql-order-by


【解决方案1】:

我建议你在表Sessione 上添加一个索引来帮助排序:

create index idx_sessione_quick on sessione(id_tipo_sessione, data_sessione);

索引中的第一个字段用于快速查找记录,第二个字段用于排序。您甚至可以使用覆盖索引来加快速度:

create index idx_sessione_quick on sessione(id_tipo_sessione, data_sessione, 
                                            id_gel, numero_sessione);

【讨论】:

    【解决方案2】:

    (paziente5_.DATA_NASCITA IS NOT NULL OR paziente5_.DATA_NASCITA > 0) 没有意义。也许你的意思是AND?在这种情况下,这就足够了:(paziente5_.DATA_NASCITA > 0)。在这种情况下,这可能是可用的并有助于提高性能:

    INDEX(nome, DATA_NASCITA)
    

    DATA_NASCITA 是什么数据类型无关紧要。

    如果这还不够帮助,请为每个表提供SHOW CREATE TABLE,以便我们查看是否有足够的索引允许paziente5_ 开始。这是性能所需要的。

    更多

    (paziente5_.DATA_NASCITA IS NOT NULL OR paziente5_.DATA_NASCITA > 0) 等同于(paziente5_.DATA_NASCITA IS NOT NULL),但我怀疑优化器没有意识到这一点。无论如何,您的 EXPLAIN 暗示它不在乎。

    可以为测试提供EXPLAINAND (paziente5_.DATA_NASCITA IS NOT NULL OR paziente5_.DATA_NASCITA > 0)。请明确说明哪个 EXPLAIN 与哪个测试一起使用(有/没有 ORDER BY 和有/没有“愚蠢”条件)。

    【讨论】:

    • 不是一个,因为这是一个愚蠢的条件,我必须采取一切,在那一行我也有空值。奇怪的是,我正在寻找一个名称,这个愚蠢的条件对我有帮助,而如果我正在寻找 ID_SESSO,这个愚蠢的条件将选择时间从 40 秒增加到 75 秒。我将表格创建脚本附加到上面的文本中
    • @Etantonio:所以 DATA_NASCITA 是 DATE 并且在您的查询中不能为 NULL。但是paziente5_.DATA_NASCITA IS NOT NULL 很慢,添加OR paziente5_.DATA_NASCITA > 0 会更快???或者你还有什么想说的?
    • 我只是想说寻找“AND (paziente5_.nome LIKE 'MARIA%')”如果我还添加这个愚蠢的条件“AND (paziente5_.DATA_NASCITA IS NOT NULL OR paziente5_.DATA_NASCITA > 0)”在同一张表 PAZIENTE 上查找“paziente1_.ID_SESSO = 1”时,愚蠢的条件会产生较慢的查询。所以最后我可以说,在我看来,mysql 并不是那么容易预测的。
    【解决方案3】:

    对于您的查询,我没有看到任何真正的复合索引或覆盖索引。我提供以下内容来帮助优化您的查询,甚至提供覆盖索引以防止访问原始数据页面(如查找表)。

    table                  index
    Paziente               ( nome, DATA_NASCITA, ID_PAZIENTE, ID_SESSO, ID_SPECIE )
    Sessione               ( ID_SESSIONE, DATA_SESSIONE, ID_TIPO_SESSIONE )
    tipo_sessione          ( ID_TIPO_SESSIONE, ID_METODICA_TIPO_METODICA )
    metodica_tipo_metodica ( ID_METODICA_TIPO_METODICA, ID_METODICA
    Metodica               ( ID_METODICA, metodica )
    Analisi                ( ID_SESSIONE, ID_PAZIENTE, ID_PATOLOGICO, ID_TIPO_VALIDAZIONE )
    Sesso                  ( ID_SESSO, sesso )
    Specie                 ( ID_SPECIE, specie )
    Patologico             ( ID_PATOLOGICO, patologico )
    tipo_validazione       ( ID_TIPO_VALIDAZIONE, TIPO_VALIDAZIONE )
    

    接下来,我出于两部分原因修改了查询。将您的 paziente5 表放在首位,因为这是您的 WHERE 子句的基础。以 nome 和 DATA_NASCITA 开头的索引限定了您的 WHERE 条件,而其他字段用于优化后续的 JOIN 条件。

    此外,一旦加入您的 sessione 表,就具有连接的关键元素,但 THEN 基于 ORDER BY 列。这些应该会有所帮助。

    SELECT 
          analisi0_.ID_ANALISI          AS col_0_0_,
          paziente5_.ID_PAZIENTE_LAB    AS col_1_0_,
          sessione1_.ID_GEL             AS col_2_0_,
          patologico8_.patologico       AS col_3_0_,
          tipovalida9_.TIPO_VALIDAZIONE AS col_4_0_,
          specie7_.specie               AS col_5_0_,
          analisi0_.campione            AS col_6_0_,
          analisi0_.tracciato           AS col_7_0_,
          paziente5_.cognome            AS col_8_0_,
          paziente5_.nome               AS col_9_0_,
          paziente5_.DATA_NASCITA       AS col_10_0_,
          sesso6_.sesso                 AS col_11_0_,
          sessione1_.NUMERO_SESSIONE    AS col_12_0_,
          sessione1_.DATA_SESSIONE      AS col_13_0_,
          metodica4_.metodica           AS col_14_0_
       FROM 
          Paziente paziente5_ 
             INNER JOIN Analisi analisi0_
                ON paziente5_.ID_PAZIENTE analisi0_.ID_PAZIENTE
                INNER JOIN Sessione sessione1_ 
                   ON analisi0_.ID_SESSIONE = sessione1_.ID_SESSIONE
                   INNER JOIN tipo_sessione tiposessio2_ 
                      ON sessione1_.ID_TIPO_SESSIONE = tiposessio2_.ID_TIPO_SESSIONE
                      INNER JOIN metodica_tipo_metodica metodicati3_ 
                         ON tiposessio2_.ID_METODICA_TIPO_METODICA = metodicati3_.ID_METODICA_TIPO_METODICA
                         INNER JOIN Metodica metodica4_ 
                            ON metodicati3_.ID_METODICA = metodica4_.ID_METODICA
                LEFT OUTER JOIN Patologico patologico8_ 
                   ON analisi0_.ID_PATOLOGICO = patologico8_.ID_PATOLOGICO
                INNER JOIN tipo_validazione tipovalida9_ 
                   ON analisi0_.ID_TIPO_VALIDAZIONE = tipovalida9_.ID_TIPO_VALIDAZIONE
             INNER JOIN Sesso sesso6_ 
                ON paziente5_.ID_SESSO = sesso6_.ID_SESSO
             INNER JOIN Specie specie7_ 
                ON paziente5_.ID_SPECIE = specie7_.ID_SPECIE
       WHERE 
              1 = 1
          AND ( paziente5_.nome LIKE 'MARIA%' )
          AND (   paziente5_.DATA_NASCITA IS NOT NULL 
               OR paziente5_.DATA_NASCITA > 0)
       ORDER BY 
          sessione1_.DATA_SESSIONE ASC 
       LIMIT 
          20;
    

    最后一次优化尝试是添加关键字

    SELECT STRAIGHT_JOIN ...查询的其余部分。

    STRAIGHT_JOIN 告诉引擎按照显示的顺序运行。我已经看到它在许多情况下都有效,但在其他情况下却不行,这就是为什么我默认省略了它,您可以尝试在之后添加。

    order by 延迟的原因是引擎需要首先返回 ALL QUALIFIED 记录,然后根据您的 order by 进行排序,但您需要根据您的 paziente 限定条件更快地到达 sessione 表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多