【问题标题】:Massive CROSS JOIN in SQL Server 2005SQL Server 2005 中的大规模交叉连接
【发布时间】:2010-09-26 04:20:11
【问题描述】:

我正在移植一个创建两个表的 MASSIVE CROSS JOIN 的进程。结果表包含 15m 条记录(看起来该过程与 2600 行表和 12000 行表进行 30m 交叉连接,然后进行一些必须将其分成两半的分组)。行相对较窄 - 只有 6 列。它已经运行了5个小时,没有完成的迹象。我只是注意到已知商品和我对交叉连接的期望之间的计数差异,所以我的输出没有分组或重复数据删除,这将使决赛桌减半 - 但这似乎仍然不会完成任何很快。

首先,如果可能的话,我将考虑从流程中删除该表 - 显然它可以通过单独加入两个表来替换,但现在我无法看到它使用的其他任何地方。

但是考虑到现有进程可以做到(在更短的时间内,在功能不太强大的机器上,使用 FOCUS 语言),是否有任何选项可以提高 SQL Server (2005) 中大型CROSS JOINs 的性能(硬件不是一个真正的选择,这个盒子是 64 位 8 路,32 GB 的 RAM)?

详情:

在 FOCUS 中是这样写的(我正在尝试产生相同的输出,即 SQL 中的 CROSS JOIN):

JOIN CLEAR *
DEFINE FILE COSTCENT
  WBLANK/A1 = ' ';
  END
TABLE FILE COSTCENT
  BY WBLANK BY CC_COSTCENT
  ON TABLE HOLD AS TEMPCC FORMAT FOCUS
  END

DEFINE FILE JOINGLAC
  WBLANK/A1 = ' ';
  END
TABLE FILE JOINGLAC
  BY WBLANK BY ACCOUNT_NO BY LI_LNTM
  ON TABLE HOLD AS TEMPAC FORMAT FOCUS INDEX WBLANK

JOIN CLEAR *
JOIN WBLANK IN TEMPCC TO ALL WBLANK IN TEMPAC
DEFINE FILE TEMPCC
  CA_JCCAC/A16=EDIT(CC_COSTCENT)|EDIT(ACCOUNT_NO);
  END
TABLE FILE TEMPCC
  BY CA_JCCAC BY CC_COSTCENT AS COST CENTER BY ACCOUNT_NO
  BY LI_LNTM
  ON TABLE HOLD AS TEMPCCAC
  END

所以所需的输出实际上是一个 CROSS JOIN(它从每一侧加入一个空白列)。

在 SQL 中:

CREATE TABLE [COSTCENT](
       [COST_CTR_NUM] [int] NOT NULL,
       [CC_CNM] [varchar](40) NULL,
       [CC_DEPT] [varchar](7) NULL,
       [CC_ALSRC] [varchar](6) NULL,
       [CC_HIER_CODE] [varchar](20) NULL,
 CONSTRAINT [PK_LOOKUP_GL_COST_CTR] PRIMARY KEY NONCLUSTERED
(
       [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [JOINGLAC](
       [ACCOUNT_NO] [int] NULL,
       [LI_LNTM] [int] NULL,
       [PR_PRODUCT] [varchar](5) NULL,
       [PR_GROUP] [varchar](1) NULL,
       [AC_NAME_LONG] [varchar](40) NULL,
       [LI_NM_LONG] [varchar](30) NULL,
       [LI_INC] [int] NULL,
       [LI_MULT] [int] NULL,
       [LI_ANLZ] [int] NULL,
       [LI_TYPE] [varchar](2) NULL,
       [PR_SORT] [varchar](2) NULL,
       [PR_NM] [varchar](26) NULL,
       [PZ_SORT] [varchar](2) NULL,
       [PZNAME] [varchar](26) NULL,
       [WANLZ] [varchar](3) NULL,
       [OPMLNTM] [int] NULL,
       [PS_GROUP] [varchar](5) NULL,
       [PS_SORT] [varchar](2) NULL,
       [PS_NAME] [varchar](26) NULL,
       [PT_GROUP] [varchar](5) NULL,
       [PT_SORT] [varchar](2) NULL,
       [PT_NAME] [varchar](26) NULL
) ON [PRIMARY]

CREATE TABLE [JOINCCAC](
       [CA_JCCAC] [varchar](16) NOT NULL,
       [CA_COSTCENT] [int] NOT NULL,
       [CA_GLACCOUNT] [int] NOT NULL,
       [CA_LNTM] [int] NOT NULL,
       [CA_UNIT] [varchar](6) NOT NULL,
 CONSTRAINT [PK_JOINCCAC_KNOWN_GOOD] PRIMARY KEY CLUSTERED
(
       [CA_JCCAC] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

使用 SQL 代码:

INSERT  INTO [JOINCCAC]
       (
        [CA_JCCAC]
       ,[CA_COSTCENT]
       ,[CA_GLACCOUNT]
       ,[CA_LNTM]
       ,[CA_UNIT]
       )
       SELECT  Util.PADLEFT(CONVERT(varchar, CC.COST_CTR_NUM), '0',
                                     7)
               + Util.PADLEFT(CONVERT(varchar, GL.ACCOUNT_NO), '0',
                                       9) AS CC_JCCAC
              ,CC.COST_CTR_NUM AS CA_COSTCENT
              ,GL.ACCOUNT_NO % 900000000 AS CA_GLACCOUNT
              ,GL.LI_LNTM AS CA_LNTM
              ,udf_BUPDEF(GL.ACCOUNT_NO, CC.COST_CTR_NUM, GL.LI_LNTM, 'N') AS CA_UNIT
       FROM   JOINGLAC AS GL
       CROSS JOIN COSTCENT AS CC

根据随后如何使用此表,它应该能够从流程中消除,只需连接到用于构建它的两个原始表即可。但是,这是一个非常大的移植工作,我可能有一段时间找不到表的用法,所以我想知道是否有任何技巧可以及时CROSS JOINing 这样的大表(特别是考虑到FOCUS 中的现有流程能够更快地完成)。这样我就可以验证我构建替换查询的正确性,然后用视图或其他方式将其分解出来。

我也在考虑分解 UDF 和字符串操作,并首先执行 CROSS JOIN 以稍微分解过程。

目前的结果:

事实证明,UDF 确实对性能有很大贡献(负面)。但是 15m 行交叉连接和 30m 行交叉连接之间似乎也存在很大差异。我没有 SHOWPLAN 权限(嘘),所以我无法判断它使用的计划在更改索引后是更好还是更差。我还没有重构它,但我希望整个表很快就会消失。

【问题讨论】:

  • "MASSIVE CROSS JOIN" 该语法应该被引入到 SQL 语言中。 :)

标签: sql sql-server sql-server-2005 performance cross-join


【解决方案1】:

检查该查询显示仅使用了一个表中的一列,并且仅使用了另一表中的两列。由于使用的列数非常少,因此可以通过覆盖索引轻松增强此查询:

CREATE INDEX COSTCENTCoverCross ON COSTCENT(COST_CTR_NUM)
CREATE INDEX JOINGLACCoverCross ON JOINGLAC(ACCOUNT_NO, LI_LNTM)

以下是我需要进一步优化的问题:

当您将查询放入查询分析器并点击“显示估计的执行计划”按钮时,它将显示其将要执行的操作的图形表示。

连接类型:应该有一个嵌套循环连接。 (其他选项是合并连接和哈希连接)。如果您看到嵌套循环,则可以。如果您看到合并联接或哈希联接,请告诉我们。

表格访问顺序:一直到顶部并一直滚动到右侧。第一步应该是访问一个表。那是哪个表以及使用什么方法(索引扫描,聚集索引扫描)?用什么方法访问另一个表?

并行度:您应该在计划中几乎所有图标上看到锯齿状的小箭头,表明正在使用并行度。如果你没有看到这个,那就是一个大问题!

udf_BUPDEF 与我有关。它是否从其他表中读取? Util.PADLEFT 不太关心我,但仍然.. 它是什么?如果它不是数据库对象,请考虑改用它:

RIGHT('z00000000000000000000000000' + columnName, 7)

JOINCCAC 上是否有任何触发器?索引呢?有了这么大的插入,您需要删除该表上的所有触发器和索引。

【讨论】:

  • BUPDEF 是一个庞大的业务逻辑功能,已被移植。希望它会消失(就像这张表一样),但其中没有查找(或为清楚起见我遗漏的其他 UDF)
  • UDF 性能是关键,而且非常糟糕——两个 UDF 每秒只能处理大约 300 行。我目前正在寻找解决方法。
【解决方案2】:

继续其他人的说法,包含在 select 中使用的查询的 DB 函数总是使我的查询非常慢。在我的脑海中,我相信我在 45 秒内运行了一个查询,然后我删除了这个函数,然后结果是 0 秒 :)

所以检查 udf_BUPDEF 没有做任何查询。

【讨论】:

  • UDF 性能(它们是标量且不访问表)是关键且非常糟糕 - 两个 UDF 每秒只能处理大约 300 行。我目前正在寻找解决方法。
【解决方案3】:

分解查询,使其成为一个简单的交叉连接。

SELECT CC.COST_CTR_NUM, GL.ACCOUNT_NO ,CC.COST_CTR_NUM AS CA_COSTCENT ,GL.ACCOUNT_NO AS CA_GLACCOUNT ,GL.LI_LNTM AS CA_LNTM -- I don't know what is BUPDEF doing? but remove it from the query for time being -- ,udf_BUPDEF(GL.ACCOUNT_NO, CC.COST_CTR_NUM, GL.LI_LNTM, 'N') AS CA_UNIT FROM JOINGLAC AS GL CROSS JOIN COSTCENT AS CC

看看简单的交叉连接有多好? (没有应用任何功能)

【讨论】:

  • 如果效果很快,请尝试只执行 SELECT(应用了函数),看看是否还可以?
  • UDF 性能(它们是标量且不访问表)是关键且非常糟糕 - 两个 UDF 每秒只能处理大约 300 行。我目前正在寻找解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 2010-10-18
  • 1970-01-01
相关资源
最近更新 更多