提高 MYSQL 涉及联合的查询的性能
Increase Performance of MYSQL QUERY involving unions
有一个 Golang 实用程序,它能够每天减少 table 历史数据中的数据点。
记录范围为每天 20 到 400 条记录。
总共至少有1亿条记录。
该实用程序能够 trim 在给定日期之前每天减少到 n 条记录。 (n 的范围为每天 1 到 300 条记录)
我使用的方法如下:
第 1 步:
CREATE TABLE main_table_tmp LIKE main_table;
第 2 步:
ALTER TABLE main_table_tmp ADD COLUMN timekey INT;
第 3 步:
INSERT INTO main_table_tmp
SELECT * FROM (
SELECT *,FLOOR(UNIX_TIMESTAMP(column_name)/((1440/2)*60)) AS timekey
FROM main_table
WHERE column_name <= '2018-01-01'
GROUP BY timekey
) m
UNION ALL
(SELECT * ,0 As timekey FROM main_table where column_name > 'date') ;
第 4 步:
ALTER TABLE main_table_tmp DROP COLUMN timekey;
DROP TABLE maintable;
RENAME TABLE maintable_tmp TO maintable;
我正在使用 golang 实现上述目标。
func somefuncname(){
----
----
----
q := "CREATE TABLE " + *tablename + "_tmp LIKE " + *tablename + ";"
rows, err := db.Query(q)
if err != nil {
fmt.Println(err)
}
//--ALTER ADD timekey
//--INSERT INTO SELECT *....
//--ALTER DROP timekey ,DROP table and rename
}
这个查询的当前响应时间很慢
部分结果:
总记录: 200 万条
执行时间: 180 秒
这是在 16Gb RAM 上 CPU
部署在低等级系统上很慢
我为解决此问题采取的步骤:
查看了所有 table 的索引。尝试删除索引并 运行ning 实用程序。删除索引使实用程序快了 5 秒,这也不算多。
分阶段执行实用程序:如果总记录超过 100 万条,则 运行 实用程序一次 100 万条
但经过所有这些努力,主要问题似乎出在查询本身。
只是不够快。我只是需要一种提高查询效率的方法
感谢任何帮助,
谢谢你们!!
为什么我们添加 timekey
然后删除它?将它添加到一个空的 table 中很快,但是在它被填充后从 table 中删除它,就像 table 的一个额外副本。如果我们不需要,那是不必要的工作。
我们可以对一个表达式做一个GROUP BY
;该表达式不必出现在 SELECT 列表中。例如:
SELECT t.*
FROM main_table t
WHERE t.column_name <= '2018-01-01'
GROUP
BY FLOOR(UNIX_TIMESTAMP(t.column_name)/((1440/2)*60))
(请注意,如果 sql_mode 中包含 ONLY_FULL_GROUP_BY
,此查询将导致错误;这会禁用允许查询 运行 的 MySQL-specific 扩展。)
没有一些 table 定义(包括存储引擎、列数据类型、索引)并且没有 EXPLAIN 输出,我们只是猜测。
但是一些建议:
在正在填充的空 table 上删除二级索引,并在 table 加载后添加它们。
我会避免 UNION。鉴于其中一个 SELECT 语句在 column_name
上有一个谓词,而另一个在完全不同的列 date
上有一个谓词,我们确实想要分开 SELECT 语句。
CREATE TABLE main_table_tmp LIKE main_table
;
-- for performance, remove secondary indexes, leave just the cluster index
ALTER TABLE main_table_tmp
DROP INDEX noncluster_index_1
, DROP INDEX noncluster_index_2
, ...
;
-- for performance, have a suitable index available on main_table
-- with `column_name` as the leading column
INSERT INTO main_table_tmp
SELECT h.*
FROM main_table h
WHERE h.column_name <= '2018-01-01'
GROUP
BY FLOOR(UNIX_TIMESTAMP(h.column_name)/((1440/2)*60))
;
-- for performance, have a suitable index available on main_table
-- with `date` as the leading column
INSERT INTO main_table_tmp
SELECT c.*
FROM main_table
WHERE c.date > '????-??-??'
;
-- add secondary indexes
ALTER TABLE maint_table_tmp
ADD UNIQUE INDEX noncluster_index_1 (fee,fi,fo)
, ADD INDEX noncluster_index_2 (fum)
, ...
;
有一个 Golang 实用程序,它能够每天减少 table 历史数据中的数据点。
记录范围为每天 20 到 400 条记录。 总共至少有1亿条记录。
该实用程序能够 trim 在给定日期之前每天减少到 n 条记录。 (n 的范围为每天 1 到 300 条记录)
我使用的方法如下:
第 1 步:
CREATE TABLE main_table_tmp LIKE main_table;
第 2 步:
ALTER TABLE main_table_tmp ADD COLUMN timekey INT;
第 3 步:
INSERT INTO main_table_tmp
SELECT * FROM (
SELECT *,FLOOR(UNIX_TIMESTAMP(column_name)/((1440/2)*60)) AS timekey
FROM main_table
WHERE column_name <= '2018-01-01'
GROUP BY timekey
) m
UNION ALL
(SELECT * ,0 As timekey FROM main_table where column_name > 'date') ;
第 4 步:
ALTER TABLE main_table_tmp DROP COLUMN timekey;
DROP TABLE maintable;
RENAME TABLE maintable_tmp TO maintable;
我正在使用 golang 实现上述目标。
func somefuncname(){
----
----
----
q := "CREATE TABLE " + *tablename + "_tmp LIKE " + *tablename + ";"
rows, err := db.Query(q)
if err != nil {
fmt.Println(err)
}
//--ALTER ADD timekey
//--INSERT INTO SELECT *....
//--ALTER DROP timekey ,DROP table and rename
}
这个查询的当前响应时间很慢
部分结果:
总记录: 200 万条
执行时间: 180 秒
这是在 16Gb RAM 上 CPU 部署在低等级系统上很慢
我为解决此问题采取的步骤:
查看了所有 table 的索引。尝试删除索引并 运行ning 实用程序。删除索引使实用程序快了 5 秒,这也不算多。
分阶段执行实用程序:如果总记录超过 100 万条,则 运行 实用程序一次 100 万条
但经过所有这些努力,主要问题似乎出在查询本身。
只是不够快。我只是需要一种提高查询效率的方法
感谢任何帮助, 谢谢你们!!
为什么我们添加 timekey
然后删除它?将它添加到一个空的 table 中很快,但是在它被填充后从 table 中删除它,就像 table 的一个额外副本。如果我们不需要,那是不必要的工作。
我们可以对一个表达式做一个GROUP BY
;该表达式不必出现在 SELECT 列表中。例如:
SELECT t.*
FROM main_table t
WHERE t.column_name <= '2018-01-01'
GROUP
BY FLOOR(UNIX_TIMESTAMP(t.column_name)/((1440/2)*60))
(请注意,如果 sql_mode 中包含 ONLY_FULL_GROUP_BY
,此查询将导致错误;这会禁用允许查询 运行 的 MySQL-specific 扩展。)
没有一些 table 定义(包括存储引擎、列数据类型、索引)并且没有 EXPLAIN 输出,我们只是猜测。
但是一些建议:
在正在填充的空 table 上删除二级索引,并在 table 加载后添加它们。
我会避免 UNION。鉴于其中一个 SELECT 语句在 column_name
上有一个谓词,而另一个在完全不同的列 date
上有一个谓词,我们确实想要分开 SELECT 语句。
CREATE TABLE main_table_tmp LIKE main_table
;
-- for performance, remove secondary indexes, leave just the cluster index
ALTER TABLE main_table_tmp
DROP INDEX noncluster_index_1
, DROP INDEX noncluster_index_2
, ...
;
-- for performance, have a suitable index available on main_table
-- with `column_name` as the leading column
INSERT INTO main_table_tmp
SELECT h.*
FROM main_table h
WHERE h.column_name <= '2018-01-01'
GROUP
BY FLOOR(UNIX_TIMESTAMP(h.column_name)/((1440/2)*60))
;
-- for performance, have a suitable index available on main_table
-- with `date` as the leading column
INSERT INTO main_table_tmp
SELECT c.*
FROM main_table
WHERE c.date > '????-??-??'
;
-- add secondary indexes
ALTER TABLE maint_table_tmp
ADD UNIQUE INDEX noncluster_index_1 (fee,fi,fo)
, ADD INDEX noncluster_index_2 (fum)
, ...
;