web-dev-qa-db-ja.com

MS SQL 2012の特定のパーティションからデータを削除する

パーティションIDを使用して特定のパーティションからデータを削除したいのですが。 SQL 2016の特定のパーティションからデータを切り捨てるクエリを取得しましたが、それより低いバージョンのクエリは見つかりませんでした。

以下のクエリを実行して、パーティションID 14および15のパーティションからデータのみを削除しました。

delete from  partitiontable1 WITH (PARTITIONS (14 to 15))

Deleteステートメントは、パーティション自体をデータと共に削除しますか?

パーティションをそのままにして、特定のパーティションからデータを削除したい。たとえば、テーブルにパーティションを作成し、5つのパーティション(1、2、3、4、5)があり、2番目と3番目のパーティションからのみデータを削除したいとします。

2
l.lijith

この削除ステートメントは無効なSQL Server 2012構文であるため、エラーが発生するだけです。

パーティションとそれに関連付けられた境界を削除するには、MERGE DDLを使用します。 DELETEのようなDMLステートメントはパーティションを削除しません。

SQL 2014以前のバージョンでパーティションからすべての行を削除する最も効率的な方法は、SWITCHを使用することです(SQL 2016では、特定のパーティションをTRUNCATEで指定できます)。 SWITCHを使用するには、同じスキーマとインデックスを使用して、同様にパーティション分割されたステージングテーブルを作成します。次に、メタデータ操作としてテーブル間でデータを切り替え、次にステージングテーブルをTRUNCATEできます。

ALTER TABLE dbo.YourTable
    SWITCH PARTITION 1 TO dbo.YourTable_Staging PARTITION 1;
ALTER TABLE dbo.YourTable
    SWITCH PARTITION 2 TO dbo.YourTable_Staging PARTITION 2;
ALTER TABLE dbo.YourTable
    SWITCH PARTITION 3 TO dbo.YourTable_Staging PARTITION 3;
ALTER TABLE dbo.YourTable
    SWITCH PARTITION 4 TO dbo.YourTable_Staging PARTITION 4;
ALTER TABLE dbo.YourTable
    SWITCH PARTITION 5 TO dbo.YourTable_Staging PARTITION 5;
TRUNCATE TABLE dbo.YourTable_Staging;
4
Dan Guzman

この回答は Cathrine Wilhemsen からのものです。彼女が近くのイベントに出席している場合は、プレゼントを読んで見ることを強くお勧めします。コードは主に彼女から来ており、 Itzik Ben-Gan へのシャウトアウトと彼の関数GetNumsがあります。

要約すると、パーティションを新しいテーブルに切り替えて、テーブルを削除します。その後もパーティション番号は残ります。以下のコード(主にCathrineからのものですが、少し変更しました)をデモとして参照してください。

-- Drop objects if they already exist
IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesSource')
  DROP TABLE SalesSource;
IF EXISTS (SELECT * FROM sys.tables WHERE name = N'SalesTarget')
  DROP TABLE SalesTarget;
IF EXISTS (SELECT * FROM sys.partition_schemes WHERE name = N'psSales')
  DROP PARTITION SCHEME psSales;
IF EXISTS (SELECT * FROM sys.partition_functions WHERE name = N'pfSales')
  DROP PARTITION FUNCTION pfSales;

-- Create the Partition Function 
CREATE PARTITION FUNCTION pfSales (DATE)
AS RANGE RIGHT FOR VALUES 
('2013-01-01', '2014-01-01', '2015-01-01');

-- Create the Partition Scheme
CREATE PARTITION SCHEME psSales
AS PARTITION pfSales 
ALL TO ([Primary]);

-- Create the Partitioned Source Table (Heap) on the Partition Scheme
CREATE TABLE SalesSource (
  SalesDate DATE,
  Quantity INT
) ON psSales(SalesDate);

 IF OBJECT_ID(N'dbo.GetNums', N'IF') IS NOT NULL DROP FUNCTION dbo.GetNums;
GO
CREATE FUNCTION dbo.GetNums(@low AS BIGINT, @high AS BIGINT) RETURNS TABLE
AS
RETURN
  WITH
    L0   AS (SELECT c FROM (SELECT 1 UNION ALL SELECT 1) AS D(c)),
    L1   AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
    L2   AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
    L3   AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
    L4   AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
    L5   AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B),
    Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
             FROM L5)
  SELECT TOP(@high - @low + 1) @low + rownum - 1 AS n
  FROM Nums
  ORDER BY rownum;
GO
-- Insert test data
INSERT INTO SalesSource(SalesDate, Quantity)
SELECT DATEADD(DAY,dates.n-1,'2012-01-01') AS SalesDate, qty.n AS Quantity
FROM GetNums(1,1000) dates
CROSS JOIN GetNums(1,1000) AS qty;

-- Create the Non-Partitioned Target Table (Heap) on the [PRIMARY] filegroup
CREATE TABLE SalesTarget (
  SalesDate DATE,
  Quantity INT
) ON [PRIMARY];

-- Verify row count before switch
SELECT 
    pstats.partition_number AS PartitionNumber
    ,pstats.row_count AS PartitionRowCount
FROM sys.dm_db_partition_stats AS pstats
WHERE pstats.object_id = OBJECT_ID('Salessource')
ORDER BY PartitionNumber; -- 366000 rows in Partition 1, 365000 rows in Partition 2 and 269000 in 3 and 0 in 4
SELECT COUNT(*) FROM SalesTarget; -- 0 rows

-- Turn on statistics
SET STATISTICS TIME ON;

-- Is it really that fast...?
ALTER TABLE SalesSource SWITCH PARTITION 1 TO SalesTarget; 
-- YEP! SUPER FAST!

-- Turn off statistics
SET STATISTICS TIME OFF;

-- Verify row count after switch
SELECT 
    pstats.partition_number AS PartitionNumber
    ,pstats.row_count AS PartitionRowCount
FROM sys.dm_db_partition_stats AS pstats
WHERE pstats.object_id = OBJECT_ID('SalesSource')
ORDER BY PartitionNumber; -- 0 rows in Partition 1, 365000 rows in Partition 2 and 269000 in 3 and 0 in 4
SELECT COUNT(*) FROM SalesTarget; -- 366000 rows
0
Shaulinator