2011-12-13 2 views
1

웹 서버 (CMS)에 올려졌지만 더 이상 필요하지 않으며 삭제할 수있는 파일을 식별하기위한 소프트웨어를 작성하고 있습니다.이 SQL 쿼리를 최적화하는 방법

시작하려면 필요한 모든 단계를 수동으로 재현하려고합니다.

웹 루트에서 실행 된 배치 스크립트를 사용하여 서버의 모든 (관련) 파일을 식별합니다. 그럼, SQL Server에 목록을 수입하고있어 테이블은 다음과 같습니다

id filename 
1 filename1.docx 
2 files/file.pdf 
3 files/filename2.docx 
4 files/filename3.docx 
5 files/file1.pdf 
6 file2.pdf 
7 file4.pdf 

나는 또한 CMS 데이터베이스 2 개 페이지의 컨텐츠를 저장하는 테이블이 (Alterian/직접 CMC 6.X)이 있습니다 page_data 및 PageXMLArchive.

첫 번째 테이블의 파일이 page_data 테이블의 p_content 열과 PageXMLArchive 테이블의 PageXML 열의 모든 위치에서 참조되는지 여부를 확인하기 위해 데이터베이스를 검사하고 싶습니다.

그래서 각 파일 이름을 가져 와서 해당 테이블에서 참조되는지 검사합니다. 건너 뛰면 임시 테이블에 추가됩니다.

쿼리가 끝나면 임시 테이블이 표시됩니다. 아래

검색어 :

인해 쿼리가 밖으로 실행하고 시간이 2 시간 이상 소요 불쌍한 내 SQL 기술에 불행하게도
DECLARE @t as table (_fileName nvarchar(255)) 
DECLARE @row as int 
DECLARE @result as nvarchar(255) 

SET @row = 1 


WHILE(@row <= (SELECT COUNT(*) FROM ListFileReport)) 
BEGIN 
    SET @result = (SELECT [FileName] FROM ListFileReport WHERE id = @row) 

    IF ((SELECT TOP(1) p_content FROM page_data WHERE p_content LIKE '%' + LTRIM(RTRIM(@result)) + '%') IS NULL) OR ((SELECT TOP(1) PageXML FROM PageXMLArchive WHERE PageXML LIKE '%' + LTRIM(RTRIM(@result)) + '%') IS NULL) 
    BEGIN 
     INSERT INTO @t (_fileName) VALUES(@result) 
    END 

    SET @row = @row + 1 

END 

select * from @t 

.

ntext 필드에서 WHERE x LIKE 문을 1000 초 실행하지 않고도 비슷한 질문을 던지려면 어떻게해야합니까? 나는 데이터베이스를 변경할 수 없으며, 그대로 유지되어야한다. (또는 지원되지 않을 것이다. 고객에게 큰 이익이된다.)

감사

편집 : 은 현재 내가 한 번에 몇 백 결과를 일괄 처리하여 문제를 해결 일하고 있어요. 그것은 효과가 있지만 영원히 걸립니다.

편집 :

내가 아마도 이것을 달성하기 위해 전체 텍스트 검색을 이용할 수 있습니까? 나는 원하는 결과를 얻기 위해 스키마를 변경하는 방법이 있다면 데이터베이스의 스냅 샷을 작성하고 사본을 작성하려고합니다.

page_data 테이블 :

USE [TD-VMB-01-STG] 
GO 

/****** Object: Table [dbo].[page_data] Script Date: 12/13/2011 13:19:15 ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE TABLE [dbo].[page_data](
    [p_page_id] [int] NOT NULL, 
    [p_title] [nvarchar](120) NULL, 
    [p_link] [nvarchar](250) NULL, 
    [p_content] [ntext] NULL, 
    [p_parent_id] [int] NULL, 
    [p_top_id] [int] NULL, 
    [p_stylesheet] [nvarchar](50) NULL, 
    [p_author] [nvarchar](50) NULL, 
    [p_last_update] [datetime] NULL, 
    [p_order] [smallint] NULL, 
    [p_window] [nvarchar](10) NULL, 
    [p_meta_keywords] [nvarchar](1000) NULL, 
    [p_meta_desc] [nvarchar](2000) NULL, 
    [p_type] [nvarchar](1) NULL, 
    [p_confirmed] [int] NOT NULL, 
    [p_changed] [int] NOT NULL, 
    [p_access] [int] NULL, 
    [p_errorlink] [nvarchar](255) NULL, 
    [p_noshow] [int] NOT NULL, 
    [p_edit_parent] [int] NULL, 
    [p_hidemenu] [int] NOT NULL, 
    [p_subscribe] [int] NOT NULL, 
    [p_StartDate] [datetime] NULL, 
    [p_EndDate] [datetime] NULL, 
    [p_pageEnSDate] [int] NOT NULL, 
    [p_pageEnEDate] [int] NOT NULL, 
    [p_hideexpiredPage] [int] NOT NULL, 
    [p_version] [float] NULL, 
    [p_edit_order] [float] NULL, 
    [p_order_change] [datetime] NOT NULL, 
    [p_created_date] [datetime] NOT NULL, 
    [p_short_title] [nvarchar](30) NULL, 
    [p_authentication] [tinyint] NOT NULL, 
CONSTRAINT [aaaaapage_data_PK] PRIMARY KEY NONCLUSTERED 
(
    [p_page_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] TEXTIMAGE_ON [PRIMARY] 

GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_order] DEFAULT (0) FOR [p_order] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF__Temporary__p_con__1CF15040] DEFAULT (0) FOR [p_confirmed] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF__Temporary__p_cha__1DE57479] DEFAULT (0) FOR [p_changed] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF__Temporary__p_acc__1ED998B2] DEFAULT (1) FOR [p_access] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF__Temporary__p_nos__1FCDBCEB] DEFAULT (0) FOR [p_noshow] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF__Temporary__p_edi__20C1E124] DEFAULT (0) FOR [p_edit_parent] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF__Temporary__p_hid__21B6055D] DEFAULT (0) FOR [p_hidemenu] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_subscribe] DEFAULT (0) FOR [p_subscribe] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_pageEnSDate] DEFAULT (0) FOR [p_pageEnSDate] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_pageEnEDate] DEFAULT (0) FOR [p_pageEnEDate] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_hideexpiredPage] DEFAULT (1) FOR [p_hideexpiredPage] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_version] DEFAULT (0) FOR [p_version] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_edit_order] DEFAULT (0) FOR [p_edit_order] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_order_change] DEFAULT (getdate()) FOR [p_order_change] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_created_date] DEFAULT (getdate()) FOR [p_created_date] 
GO 

ALTER TABLE [dbo].[page_data] ADD CONSTRAINT [DF_page_data_p_authentication] DEFAULT ((0)) FOR [p_authentication] 
GO 

PageXMLArchive 테이블 : 당신은 예입니다 여기에 여러 가지 방법으로 루프를 방지 할 수 있습니다

USE [TD-VMB-01-STG] 
GO 

/****** Object: Table [dbo].[PageXMLArchive] Script Date: 12/13/2011 13:20:00 ******/ 
SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

CREATE TABLE [dbo].[PageXMLArchive](
    [ArchiveID] [bigint] IDENTITY(1,1) NOT NULL, 
    [P_Page_ID] [int] NOT NULL, 
    [p_author] [nvarchar](100) NULL, 
    [p_title] [nvarchar](400) NULL, 
    [Version] [int] NOT NULL, 
    [PageXML] [ntext] NULL, 
    [ArchiveDate] [datetime] NOT NULL, 
CONSTRAINT [PK_PageXMLArchive] PRIMARY KEY CLUSTERED 
(
    [ArchiveID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

GO 

ALTER TABLE [dbo].[PageXMLArchive] ADD CONSTRAINT [DF_PageXMLArchive_ArchiveDate] DEFAULT (getdate()) FOR [ArchiveDate] 
GO 
+0

page_data 및 PageXMLArchive 테이블의 구조를 질문에 포함 할 수 있습니까? –

+2

처음에는'WHILE' 위에'SELECT COUNT (*)'를 이동시켜 결과를 변수에 넣어야합니다. 모든 행에 대해 해당 쿼리를 수행하지 않으려면. – Johan

+0

@ MarkBannister가 테이블 구조를 추가했습니다. 감사합니다. – LukeP

답변

3

...

SELECT 
    * 
FROM 
    ListFileReport 
WHERE 
    NOT EXISTS (
    SELECT * 
    FROM page_data 
    WHERE p_content LIKE '%' + LTRIM(RTRIM(ListFileReport.FileName)) + '%' 
    ) 
    AND 
    NOT EXISTS (
    SELECT * 
    FROM PageXMLArchive 
    WHERE PageXML LIKE '%' + LTRIM(RTRIM(ListFileReport.FileName)) + '%' 
    ) 

참고 : 이렇게하면 루프가 제거되고 이로 인해 많은 개선이 이루어집니다. 그러나 ListFileReport의 모든 항목에 대해 두 가지 조회 테이블 전체를 파싱해야합니다. 유용한 알고리즘이 없어도 유용한 인덱싱이 될 수 없습니다. 그래서 개처럼 느려질 것입니다. 두 개가 아닌 하나의 부러진 다리가 있습니다.


LIKE의 사용을 피하는 유일한 방법은 page_dataPageXMLArchive 테이블의 모든 필드를 구문 분석 및 참조 된 파일의 목록을 작성하는 것입니다. HTML과 XML이 매우 구조화되어 있기 때문에이 작업을 수행 할 수는 있지만 라이브러리 또는 사용자를 대신하여 수행 할 작업을 찾습니다.

그런 다음 중복없이, 모든 파일과 다른 테이블을 생성하고, 적절한 인덱스 할 수 있습니다. LIKE를 사용하는 대신 쿼리하는 것이 훨씬 빨라집니다. 나는 전혀 의심 할 여지가 없다. 그러나 코드를 작성하거나 코드를 찾는 일은 어려움이 될 것입니다.

+0

+1. –

+0

감사합니다. 테스트를 위해 나는 (PageXMLArchive을 떠나, 그것의 일부분 만 쿼리 page_data 테이블)에 쿼리를 실행하고 내 쿼리 5:04 분에 종료 당신의 5 걸리는 반면, :. 09mins를에만 page_data 테이블 (1600 행)에 PageXMLArchive가 16000 개 행이 루프의 지금을 실행 외부 COUNT 쿼리 이전 다시 초에보고 나는 생각하지 않는다 – LukeP

0

저장 프로시 저는 특히 selectinsert이 혼합 된 루프가있어 쿼리의 속도가 느려집니다.

이상적으로는 빠른 개별적으로 각 행을 삽입 할 때보 것 수백만 시간 insert into @table select a, b from table 수 있다면. 귀하의 예를 들어

, 같은 것을 할 수있는 : @t에

삽입 (_fileName) 선택 ... p_content에서 가입 ...에 ... 어디 %의 STH 같은 STH

해당 사항이없는 경우 알려주십시오.

+0

.... 그것은 지연을 일으키는 INSERT입니다. 그것은 SELECT * FROM X WHERE Y LIKE '% Z %'는 총 17000 개의 행을 가진 2 개의 테이블의 ntext 열에 있습니다. 또한 각 행의 ntext 필드에는 XML/HTML 코드의 전체 페이지가 포함됩니다. – LukeP

관련 문제