简体   繁体   English

帮助:在MySQL中优化此查询

[英]Help: Optimize this query in MySQL

This is my tables, the AUTO_INCREMENT shows the size of each: 这是我的表,AUTO_INCREMENT显示每个表的大小:

tbl_clientes : tbl_clientes

CREATE TABLE `tbl_clientes` (
  `int_clientes_id_pk` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `str_clientes_documento` varchar(255) DEFAULT NULL,
  `str_clientes_nome_original` char(255) DEFAULT NULL,
  PRIMARY KEY (`int_clientes_id_pk`),
  UNIQUE KEY `str_clientes_documento` (`str_clientes_documento`),
  KEY `str_clientes_nome_original` (`str_clientes_nome_original`),
  KEY `nome_original_cliente_id` (`str_clientes_nome_original`,`int_clientes_id_pk`),
  KEY `cliente_id_nome_original` (`int_clientes_id_pk`,`str_clientes_nome_original`)
) ENGINE=MyISAM AUTO_INCREMENT=2815520 DEFAULT CHARSET=utf8

tbl_clienteEnderecos : tbl_clienteEnderecos

CREATE TABLE `tbl_clienteEnderecos` (
  `int_clienteEnderecos_id_pk` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `int_clienteEnderecos_cliente_id_fk` bigint(20) unsigned NOT NULL,
  `str_clienteEnderecos_endereco` varchar(255) NOT NULL,
  `str_clienteEnderecos_cep` varchar(255) DEFAULT NULL,
  `str_clienteEnderecos_numero` varchar(255) DEFAULT NULL,
  `str_clienteEnderecos_complemento` varchar(255) DEFAULT NULL,
  `str_clienteEnderecos_bairro` varchar(255) DEFAULT NULL,
  `str_clienteEnderecos_cidade` varchar(255) DEFAULT NULL,
  `str_clienteEnderecos_uf` varchar(2) DEFAULT NULL,
  `int_clienteEnderecos_correspondencia` tinyint(1) NOT NULL DEFAULT '0',
  `int_clienteEnderecos_tipo` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`int_clienteEnderecos_id_pk`),
  KEY `int_clienteEnderecos_cliente_id_fk` (`int_clienteEnderecos_cliente_id_fk`),
  KEY `str_clienteEnderecos_cidade` (`str_clienteEnderecos_cidade`),
  KEY `str_clienteEnderecos_uf` (`str_clienteEnderecos_uf`),
  KEY `uf_cidade` (`str_clienteEnderecos_uf`,`str_clienteEnderecos_cidade`)
) ENGINE=MyISAM AUTO_INCREMENT=1542038 DEFAULT CHARSET=utf8

Then I run this query to search, it will be fast, is using indexes: 然后我运行此查询来搜索,使用索引的速度很快:

EXPLAIN
SELECT * FROM tbl_clientes LEFT JOIN tbl_clienteEnderecos ON int_clienteEnderecos_cliente_id_fk = int_clientes_id_pk
GROUP BY str_clientes_nome_original, int_clientes_id_pk
ORDER BY str_clientes_nome_original, int_clientes_id_pk
LIMIT 0,20

The result of EXPAIN is: EXPAIN的结果是:

| id | select_type | table                | type  | possible_keys                      | key                                | key_len | ref                                               | rows | Extra |
+----+-------------+----------------------+-------+------------------------------------+------------------------------------+---------+---------------------------------------------------+------+-------+
|  1 | SIMPLE      | tbl_clientes         | index | NULL                               | nome_original_cliente_id           | 774     | NULL                                              |   20 |       |
|  1 | SIMPLE      | tbl_clienteEnderecos | ref   | int_clienteEnderecos_cliente_id_fk | int_clienteEnderecos_cliente_id_fk | 8       | mydb.tbl_clientes.int_clientes_id_pk |    1 |       |
+----+-------------+----------------------+-------+------------------------------------+------------------------------------+---------+---------------------------------------------------+------+-------+

All right, but I need to filter by tbl_clienteEnderecos.str_clienteEnderecos_uf . 好的,但是我需要按tbl_clienteEnderecos.str_clienteEnderecos_uf进行过滤。 It breaks all indexes, use temporary table and filesort (no index). 它会破坏所有索引,使用临时表和文件排序(无索引)。 Here's the query: 这是查询:

EXPLAIN
SELECT * FROM tbl_clientes LEFT JOIN tbl_clienteEnderecos ON int_clienteEnderecos_cliente_id_fk = int_clientes_id_pk
WHERE str_clienteEnderecos_uf = "SP"
GROUP BY str_clientes_nome_original, int_clientes_id_pk
ORDER BY str_clientes_nome_original, int_clientes_id_pk
LIMIT 0,20

Look, this is the output of EXPLAIN: 看,这是EXPLAIN的输出:

| id | select_type | table                | type   | possible_keys                                                        | key       | key_len | ref                                                                       | rows   | Extra                                        |
+----+-------------+----------------------+--------+----------------------------------------------------------------------+-----------+---------+---------------------------------------------------------------------------+--------+----------------------------------------------+
|  1 | SIMPLE      | tbl_clienteEnderecos | ref    | int_clienteEnderecos_cliente_id_fk,str_clienteEnderecos_uf,uf_cidade | uf_cidade | 9       | const                                                                     | 670654 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | tbl_clientes         | eq_ref | PRIMARY,cliente_id_nome_original                                     | PRIMARY   | 8       | mydb.tbl_clienteEnderecos.int_clienteEnderecos_cliente_id_fk |      1 |                                              |
+----+-------------+----------------------+--------+----------------------------------------------------------------------+-----------+---------+---------------------------------------------------------------------------+--------+----------------------------------------------+

With this Using where; 通过使用 Using temporary; 使用临时; Using filesort it can't be fast. 使用filesort不可能很快。 I've tried a lot of things, how optimize this query? 我已经尝试了很多事情,如何优化此查询?

Is it time to switch to NoSQL/MongoDB? 现在该切换到NoSQL / MongoDB了吗?

MySQL will typically not use an index if it will not help narrow the results down enough. 如果MySQL不能帮助缩小结果范围,通常将不使用索引。 It appears that "SP" occurs in roughly 670654 rows. 看来“ SP”出现在大约670654行中。 Since this is about 1/3 of your total rows, it is more efficient to read it in disk order. 由于这大约占总行数的1/3,因此按磁盘顺序读取它会更有效。

You can try an index to tbl_clienteEnderecos: 您可以尝试索引tbl_clienteEnderecos:

KEY `test` (`str_clienteEnderecos_uf `, `int_clienteEnderecos_cliente_id_fk`)

This might be enough to get it to use the index. 这可能足以使其使用索引。

What is the difference between these two columns? 这两列之间有什么区别? They look like they should be the same. 他们看起来应该一样。

int_clienteEnderecos_id_pk
int_clienteEnderecos_cliente_id_fk

Edit 编辑

I understand what the names of the columns imply. 我了解这些列的名称意味着什么。 I was just curious if the two values should be identical. 我只是好奇两个值是否应该相同。 If they are, it would simplify a few things and have them be joined on the primary key of the tables. 如果是这样,它将简化一些事情,并将它们连接到表的主键上。 I am not sure about the specific meaning of the tables involved, so I don't know if there is a 1-1 or 1-0 relationship between them or a one to many relationship. 我不确定所涉及的表的具体含义,所以我不知道它们之间是否存在1-1或1-0关系或一对多关系。

I suggest trying to retrieve just the primary key of the tables that you want. 我建议尝试仅检索所需表的主键。 For instance, instead of select * try: 例如,不要选择*尝试:

EXPLAIN 
SELECT int_clienteEnerecos_id_pk, int_clientes_id_pk 
FROM tbl_clientes 
LEFT JOIN tbl_clienteEnderecos ON int_clienteEnderecos_cliente_id_fk = int_clientes_id_pk
WHERE str_clienteEnderecos_uf = "SP"
GROUP BY str_clientes_nome_original, int_clientes_id_pk
ORDER BY str_clientes_nome_original, int_clientes_id_pk
LIMIT 0,20

If this works out the way I hope it will, you sell see "from index" in the Extra column. 如果可以按照我希望的方式解决问题,您可以在Extra栏中看到“ from index”。 If you need additional fields returned, you can either make another round trip to fetch them, or add them to your index. 如果需要返回其他字段,则可以进行另一次往返以获取它们,或将它们添加到索引中。 Or use a nested query to fetch them based on the results of the query above. 或者使用嵌套查询根据上述查询的结果来获取它们。

Also, why are you grouping by and ordering by the same thing? 另外,为什么要对同一事物进行分组和排序? Are you expecting multiple matches of the foreign key? 您是否希望外键有多个匹配项?

I'd suggest giving the following a try; 我建议尝试以下方法; the subquery might use the key better than the join in this context. 在这种情况下,子查询可能比联接更好地使用键。 Take care, though; 不过要小心; I couldn't swear on a stack of K & R's that the query is the same as your original. 我不能保证K&R的查询与您的原始查询相同。

SELECT *,
       (SELECT *
            FROM tbl_clienteEnderecos
            WHERE int_clienteEnderecos_cliente_id_fk = int_clientes_id_pk AND
                  str_clienteEnderecos_uf = "SP") AS T2
    FROM tbl_clientes
    GROUP BY str_clientes_nome_original, int_clientes_id_pk
    HAVING T2.int_clienteEnderecos_id_pk IS NOT NULL
    ORDER BY str_clientes_nome_original, int_clientes_id_pk
    LIMIT 0, 20

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

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