在这种情况下,MyISAM 在 mysql 中比 InnoDB 快得多
In this case MyISAM is dramatically faster than InnoDB in mysql
我一直在写 InnoDB table 中计算客户之间距离的算法的结果。例如,如果我的客户是 A、B、C 和 D,则数据库中的 table 看起来像这样,在其他列中:
From | To | Distance
A B 344
A C 274
A D 182
B C 338
等等...排的很多我觉得我会打到5000万
其他列是 product_type 和值。这些告诉我客户 B(列中的 customer_to)购买了多少 product_type。这意味着我根据客户 B 购买的 product_type 数量对每双进行多次。
我需要查询以将每个客户与他的邻居购买的产品和价值分组。查询如下所示:
select customer_from, product_type, avg(value) as opportunity
from customer_distances
where distance < 500
group by customer_from, product_type
order by opportunity desc;
innodb table 无法回答我的问题。尽管我将 net_read_timeout 更改为 28800,但 mysql 连接在查询期间丢失了。
我认为它与用于事务处理而不是用于密集查询的 innodb 构建有关。所以我用 MyIsam 作为引擎创建了一个新的 table 并插入-select 来自 innodb table.
的所有记录
正如预期的那样,select 非常快(70 段),所有其他 selects 都像 count(distinct customer_from),几乎是瞬时的。
出于好奇,我尝试继续在 myisam table 中插入距离的过程。当程序开始 运行 比它在 innodb table -for INSERTS!
上工作时至少快 100 倍时,我感到很惊讶
对于每个客户,程序插入大约 3000 行(每个 product_type 每个邻居一个。大约 300 个邻居和每个客户 10 product_types)。使用 innodb table 插入单个客户需要 40 到 60 秒(大约 3000 行)。使用 myisam table,插入 3 个客户需要 1 秒(大约 9000 行)。
一些额外信息:
- mysql 数据库在我的 PC(本地主机)中。
- 用 java 编写的程序 运行 从我的电脑上下载。
- 我正在使用准备好的语句,我只更改每个语句之间的数据
行和下一个。这与这个问题有关
Why is myisam storage engine is faster than Innodb storage engine
所以总结起来问题是:
为什么 MyISAM 使用插入语句那么快?
你怎么看?
编辑 1:我正在为 tables、innodb 和 myisam 添加创建语句。
编辑 2:我删除了一些无用的信息,并在这里和那里进行了一些格式化。
/* INNODB TABLE */
CREATE TABLE `customer_distances` (
`customer_from` varchar(50) NOT NULL,
`customer_from_type` varchar(50) DEFAULT NULL,
`customer_from_segment` varchar(50) DEFAULT NULL,
`customer_from_district` int(11) DEFAULT NULL,
`customer_from_zone` int(11) DEFAULT NULL,
`customer_from_longitud` decimal(15,6) DEFAULT NULL,
`customer_from_latitud` decimal(15,6) DEFAULT NULL,
`customer_to` varchar(50) NOT NULL,
`customer_to_type` varchar(50) DEFAULT NULL,
`customer_to_segment` varchar(50) DEFAULT NULL,
`customer_to_district` int(11) DEFAULT NULL,
`customer_to_zone` int(11) DEFAULT NULL,
`customer_to_longitud` decimal(15,6) DEFAULT NULL,
`customer_to_latitud` decimal(15,6) DEFAULT NULL,
`distance` decimal(10,2) DEFAULT NULL,
`product_business_line` varchar(50) DEFAULT NULL,
`product_type` varchar(50) NOT NULL,
`customer_from_liters` decimal(10,2) DEFAULT NULL,
`customer_from_dollars` decimal(10,2) DEFAULT NULL,
`customer_from_units` decimal(10,2) DEFAULT NULL,
`customer_to_liters` decimal(10,2) DEFAULT NULL,
`customer_to_dollars` decimal(10,2) DEFAULT NULL,
`customer_to_units` decimal(10,2) DEFAULT NULL,
`liters_opportunity` decimal(10,2) DEFAULT NULL,
`dollars_opportunity` decimal(10,2) DEFAULT NULL,
`units_oportunity` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`cliente_desde`,`cliente_hasta`,`grupo`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/* MYISAM TABLE */
CREATE TABLE `customer_distances` (
`customer_from` varchar(50) NOT NULL,
`customer_from_type` varchar(50) DEFAULT NULL,
`customer_from_segment` varchar(50) DEFAULT NULL,
`customer_from_district` int(11) DEFAULT NULL,
`customer_from_zone` int(11) DEFAULT NULL,
`customer_from_longitud` decimal(15,6) DEFAULT NULL,
`customer_from_latitud` decimal(15,6) DEFAULT NULL,
`customer_to` varchar(50) NOT NULL,
`customer_to_type` varchar(50) DEFAULT NULL,
`customer_to_segment` varchar(50) DEFAULT NULL,
`customer_to_district` int(11) DEFAULT NULL,
`customer_to_zone` int(11) DEFAULT NULL,
`customer_to_longitud` decimal(15,6) DEFAULT NULL,
`customer_to_latitud` decimal(15,6) DEFAULT NULL,
`distance` decimal(10,2) DEFAULT NULL,
`product_business_line` varchar(50) DEFAULT NULL,
`product_type` varchar(50) NOT NULL,
`customer_from_liters` decimal(10,2) DEFAULT NULL,
`customer_from_dollars` decimal(10,2) DEFAULT NULL,
`customer_from_units` decimal(10,2) DEFAULT NULL,
`customer_to_liters` decimal(10,2) DEFAULT NULL,
`customer_to_dollars` decimal(10,2) DEFAULT NULL,
`customer_to_units` decimal(10,2) DEFAULT NULL,
`liters_opportunity` decimal(10,2) DEFAULT NULL,
`dollars_opportunity` decimal(10,2) DEFAULT NULL,
`units_oportunity` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`cliente_desde`,`cliente_hasta`,`grupo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
插入
- InnoDB,默认情况下,"commits"每个
INSERT
立即。这可以通过一次聚集 100-1000 行来解决。
- 批处理插入将加速 MyISAM 和 InnoDB - 可能提高 10 倍。
- 了解
autocommit
和 BEGIN..COMMIT
。
Select
- InnoDB 消耗的磁盘 space 比 MyISAM 多——通常是 2x-3x;这会影响 table 扫描,您可能
- 对于该查询,(customer_from、product_type、距离)上的复合索引可能对两个引擎都有帮助。
调整
- 当运行宁只是 MyISAM时,设置
key_buffer_size
为RAM的20%和innodb_buffer_pool_size=0
。
- 当运行宁只是 InnoDB时,设置
key_buffer_size
到只有10M和innodb_buffer_pool_size
到RAM的70%。
规范化和保存space
- 更小 --> 更可缓存 --> 更少 I/O --> 更快(在任一引擎中)
DECIMAL(10,2)
在大多数情况下并不是最好的。考虑 FLOAT
表示非货币(例如 distance
)。考虑更少的数字;最多可处理 99,999,999.99,占用 5 个字节。
- 复制列通常不是一个好主意,例如
customer_from
和 customer_to
的 10 列。有一个 Customers
table,两者都在里面。
- 你的纬度和经度都是7个字节,并且有不必要的分辨率。建议
latidud DECIMAL(6,4)
和 longitud (7,4)
,总计 为 7 个字节。 (这些分辨率为 16m/52ft。)
结果
在这些建议之后,5000 万行 table 会小很多,并且 运行 在两个引擎中都快得多。然后运行再次比较
我一直在写 InnoDB table 中计算客户之间距离的算法的结果。例如,如果我的客户是 A、B、C 和 D,则数据库中的 table 看起来像这样,在其他列中:
From | To | Distance
A B 344
A C 274
A D 182
B C 338
等等...排的很多我觉得我会打到5000万
其他列是 product_type 和值。这些告诉我客户 B(列中的 customer_to)购买了多少 product_type。这意味着我根据客户 B 购买的 product_type 数量对每双进行多次。
我需要查询以将每个客户与他的邻居购买的产品和价值分组。查询如下所示:
select customer_from, product_type, avg(value) as opportunity
from customer_distances
where distance < 500
group by customer_from, product_type
order by opportunity desc;
innodb table 无法回答我的问题。尽管我将 net_read_timeout 更改为 28800,但 mysql 连接在查询期间丢失了。
我认为它与用于事务处理而不是用于密集查询的 innodb 构建有关。所以我用 MyIsam 作为引擎创建了一个新的 table 并插入-select 来自 innodb table.
的所有记录正如预期的那样,select 非常快(70 段),所有其他 selects 都像 count(distinct customer_from),几乎是瞬时的。
出于好奇,我尝试继续在 myisam table 中插入距离的过程。当程序开始 运行 比它在 innodb table -for INSERTS!
上工作时至少快 100 倍时,我感到很惊讶对于每个客户,程序插入大约 3000 行(每个 product_type 每个邻居一个。大约 300 个邻居和每个客户 10 product_types)。使用 innodb table 插入单个客户需要 40 到 60 秒(大约 3000 行)。使用 myisam table,插入 3 个客户需要 1 秒(大约 9000 行)。
一些额外信息:
- mysql 数据库在我的 PC(本地主机)中。
- 用 java 编写的程序 运行 从我的电脑上下载。
- 我正在使用准备好的语句,我只更改每个语句之间的数据 行和下一个。这与这个问题有关 Why is myisam storage engine is faster than Innodb storage engine
所以总结起来问题是: 为什么 MyISAM 使用插入语句那么快? 你怎么看?
编辑 1:我正在为 tables、innodb 和 myisam 添加创建语句。 编辑 2:我删除了一些无用的信息,并在这里和那里进行了一些格式化。
/* INNODB TABLE */
CREATE TABLE `customer_distances` (
`customer_from` varchar(50) NOT NULL,
`customer_from_type` varchar(50) DEFAULT NULL,
`customer_from_segment` varchar(50) DEFAULT NULL,
`customer_from_district` int(11) DEFAULT NULL,
`customer_from_zone` int(11) DEFAULT NULL,
`customer_from_longitud` decimal(15,6) DEFAULT NULL,
`customer_from_latitud` decimal(15,6) DEFAULT NULL,
`customer_to` varchar(50) NOT NULL,
`customer_to_type` varchar(50) DEFAULT NULL,
`customer_to_segment` varchar(50) DEFAULT NULL,
`customer_to_district` int(11) DEFAULT NULL,
`customer_to_zone` int(11) DEFAULT NULL,
`customer_to_longitud` decimal(15,6) DEFAULT NULL,
`customer_to_latitud` decimal(15,6) DEFAULT NULL,
`distance` decimal(10,2) DEFAULT NULL,
`product_business_line` varchar(50) DEFAULT NULL,
`product_type` varchar(50) NOT NULL,
`customer_from_liters` decimal(10,2) DEFAULT NULL,
`customer_from_dollars` decimal(10,2) DEFAULT NULL,
`customer_from_units` decimal(10,2) DEFAULT NULL,
`customer_to_liters` decimal(10,2) DEFAULT NULL,
`customer_to_dollars` decimal(10,2) DEFAULT NULL,
`customer_to_units` decimal(10,2) DEFAULT NULL,
`liters_opportunity` decimal(10,2) DEFAULT NULL,
`dollars_opportunity` decimal(10,2) DEFAULT NULL,
`units_oportunity` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`cliente_desde`,`cliente_hasta`,`grupo`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/* MYISAM TABLE */
CREATE TABLE `customer_distances` (
`customer_from` varchar(50) NOT NULL,
`customer_from_type` varchar(50) DEFAULT NULL,
`customer_from_segment` varchar(50) DEFAULT NULL,
`customer_from_district` int(11) DEFAULT NULL,
`customer_from_zone` int(11) DEFAULT NULL,
`customer_from_longitud` decimal(15,6) DEFAULT NULL,
`customer_from_latitud` decimal(15,6) DEFAULT NULL,
`customer_to` varchar(50) NOT NULL,
`customer_to_type` varchar(50) DEFAULT NULL,
`customer_to_segment` varchar(50) DEFAULT NULL,
`customer_to_district` int(11) DEFAULT NULL,
`customer_to_zone` int(11) DEFAULT NULL,
`customer_to_longitud` decimal(15,6) DEFAULT NULL,
`customer_to_latitud` decimal(15,6) DEFAULT NULL,
`distance` decimal(10,2) DEFAULT NULL,
`product_business_line` varchar(50) DEFAULT NULL,
`product_type` varchar(50) NOT NULL,
`customer_from_liters` decimal(10,2) DEFAULT NULL,
`customer_from_dollars` decimal(10,2) DEFAULT NULL,
`customer_from_units` decimal(10,2) DEFAULT NULL,
`customer_to_liters` decimal(10,2) DEFAULT NULL,
`customer_to_dollars` decimal(10,2) DEFAULT NULL,
`customer_to_units` decimal(10,2) DEFAULT NULL,
`liters_opportunity` decimal(10,2) DEFAULT NULL,
`dollars_opportunity` decimal(10,2) DEFAULT NULL,
`units_oportunity` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`cliente_desde`,`cliente_hasta`,`grupo`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
插入
- InnoDB,默认情况下,"commits"每个
INSERT
立即。这可以通过一次聚集 100-1000 行来解决。 - 批处理插入将加速 MyISAM 和 InnoDB - 可能提高 10 倍。
- 了解
autocommit
和BEGIN..COMMIT
。
Select
- InnoDB 消耗的磁盘 space 比 MyISAM 多——通常是 2x-3x;这会影响 table 扫描,您可能
- 对于该查询,(customer_from、product_type、距离)上的复合索引可能对两个引擎都有帮助。
调整
- 当运行宁只是 MyISAM时,设置
key_buffer_size
为RAM的20%和innodb_buffer_pool_size=0
。 - 当运行宁只是 InnoDB时,设置
key_buffer_size
到只有10M和innodb_buffer_pool_size
到RAM的70%。
规范化和保存space
- 更小 --> 更可缓存 --> 更少 I/O --> 更快(在任一引擎中)
DECIMAL(10,2)
在大多数情况下并不是最好的。考虑FLOAT
表示非货币(例如distance
)。考虑更少的数字;最多可处理 99,999,999.99,占用 5 个字节。- 复制列通常不是一个好主意,例如
customer_from
和customer_to
的 10 列。有一个Customers
table,两者都在里面。 - 你的纬度和经度都是7个字节,并且有不必要的分辨率。建议
latidud DECIMAL(6,4)
和longitud (7,4)
,总计 为 7 个字节。 (这些分辨率为 16m/52ft。)
结果
在这些建议之后,5000 万行 table 会小很多,并且 运行 在两个引擎中都快得多。然后运行再次比较