MYSQL 需要在单个表上进行更快的分组

标签 mysql

我试图从包含 1,000,000 个属性的表中为每个州选择一个属性。我正在努力

select * from properties
where latitude is not null and longitude is not null
group by property_state;

但是查询需要3秒。我有一个关于纬度和经度的索引,以及一个关于州的索引。我尝试在所有 3 列上添加第三个索引,但这没有帮助。 有什么想法吗?

这是创建表的代码,如果有帮助的话(我删除了没有帮助的新索引)

CREATE TABLE `t_national_comps` (
`deal_Id` INT(11) NULL DEFAULT NULL,
`nc_id` INT(11) NOT NULL AUTO_INCREMENT,
`property_id` INT(15) NULL DEFAULT NULL,
`reonomy_property_id` VARCHAR(50) NULL DEFAULT NULL,
`reonomy_url` VARCHAR(80) NULL DEFAULT NULL,
`confidence` FLOAT NULL DEFAULT NULL,
`latitude` DECIMAL(11,8) NULL DEFAULT NULL,
`longitude` DECIMAL(11,8) NULL DEFAULT NULL,
`prop_key` VARCHAR(255) NULL DEFAULT NULL,
`fmt_address` VARCHAR(255) NULL DEFAULT NULL,
`property_street_number` VARCHAR(20) NULL DEFAULT NULL,
`property_street_name` VARCHAR(40) NULL DEFAULT NULL,
`property_street_mode` VARCHAR(20) NULL DEFAULT NULL,
`property_city` VARCHAR(40) NULL DEFAULT NULL,
`property_state` VARCHAR(10) NULL DEFAULT NULL,
`property_zip` VARCHAR(10) NULL DEFAULT NULL,
`property_zip4` VARCHAR(10) NULL DEFAULT NULL,
`municipality` VARCHAR(40) NULL DEFAULT NULL,
`property_class_id` VARCHAR(15) NULL DEFAULT NULL,
`std_land_use_code` VARCHAR(15) NULL DEFAULT NULL,
`sale_doc_num` VARCHAR(30) NULL DEFAULT NULL,
`mortgage_doc_num` VARCHAR(30) NULL DEFAULT NULL,
`mortgage_date` DATE NULL DEFAULT NULL,
`lender` VARCHAR(100) NULL DEFAULT NULL,
`bank_id` INT(11) NULL DEFAULT NULL,
`loan_amount` BIGINT(15) NULL DEFAULT NULL,
`maturity_date` DATE NULL DEFAULT NULL,
`rate` VARCHAR(20) NULL DEFAULT NULL,
`sale_date` DATE NULL DEFAULT NULL,
`curr_sale_contract_date` DATE NULL DEFAULT NULL,
`curr_sale_document_type` VARCHAR(20) NULL DEFAULT NULL,
`sale_price` BIGINT(22) NULL DEFAULT NULL,
`curr_sale_buyer1_full_name` VARCHAR(60) NULL DEFAULT NULL,
`curr_sale_buyer2_full_name` VARCHAR(60) NULL DEFAULT NULL,
`reported_owner` VARCHAR(60) NULL DEFAULT NULL,
`mailing_address` VARCHAR(500) NULL DEFAULT NULL,
`curr_sale_seller1_full_name` VARCHAR(60) NULL DEFAULT NULL,
`curr_sale_seller2_full_name` VARCHAR(60) NULL DEFAULT NULL,
`sq_footage` VARCHAR(10) NULL DEFAULT NULL,
`resi_units` VARCHAR(10) NULL DEFAULT NULL,
`commercial_units` VARCHAR(10) NULL DEFAULT NULL,
`num_floors` VARCHAR(10) NULL DEFAULT NULL,
`num_buildings` VARCHAR(10) NULL DEFAULT NULL,
`price_per_sq_ft` INT(11) NULL DEFAULT NULL,
`price_per_unit` INT(11) NULL DEFAULT NULL,
`property_type_id` INT(11) NULL DEFAULT NULL,
`property_type` VARCHAR(60) NULL DEFAULT NULL,
`long_lat_point` POINT NULL DEFAULT NULL,
PRIMARY KEY (`nc_id`),
INDEX `t_national_comps_latitude_longitude_index` (`latitude`, `longitude`),
INDEX `t_national_comps_property_city_index` (`property_city`),
INDEX `t_national_comps_property_state_index` (`property_state`),
INDEX `t_national_comps_sale_date_index` (`sale_date`),
INDEX `t_national_comps_point_index` (`long_lat_point`(25)),
INDEX `t_national_comps_reonomy_id_index` (`reonomy_property_id`),
INDEX `mailing_address_index` (`mailing_address`),
INDEX `mortgage_date_index` (`mortgage_date`),
INDEX `t_national_comps_lender_index` (`lender`),
INDEX `bank_id_index` (`bank_id`),
INDEX `street_num_and_zip` (`property_street_number`, `property_zip`)
);

编辑
我没有在查询中聚合任何内容的原因是因为我没有什么可以聚合的。我知道这不是 group by 的主要用途,但它很常用,只是为了获取每条记录之一。

我能够通过强制在所有 3 列上使用索引来加快查询速度,例如

select latitude, longitude, property_street_number, property_street_name, 
property_city, property_state, property_zip from properties
USE INDEX (lat_long_state_index)
where latitude is not null and longitude is not null
group by property_state;

但我仍在寻找更多优化。
感谢大家的帮助。

最佳答案

分组依据

我不相信 Group By 应该以这种方式使用,尽管 MySQL 内部可能足够聪明(我不确定),当它看到没有聚合的 group by 时使用 Distinct,但我不认为这是使用 Group By 的正确方法。

索引

MySQL 每个查询每个表使用一个索引,并且只会选择一个索引,因此在拥有三列之前,使用 property_state 选择索引是正确的,因为 MySQL 通常不会在不相等的条件下使用索引。

您可以对强制索引前后的查询进行 EXPLAIN 比较。 MySQL优化器认为单列索引更好。

过多的索引也会增加插入的开销。拥有三列索引后,您实际上可以删除 property_state 索引,因为它被三列索引(最左边)覆盖。您将来的查询肯定会使用您创建的新索引。

关于MYSQL 需要在单个表上进行更快的分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51404905/

相关文章:

java - 对于 MySQL 和 Java,没有文件(即内存中)的 "Load DATA"是否可行?

php - 如何将本地MySql数据库移动到远程服务器上

PHP - 不要在 MySQL 查询中使用 "\"

mysql从多个表中选择数据并求和和平均值

javascript - 使用 php 和 javascript 创建实时聊天

mysql - 在 Laravel 迁移中,使用长度大于 255 的字符串

mysql - 使用连接查询中的字段值作为列

mysql - 如何在 MySQL 中选择两个单独的非重叠表

php连接到不同服务器上的两个数据库并使用insert select

php - 显示两个日期之间的记录