Microsoft Certified Azure Data Engineer Associate · Free Practice Question Hard
Question 50
Scenario: You are working as a consultant at Avengers Security. At the moment, you are consulting with Tony, the lead of the IT team and the topic of discussion is about a table in an enterprise data warehouse in Azure Synapse Analytics. See the subject table details below.
Table Characteristics:
The file name is
SalesHistory.The table contains sales data from the past 36 months.
The file is partitioned by month.
The file contains 1.5 billion rows.
The file has clustered columnstore indexes.
Required:
At the beginning of each month, data older than 36 months must be promptly removed from the SalesHistory file.
The IT team has created a list of possible actions that should be performed to create a stored procedure, but there is debate about which are valid and the required sequence of the tabled actions. See the proposed action list below.
Proposed Actions:
a. Create an empty table named SalesHistory_Current that has a duplicate schema as the SalesHistory table.
b. Drop the SalesHistory_Current table.
c. Copy the data to a new table by using CREATE TABLE AS SELECT.
d. TRUNCATE the partition containing the stale data.
e. Switch the partition containing the stale data from SalesHistory to SalesHistory_Current.
f. Execute a DELETE statement where the value in the Date column is more than 36 months ago.
As the Azure SME, Tony and the team look to you to select the correct actions and put them in order in preparation for creation of the stored procedure. Which of the below contains the correct items in the correct sequence for the required stored procedure?
-
A
a → c → e → d
-
B
c → f → b
-
C
c → b
-
D
a → e → b
-
E
e → f → c
Reveal correct answer
Correct answer: D
Explanation
Step 1: Create an empty table named SalesHistory_Current that has a duplicate schema as the SalesHistory table.
Step 2: Switch the partition containing the stale data from SalesHistory to SalesHistory_Current.
SQL Data Warehouse supports partition splitting, merging, and switching. To switch partitions between two tables, you must ensure that the partitions align on their respective boundaries and that the table definitions match.
Loading data into partitions with partition switching is a convenient way stage new data in a table that is not visible to users the switch in the new data.
Step 3: Drop the SalesHistory_Current table.
Partitioning tables in dedicated SQL pool
Table partitions enable you to divide your data into smaller groups of data. In most cases, table partitions are created on a date column. Partitioning is supported on all dedicated SQL pool table types; including clustered columnstore, clustered index, and heap. Partitioning is also supported on all distribution types, including both hash or round robin distributed.
Partitioning can benefit data maintenance and query performance. Whether it benefits both or just one is dependent on how data is loaded and whether the same column can be used for both purposes, since partitioning can only be done on one column.
Benefits to loads
The primary benefit of partitioning in dedicated SQL pool is to improve the efficiency and performance of loading data by use of partition deletion, switching and merging. In most cases data is partitioned on a date column that is closely tied to the order in which the data is loaded into the SQL pool. One of the greatest benefits of using partitions to maintain data is the avoidance of transaction logging. While simply inserting, updating, or deleting data can be the most straightforward approach, with a little thought and effort, using partitioning during your load process can substantially improve performance.
Partition switching can be used to quickly remove or replace a section of a table. For example, a sales fact table might contain just data for the past 36 months. At the end of every month, the oldest month of sales data is deleted from the table. This data could be deleted by using a delete statement to delete the data for the oldest month.
However, deleting a large amount of data row-by-row with a delete statement can take too much time, as well as create the risk of large transactions that take a long time to rollback if something goes wrong. A more optimal approach is to drop the oldest partition of data. Where deleting the individual rows could take hours, deleting an entire partition could take seconds.
Benefits to queries
Partitioning can also be used to improve query performance. A query that applies a filter to partitioned data can limit the scan to only the qualifying partitions. This method of filtering can avoid a full table scan and only scan a smaller subset of data. With the introduction of clustered columnstore indexes, the predicate elimination performance benefits are less beneficial, but in some cases there can be a benefit to queries.
For example, if the sales fact table is partitioned into 36 months using the sales date field, then queries that filter on the sale date can skip searching in partitions that don't match the filter.
Sizing partitions
While partitioning can be used to improve performance some scenarios, creating a table with too many partitions can hurt performance under some circumstances. These concerns are especially true for clustered columnstore tables.
For partitioning to be helpful, it is important to understand when to use partitioning and the number of partitions to create. There is no hard fast rule as to how many partitions are too many, it depends on your data and how many partitions you loading simultaneously. A successful partitioning scheme usually has tens to hundreds of partitions, not thousands.
When creating partitions on clustered columnstore tables, it is important to consider how many rows belong to each partition. For optimal compression and performance of clustered columnstore tables, a minimum of 1 million rows per distribution and partition is needed. Before partitions are created, dedicated SQL pool already divides each table into 60 distributed databases.
Any partitioning added to a table is in addition to the distributions created behind the scenes. Using this example, if the sales fact table contained 36 monthly partitions, and given that a dedicated SQL pool has 60 distributions, then the sales fact table should contain 60 million rows per month, or 2.1 billion rows when all months are populated. If a table contains fewer than the recommended minimum number of rows per partition, consider using fewer partitions in order to increase the number of rows per partition.
How to split a partition that contains data
The most efficient method to split a partition that already contains data is to use a CTAS statement. If the partitioned table is a clustered columnstore, then the table partition must be empty before it can be split.
The following example creates a partitioned columnstore table. It inserts one row into each partition:
- SQL
- CREATE TABLE [dbo].[FactInternetSales]
- (
- [ProductKey] int NOT NULL
- , [OrderDateKey] int NOT NULL
- , [CustomerKey] int NOT NULL
- , [PromotionKey] int NOT NULL
- , [SalesOrderNumber] nvarchar(20) NOT NULL
- , [OrderQuantity] smallint NOT NULL
- , [UnitPrice] money NOT NULL
- , [SalesAmount] money NOT NULL
- )
- WITH
- ( CLUSTERED COLUMNSTORE INDEX
- , DISTRIBUTION = HASH([ProductKey])
- , PARTITION ( [OrderDateKey] RANGE RIGHT FOR VALUES
- (20000101
- )
- )
- )
- ;
- INSERT INTO dbo.FactInternetSales
- VALUES (1,19990101,1,1,1,1,1,1);
- INSERT INTO dbo.FactInternetSales
- VALUES (1,20000101,1,1,1,1,1,1);
The following query finds the row count by using the sys.partitions catalogue view:
- SQL
- SELECT QUOTENAME(s.[name])+'.'+QUOTENAME(t.[name]) as Table_name
- , i.[name] as Index_name
- , p.partition_number as Partition_nmbr
- , p.[rows] as Row_count
- , p.[data_compression_desc] as Data_Compression_desc
- FROM sys.partitions p
- JOIN sys.tables t ON p.[object_id] = t.[object_id]
- JOIN sys.schemas s ON t.[schema_id] = s.[schema_id]
- JOIN sys.indexes i ON p.[object_id] = i.[object_Id]
- AND p.[index_Id] = i.[index_Id]
- WHERE t.[name] = 'FactInternetSales'
- ;
The following split command receives an error message:
- SQL
- ALTER TABLE FactInternetSales SPLIT RANGE (20010101);
Msg 35346, Level 15, State 1, Line 44 SPLIT clause of ALTER PARTITION statement failed because the partition is not empty. Only empty partitions can be split in when a columnstore index exists on the table. Consider disabling the columnstore index before issuing the ALTER PARTITION statement, then rebuilding the columnstore index after ALTER PARTITION is complete.
However, you can use CTAS to create a new table to hold the data.
- SQL
- CREATE TABLE dbo.FactInternetSales_20000101
- WITH ( DISTRIBUTION = HASH(ProductKey)
- , CLUSTERED COLUMNSTORE INDEX
- , PARTITION ( [OrderDateKey] RANGE RIGHT FOR VALUES
- (20000101
- )
- )
- )
- AS
- SELECT *
- FROM FactInternetSales
- WHERE 1=2
- ;
As the partition boundaries are aligned, a switch is permitted. This will leave the source table with an empty partition that you can subsequently split.
- SQL
- ALTER TABLE FactInternetSales SWITCH PARTITION 2 TO FactInternetSales_20000101 PARTITION 2;
- ALTER TABLE FactInternetSales SPLIT RANGE (20010101);
All that is left is to align the data to the new partition boundaries using CTAS, and then switch the data back into the main table.
- SQL
- CREATE TABLE [dbo].[FactInternetSales_20000101_20010101]
- WITH ( DISTRIBUTION = HASH([ProductKey])
- , CLUSTERED COLUMNSTORE INDEX
- , PARTITION ( [OrderDateKey] RANGE RIGHT FOR VALUES
- (20000101,20010101
- )
- )
- )
- AS
- SELECT *
- FROM [dbo].[FactInternetSales_20000101]
- WHERE [OrderDateKey] >= 20000101
- AND [OrderDateKey] < 20010101
- ;
- ALTER TABLE dbo.FactInternetSales_20000101_20010101 SWITCH PARTITION 2 TO dbo.FactInternetSales PARTITION 2;
Once you have completed the movement of the data, it is a good idea to refresh the statistics on the target table. Updating statistics ensures the statistics accurately reflect the new distribution of the data in their respective partitions.
- SQL
- UPDATE STATISTICS [dbo].[FactInternetSales];
Load new data into partitions that contain data in one step
Loading data into partitions with partition switching is a convenient way to stage new data in a table that is not visible to users. It can be challenging on busy systems to deal with the locking contention associated with partition switching.
To clear out the existing data in a partition, an ALTER TABLE used to be required to switch out the data. Then another ALTER TABLE was required to switch in the new data.
In dedicated SQL pool, the TRUNCATE_TARGET option is supported in the ALTER TABLE command. With TRUNCATE_TARGET the ALTER TABLE command overwrites existing data in the partition with new data. Below is an example that uses CTAS to create a new table with the existing data, inserts new data, then switches all the data back into the target table, overwriting the existing data.
- SQL
- CREATE TABLE [dbo].[FactInternetSales_NewSales]
- WITH ( DISTRIBUTION = HASH([ProductKey])
- , CLUSTERED COLUMNSTORE INDEX
- , PARTITION ( [OrderDateKey] RANGE RIGHT FOR VALUES
- (20000101,20010101
- )
- )
- )
- AS
- SELECT *
- FROM [dbo].[FactInternetSales]
- WHERE [OrderDateKey] >= 20000101
- AND [OrderDateKey] < 20010101
- ;
- INSERT INTO dbo.FactInternetSales_NewSales
- VALUES (1,20000101,2,2,2,2,2,2);
- ALTER TABLE dbo.FactInternetSales_NewSales SWITCH PARTITION 2 TO dbo.FactInternetSales PARTITION 2 WITH (TRUNCATE_TARGET = ON);
Table partitioning source control
To avoid your table definition from rusting in your source control system, you may want to consider the following approach:
1. Create the table as a partitioned table but with no partition values
- SQL
- CREATE TABLE [dbo].[FactInternetSales]
- (
- [ProductKey] int NOT NULL
- , [OrderDateKey] int NOT NULL
- , [CustomerKey] int NOT NULL
- , [PromotionKey] int NOT NULL
- , [SalesOrderNumber] nvarchar(20) NOT NULL
- , [OrderQuantity] smallint NOT NULL
- , [UnitPrice] money NOT NULL
- , [SalesAmount] money NOT NULL
- )
- WITH
- ( CLUSTERED COLUMNSTORE INDEX
- , DISTRIBUTION = HASH([ProductKey])
- , PARTITION ( [OrderDateKey] RANGE RIGHT FOR VALUES () )
- )
- ;
2. SPLIT the table as part of the deployment process:
- SQL
- -- Create a table containing the partition boundaries
- CREATE TABLE #partitions
- WITH
- (
- LOCATION = USER_DB
- , DISTRIBUTION = HASH(ptn_no)
- )
- AS
- SELECT ptn_no
- , ROW_NUMBER() OVER (ORDER BY (ptn_no)) as seq_no
- FROM (
- SELECT CAST(20000101 AS INT) ptn_no
- UNION ALL
- SELECT CAST(20010101 AS INT)
- UNION ALL
- SELECT CAST(20020101 AS INT)
- UNION ALL
- SELECT CAST(20030101 AS INT)
- UNION ALL
- SELECT CAST(20040101 AS INT)
- ) a
- ;
- -- Iterate over the partition boundaries and split the table
- DECLARE @c INT = (SELECT COUNT(*) FROM #partitions)
- , @i INT = 1 --iterator for while loop
- , @q NVARCHAR(4000) --query
- , @p NVARCHAR(20) = N'' --partition_number
- , @s NVARCHAR(128) = N'dbo' --schema
- , @t NVARCHAR(128) = N'FactInternetSales' --table
- ;
- WHILE @i <= @c
- BEGIN
- SET @p = (SELECT ptn_no FROM #partitions WHERE seq_no = @i);
- SET @q = (SELECT N'ALTER TABLE '+@s+N'.'+@t+N' SPLIT RANGE ('+@p+N');');
- -- PRINT @q;
- EXECUTE sp_executesql @q;
- SET @i+=1;
- END
- -- Code clean-up
- DROP TABLE #partitions;
With this approach, the code in source control remains static and the partitioning boundary values are allowed to be dynamic; evolving with the SQL pool over time.
A. Creating an empty table named SalesHistory_Current with a duplicate schema as the SalesHistory table (action a) is a valid first step in preparing for data removal. Copying the data to a new table by using CREATE TABLE AS SELECT (action c) is not necessary and introduces unnecessary complexity. Switching the partition containing the stale data from SalesHistory to SalesHistory_Current (action e) should be done before truncating the partition containing the stale data (action d).
B. While copying the data to a new table by using CREATE TABLE AS SELECT (action c) may seem like a valid step, it does not directly address the requirement to remove old data. Executing a DELETE statement where the value in the Date column is more than 36 months ago (action f) is not the most efficient way to handle large data sets in Azure Synapse Analytics. Dropping the SalesHistory_Current table (action b) without proper data management is not recommended.
C. Copying the data to a new table by using CREATE TABLE AS SELECT (action c) is not necessary in this scenario as it creates an additional table without directly addressing the requirement to remove old data. Dropping the SalesHistory_Current table (action b) alone does not fulfill the requirement of removing data older than 36 months.
D. Creating an empty table named SalesHistory_Current with a duplicate schema as the SalesHistory table (action a) is the first step to prepare for data removal. Switching the partition containing the stale data from SalesHistory to SalesHistory_Current (action e) is the next logical step to ensure data integrity before deletion. Dropping the SalesHistory_Current table (action b) completes the process by removing the unnecessary duplicate table.
E. Switching the partition containing the stale data from SalesHistory to SalesHistory_Current (action e) before executing a DELETE statement (action f) is not the most efficient way to handle data removal in Azure Synapse Analytics. Executing a DELETE statement can be resource-intensive and may not be the best approach for large data sets. Copying the data to a new table by using CREATE TABLE AS SELECT (action c) is not necessary for the requirement of removing old data.
Discussion
Think the marked answer is wrong, or have a better explanation? Share it below — comments appear after review.
