SQL Server 2005中的大规模CROSS JOIN

时间:2008-12-10 03:01:30

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

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

首先,我将尽可能地从流程中删除此表 - 显然可以通过单独连接到两个表来替换它,但是现在我无法看到它所使用的其他任何地方。 / p>

但是考虑到现有的流程(在较短的时间内,在功能较弱的机器上,使用FOCUS语言),是否有任何选项可以提高SQL Server(2005)中大CROSS JOIN的性能(硬件实际上不是一个选项,这个盒子是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 JOIN这样的大表的任何技巧(特别是鉴于FOCUS中的现有流程能够更快地完成。)这样我就可以验证构建替换查询的正确性,然后将其与视图或其他任何因素一起分解。

我也在考虑将UDF和字符串操作分解出来并首先执行CROSS JOIN以稍微打破这个过程。

结果如此:

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

3 个答案:

答案 0 :(得分:2)

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

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上有任何触发器吗?索引怎么样?如果插入这么大,您将要删除该表上的所有触发器和索引。

答案 1 :(得分:2)

继续其他人的说法,包含查询中使用的查询的数据库函数总是使我的查询非常慢。在我的头顶,我相信我有一个查询运行45秒,然后我删除了该功能,然后结果是0秒:))

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

答案 2 :(得分:1)

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


   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

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