简体   繁体   English

如何优化我的MySQL Select查询?

[英]How to optimize my MySQL Select query?

I have got a MySQL database table, that has the following form: 我有一个MySQL数据库表,其格式如下:

CREATE TABLE IF NOT EXISTS data_packet (
  id BIGINT NOT NULL AUTO_INCREMENT,
  time_received BIGINT NOT NULL,
  content TEXT NOT NULL,
  recording_id INT NOT NULL,
  PRIMARY KEY (id),
  INDEX fk_data_packet_recording_idx (recording_id ASC),
  CONSTRAINT fk_data_packet_recording
    FOREIGN KEY (recording_id)
    REFERENCES recording(id)
)

Inside this table I have got data like this: 在此表中,我有如下数据:

<Dat url="vehicleSpeed">
   <Abs name="speed" val="97"/>
   <Enm name="unit" val="kmh"/>
   <Enm name="state" val="valid"/>
</Dat>

The table can contain up to 1.000.000 rows. 该表最多可以包含1.000.000行。 Now I have got queries like the one following, to select special data packets with a certain url. 现在,我有了以下查询,以选择具有特定URL的特殊数据包。 Every data packet has such a url attribute. 每个数据包都有这样的url属性。

SELECT * 
FROM data_packet 
WHERE recording_id = 1 
    AND content LIKE '%vehicleSpeed%' 
    AND time_received BETWEEN 1435843095338 AND 1435843095996 
ORDER BY time_received ASC;

I think this constellation can be optimized. 我认为这个星座可以优化。 In MySQL workbench this query takes 47ms where the table only contains about 35.000 rows. 在MySQL工作台中,此查询耗时47ms,其中表仅包含约35.000行。 A Java application shall execute the queries later and I noticed, that it takes more time to execute it via the JDBC. Java应用程序稍后将执行查询,我注意到,通过JDBC执行查询需要更多时间。

What optimization can you recommend? 您可以建议什么优化? Index? 指数? Another column? 另一列? Another table? 另一张桌子?

Thank you very much. 非常感谢你。

Any query optimization thumb rule says you might want to have an INDEX in same sequence you are putting columns in where clause. 任何查询优化的经验法则规则都表明,您可能希望按将列放在where子句中的顺序来获得INDEX。 I would suggest to create an INDEX with two columns (content,time_received) and then check performance with EXPLAIN command in mySQL. 我建议创建一个包含两列(内容,time_received)的INDEX,然后在mySQL中使用EXPLAIN命令检查性能。

ALTER TABLE data_packet 
  ADD  INDEX `IDX_COMPOSITE` (content,time_received);

EXPLAIN SELECT * 
FROM data_packet 
WHERE recording_id = 1 
    AND content LIKE '%vehicleSpeed%' 
    AND time_received BETWEEN 1435843095338 AND 1435843095996 
ORDER BY time_received ASC;

Also try without sorting 也尝试不排序

EXPLAIN SELECT * 
FROM data_packet 
WHERE recording_id = 1 
    AND content LIKE '%vehicleSpeed%' 
    AND time_received BETWEEN 1435843095338 AND 1435843095996 

Thanks Anant 谢谢阿南特

You have an index on recording_id, but you do not have one that also covers time_received. 您在recording_id上有一个索引,但是没有一个涵盖了time_received的索引。 Depending on the number of values of recording_id and the time range they cover this could make a major difference. 取决于recording_id的值的数量和它们覆盖的时间范围,这可能会有很大的不同。

Add an index that covers both recording_id AND time_received. 添加一个同时覆盖recording_id和time_received的索引。

The 2nd major issue is that your query uses LIKE, comparing with a value which has a leading wildcard. 第二个主要问题是您的查询使用的是LIKE,而不是带有前导通配符的值。 No index in going to help with this. 没有索引可以帮助解决这个问题。 You could try using a FULLTEXT index, and then using MATCH()...AGAINST to try and find the matching values. 您可以尝试使用FULLTEXT索引,然后使用MATCH()... AGAINST尝试查找匹配的值。

However I would suggest that it might be better to restructure your database. 但是,我建议重组数据库可能会更好。 But this very much depends on the fragments of data that are stored in the content field. 但这很大程度上取决于存储在内容字段中的数据片段。 If all of them contain the url field then I would possibly just store that in the content field (so you can check it directly without the need for if), and then store each of the other fields in another table which you can join to the data_packet table. 如果它们都包含url字段,那么我可能会将其存储在content字段中(因此您可以直接检查它而不需要if),然后将其他每个字段存储在另一个表中,您可以将其加入到data_packet表。

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

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