簡體   English   中英

數據庫對象中的封裝查詢返回的行太少

[英]Encapsulated query within a database object returns too few rows

我的團隊成員已經獲得了一些奇怪的行為,可以在開發環境和系統測試環境MS SQL數據庫中重新創建。

如果他直接運行此查詢,則返回517行 ,這是正確的預期結果:

SELECT 
        p.package_id, la.CODE_KID
    FROM package p with (nolock), Strength s with (nolock),
    ProductCODE la  with (nolock), CODE  a with (nolock)
    where p.Strength_ID = s.Strength_ID
    and la.Product_ID = s.Product_ID
    AND la.CODE_KID = a.CODE_ID
    except 
    select p.package_ID, p.CODE_KID from package p

但是,如果他在視圖中放置相同的查詢,則錯誤地返回311行 - 比直接運行查詢的206行

如果我們為直接查詢和視圖查詢運行查詢分析器,我們會看到兩個查詢計划完全不同,但我們不明白為什么。

他還試圖將查詢轉儲到臨時表中:

insert into MyDB.CODE_PACKAGE
    SELECT 
            p.package_id, la.CODE_KID
        FROM package p with (nolock), Strength s with (nolock),
        ProductCODE la  with (nolock), CODE  a with (nolock)
        where p.Strength_ID = s.Strength_ID
        and la.Product_ID = s.Product_ID
        AND la.CODE_KID = a.CODE_ID
        except 
        select p.package_ID, p.CODE_KID from package p

,正確創建一個包含517行的表。 但是,如果他將相同的SQL放在存儲過程中,則會錯誤地返回311行

似乎一旦查詢被封裝在數據庫對象中,它就會返回太少的行。

如上所述,他也在其他數據庫系統上重新創建了錯誤。

什么想法會導致這種奇怪的行為?

他也嘗試過以下方面但沒有取得任何成功:

  • 刪除nolock
  • 將事務隔離級別設置為read uncommitted

更新

我不確定是否使用SSMS向導或模板來創建視圖,但如果我選擇“腳本視圖為 - >創建到 - >新查詢編輯器窗口”,那么這是輸出:

USE [TestUtv]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE view [MyDBviews].[CODE_PACKAGE]
as

    SELECT 
            p.package_id, la.CODE_KID
        FROM package p with (nolock), Strength s with (nolock),
        ProductCODE la  with (nolock), CODE  a with (nolock)
        where p.Strength_ID = s.Strength_ID
        and la.Product_ID = s.Product_ID
        AND la.CODE_KID = a.CODE_ID
        except 
        select p.package_ID, p.CODE_KID from package p

GO

這是使用的表之一,遺憾的是數據庫非常龐大,有數百個表和視圖,所以我不能在這里發布所有內容。

CREATE TABLE [dbo].[Package](
    [Package_ID] [uniqueidentifier] NOT NULL,
    [Multiple] [int] NULL,
    [Multiple2] [int] NULL,
    [OutProdnum] [varchar](6) NULL,
    [OutProdnumDate] [datetime] NULL,
    [zzzPackage_KID] [uniqueidentifier] NULL,
    [Strength_ID] [uniqueidentifier] NULL,
    [Indi] [varchar](4096) NULL,
    [CreatedDate] [datetime] NULL,
    [CreatedBy] [varchar](255) NULL,
    [LastChangedDate] [datetime] NULL,
    [LastChangedBy] [varchar](255) NULL,
    [CODE_KID] [uniqueidentifier] NULL,
    [MarkDate] [datetime] NULL,
    [Amount] [int] NULL,
    [KIPackage_ID] [uniqueidentifier] NULL,
    [xyz] [bit] NULL,
    [Ean] [varchar](255) NULL,
    [D_ID] [uniqueidentifier] NULL,
    [abc_ID] [uniqueidentifier] NULL,
    [DDD] [decimal](18, 4) NULL,
    [era_KID] [uniqueidentifier] NULL,
    [uuu] [decimal](18, 4) NULL,
    [ueer_KID] [uniqueidentifier] NULL,
    [abcIdString] [varchar](4095) NULL,
    [ExternalId] [varchar](255) NULL,
    [Dpack_KID] [uniqueidentifier] NULL,
    [tttpacks_KID] [uniqueidentifier] NULL,
 CONSTRAINT [Package_PK] PRIMARY KEY CLUSTERED 
(
    [Package_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]

嘗試在SP和/或函數中填充查詢,並比較返回的記錄數。 您看到的內容可能會受到連接ANSI設置的影響。 SSMS和SQL Server默認在每個連接上設置一些,而像視圖這樣的對象在創建時設置它們並在執行時保持不變。 檢查當前為您的會話啟用的選項: https//www.mssqltips.com/sqlservertip/1415/determining-set-options-for-a-current-session-in-sql-server/
檢查視圖中保留的選項:

SELECT * FROM sys.sql_modules

使用JOIN語句嘗試相同的查詢。 對於使用此舊連接技術的查詢,您最終可能會得到不同查詢計划的不同結果。

SELECT 
    p.package_id, 
    la.CODE_KID
FROM package p with (nolock)
INNER JOIN Strength s with (nolock)
    ON p.Strength_ID = s.Strength_ID
INNER JOIN ProductCODE la with (nolock)
    ON la.Product_ID = s.Product_ID
INNER JOIN CODE a with (nolock)
    ON la.CODE_KID = a.CODE_ID
EXCEPT
SELECT 
    p.package_ID, 
    p.CODE_KID 
FROM package p

我建議您嘗試完成以下語法。 我的猜測是在創建存儲過程時以某種方式使用中斷的舊ANSI JOIN語法。

SELECT 
    p.package_id 
    ,la.CODE_KID
FROM package AS p
JOIN Strength AS s ON p.Strength_ID = s.Strength_ID
JOIN ProductCODE AS la ON la.Product_ID = s.Product_ID
JOIN CODE AS a ON la.CODE_KID = a.CODE_ID
EXCEPT 
SELECT p.package_ID, p.CODE_KID from package p

真正的問題是,如果將查詢封裝到視圖中,哪些recods會被過濾掉?

因此,正如@Alex之前建議的那樣,您應該比較查詢中的結果和視圖中的相同查詢。

在SSMS嘗試類似於:

SELECT *
FROM (
    SELECT p.package_id, la.CODE_KID
    FROM package p with (nolock), Strength s with (nolock),
    ProductCODE la  with (nolock), CODE  a with (nolock)
    where p.Strength_ID = s.Strength_ID
    and la.Product_ID = s.Product_ID
    AND la.CODE_KID = a.CODE_ID
    except 
    select p.package_ID, p.CODE_KID from package p
    ) AS DIRECT_Q
FULL JOIN
    (
    SELECT *
    FROM YOUR_VIEW_CREATED_FROM_QUERY    /* <-- THE NAME OF YOUR VIEW */
    ) AS VIEWED_Q
ON DIRECT_Q.package_id=VIEWED_Q.package_id 
   AND DIRECT_Q.CODE_KID=VIEWED_Q.CODE_KID

通過這種方式,您將看到哪些記錄丟失並嘗試了解原因(空值,重音符號,特定字符ecc ecc)

我還將檢查package.CODE_KID和ProductCODE.CODE_KID的數據類型排序規則是否相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM