【问题标题】:mysql 8 window function wrong resultsmysql 8窗口函数错误结果
【发布时间】:2018-12-12 04:37:56
【问题描述】:

我在 MySQL8 中遇到了窗口函数的问题 - 它们在应用于大型表时会给出不正确的结果(或者:大量行或大量列)。

示例: 表:office.csv(170 万行)来自https://www.kaggle.com/c/home-credit-default-risk/data

我运行 3 个简单查询,仅更改要使用的表的行数和要输出的列数。您可以清楚地看到,大量行和许多输出列的组合给出了“count(*) over()”的错误结果 - 最后一列。

high number of rows, low number of columns - result: OK;

high number of rows, high number of columns - result: INCORRECT;

low number of rows, hight number of columns - result: OK;

Ubuntu 16.04,32GB 内存

非常感谢您的帮助! :)

无所事事

my.cnf:
[mysqld]

innodb_buffer_pool_size = 26G
default_authentication_plugin=mysql_native_password
thread_cache_size = 50
innodb-flush-method=O_DIRECT
local_infile=ON
innodb_thread_concurrency=2
internal_tmp_mem_storage_engine=MEMORY
join_buffer_size=1G
temptable_max_ram=4G
tmp_table_size=4G
max_heap_table_size=4G
mysqlx_connect_timeout=99999
mysqlx_read_timeout=99999
mysqlx_write_timeout=99999
net_read_timeout=99999
net_write_timeout=99999
regexp_time_limit=99999
mysqlx_port_open_timeout=99999
windowing-use-high-precision=OFF
sort_buffer_size=4G

要运行的代码:

select a.*
from
(
select #b.sk_id_curr,
       b.*,
       count(*) over(partition by b.sk_id_curr) as counter
from (select * from bureau limit 10000000) b
) a
order by a.sk_id_curr desc
limit 100
;

编辑: exlain and indexes picture

我还注意到一件事:在“INCORRECT”图片中,所有列都不正确(不仅是最后一个) - 与“GOOD”结果的图片比较”(查看 sk_id_curr)。

根据 Wilson Hauck 的要求:A) 完整(未编辑)my.cnf-ini 文本结果:B) SHOW GLOBAL STATUS; C) 显示全局变量; D) 显示 ENGINE INNODB 状态; SHOW CREATE TABLE 局; part1 part2

DB Fiddle 上的 1000 行示例:https://www.db-fiddle.com/f/fzXsN6vFzidhanxeUjWkiB/0

我将数据导入mysql的方式:

首先我将 csv 中的“空格”替换为 python 中的“NULL”:

import pandas as pd
bureau = pd.read_csv('../input/bureau.csv')
bureau.to_csv('../input/bureau2.csv',index=False,na_rep="NULL",header=True)

第二我用mysql中的代码:

LOAD DATA LOCAL INFILE '../input/bureau2.csv' INTO TABLE bureau
FIELDS TERMINATED BY ',' ENCLOSED BY '"' 
LINES TERMINATED BY '\n'
IGNORE 1 LINES
;

【问题讨论】:

  • 为什么会出错? MySQL docs cleary 声明窗口函数适用于行“窗口函数对一组查询行执行类似聚合的操作。但是,虽然聚合操作将查询行分组为单个结果行,但窗口函数会为每个查询行生成一个结果查询行:"源dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html
  • 请在此处以纯文本形式发布代码、错误、示例数据或文本输出,而不是难以阅读的图像,不能复制粘贴以帮助测试代码或在答案中使用,并且对使用屏幕阅读器的人怀有敌意。您可以编辑问题以在问题正文中添加代码。使用{} 按钮格式化任何代码块,或使用四个空格缩进以获得相同的效果。 很遗憾,我们无法将您的屏幕截图作为代码运行。
  • @RaymondNijland 每行的“count(*) over(partition by b.sk_id_curr)”的正确结果是共享相同 b._sk_id_curr 值的行数。
  • @tadman 已经提供了数据表的链接,代码是经典的“单线”,但我会为您提供。
  • 内联代码比链接好很多。谢谢。

标签: mysql large-data window-functions mysql-8.0


【解决方案1】:

此版本为我提供了 8.0.11 的预期结果(请注意不再有任何文本 blob)。如果您设置了 --big_tables 以使其正常工作,您还需要禁用它。

CREATE TABLE `bureau` (
 `SK_ID_CURR` int(11) DEFAULT NULL,
 `SK_ID_BUREAU` int(11) DEFAULT NULL,
 `CREDIT_ACTIVE` varchar(20),
 `CREDIT_CURRENCY` varchar(20),
 `DAYS_CREDIT` int(11) DEFAULT NULL,
 `CREDIT_DAY_OVERDUE` int(11) DEFAULT NULL,
 `DAYS_CREDIT_ENDDATE` varchar(20),
 `DAYS_ENDDATE_FACT` varchar(20),
 `AMT_CREDIT_MAX_OVERDUE` varchar(20),
 `CNT_CREDIT_PROLONG` int(11) DEFAULT NULL,
 `AMT_CREDIT_SUM` double DEFAULT NULL,
 `AMT_CREDIT_SUM_DEBT` varchar(20),
 `AMT_CREDIT_SUM_LIMIT` varchar(20),
 `AMT_CREDIT_SUM_OVERDUE` double DEFAULT NULL,
 `CREDIT_TYPE` varchar(20),
 `DAYS_CREDIT_UPDATE` int(11) DEFAULT NULL,
 `AMT_ANNUITY` varchar(20),
 KEY `bureau` (`SK_ID_CURR`,`SK_ID_BUREAU`),
 KEY `bureau_i2` (`SK_ID_BUREAU`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

set session sql_mode='';
load data infile '/export/home/tmp/dag/git/mysql/bureau.csv' into table bureau columns terminated by "," ignore 1 lines;


select a.*
from
(
select #b.sk_id_curr,
       b.*,
       count(*) over(partition by b.sk_id_curr) as counter
from (select * from bureau) b
) a
order by a.sk_id_curr desc
limit 100
;

【讨论】:

  • atDagW,运气不好...i.stack.imgur.com/7NCMF.png,big_tables=OFF,从今天 8 月 12 日开始
  • 奇怪...好的,感谢您的尝试。我会说服这个。
  • 是的,我是,但前提是我在 8.0.11 上使用 --big-tables(在最新的主干上)或大表或文本 blob。我们正在调查。
  • Witek,观察到的行为已被追溯到错误并找到了解决方案。感谢您帮助发现此问题!
  • 谢谢 DagW :) 我试图在当前的一场 kaggle 比赛中使用 MySQL,但现在我换了另一场比赛。但在未来我一定会再次使用 MySQL。好吧,因为我有点“解决了”并且因为社区(你和威尔森)非常有帮助。 :) 谢谢。 :)
【解决方案2】:

为您的 my.cnf-ini [mysqld] 部分考虑的建议

temptable_max_ram=320M # from 4G for 1 percent of RAM 
tmp_table_size=320M # from 4G for 1 percent of RAM 
max_heap_table_size=320M # from 4G for 1 percent of RAM 
innodb_thread_concurrency=0 # from 2 throttle choking your server 
innodb_buffer_pool_size=24G # from 26G for 80% of RAM 
innodb_change_buffer_max_size=10 # from 25 percent set aside 
# sort_buffer_size=4G for default 
# join_buffer_size=4G for default 

只有 32G RAM,您要求 26G、1G、4G、4G、4G、4G = 43G 没有给 MySQL 和 OS 留下任何东西?

如需更多帮助,请查看个人资料、网络个人资料以获取联系信息。

【讨论】:

  • @Witek Oleksiewicz 是否已将任何建议应用于 my.cnf-ini?您能否发布最近的完整错误日志(或最后 400 行)?
  • 'at' Wilson Hauck,是的,我应用了你的所有建议 - 这没有帮助,我没有用完内存 - 表不够大。没有错误 - 只是查询输出不正确......如果我错了,请纠正我 - 默认情况下,错误应该显示在控制台上,是吗?我不是数据库大师 - 我只是想成为一个快乐的用户...... :)
  • @WitekOleksiewicz 请发布 SHOW CREATE TABLE 局的文本结果;来自您的系统。
  • 'at' Wilson Hauck,我在 OP 末尾添加了您要求的内容。感谢您的帮助。 :)
  • @WitekOleksiewicz 这有可能奏效吗?未测试。 select a.* from (select #b.sk_id_curr, b.*, count(*) over(partition by b.sk_id_curr) as counter FROM Bureau limit 10000000) b) a order by a.sk_id_curr desc limit 100 ;很抱歉在保存编辑上重新格式化
【解决方案3】:

我下载了 Bureau.csv 并使用您的表格将其导入,如您的“第 2 部分”链接所示。我不得不禁用严格模式

set session sql_mode='';)

否则我在加载数据时出错

(load data  infile 'bureau.csv' into table bureau columns terminated by "," ignore 1 lines;

不过,我的统计数据与你的略有不同:

然后我运行了您失败的查询并得到了预期的结果:

您使用的是哪个版本的 MySQL 8?

查询的文本版本:

select a.*
   from
   (
   select #b.sk_id_curr,
          b.*,
          count(*) over(partition by b.sk_id_curr)
   from (select * from bureau limit 10000000000) b
   ) a
   order by a.sk_id_curr desc
   limit 100
   ;

【讨论】:

  • atDagW,根据我的笔记,我使用了文件“dev.mysql.com/get/mysql-apt-config_0.8.10-1_all.deb”,“版本”变量是 8.0.11
  • atDagW,请查看我的屏幕(i.stack.imgur.com/Blz9d.png - 无法在 OP 中发布更多链接) - 您可以看到带有 NULL 的列(明确显示),而屏幕上有空格,什么是那是什么意思? :) 你的“select count(*) from kag_home.bureau;”的结果是什么?我的 1716428
  • atDagW,我添加了有关如何在 OP 中导入文件的信息。我会检查你的方法,你可以检查我的。
  • atDagW,我尝试复制你的路径,但我的结果仍然有错误...i.stack.imgur.com/DcZDk.png我使用“LOAD DATA LOCAL INFILE”而不是“LOAD DATA INFILE”。
  • 在列数有限的情况下仍然可以正常工作(b.sk_id_curr 而不是 b.*)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
  • 2012-12-07
  • 2023-03-13
  • 2011-06-29
  • 2018-11-11
相关资源
最近更新 更多