SQL Azure not recognizing my clustered Index - sql

I get the following error when I try to insert a row into a SQL Azure table.
Tables without a clustered index are not supported in this version of
SQL Server. Please create a clustered index and try again.
My problem is I do have a clustered index on that table. I used SQL Azure MW to generate the Azure SQL Script.
Here's what I'm using:
IF EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[tblPasswordReset]') AND type in (N'U'))
DROP TABLE [dbo].[tblPasswordReset]
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[tblPasswordReset]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[tblPasswordReset](
[PasswordResetID] [int] IDENTITY(1,1) NOT NULL,
[PasswordResetGUID] [uniqueidentifier] NULL,
[MemberID] [int] NULL,
[RequestDate] [datetime] NULL,
CONSTRAINT [PK_tblPasswordReset] PRIMARY KEY CLUSTERED
(
[PasswordResetID] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)
END
GO
Why doesn't SQL Azure recognize my clustered Key? Is my script wrong?

Your script only creates the table if it did not exist yet. Perhaps there still is an old version of the table without a clustered index? You can check with:
select * from sys.indexes where object_id = object_id('tblPasswordReset')
If the table exists without the clustered index, you can add one like:
alter table tblPasswordReset add constraint
PK_tblPasswordReset primary key clustered
As far as I can see, your statement does conform to the Azure create table spec.

Be careful if you're using SSIS. I ran into this same problem, myself, but was using SSIS instead of manually inserting the data. By default SSIS will drop and recreate the table, so even though I had it properly defined with a clustered index, my SSIS script failed. On the "Edit Mappings" step in the SSIS wizard you can manually define the table creation script. I just deleted the table gen script there and my import worked.
(I'd leave this as a comment but my post count is too anemic)

Related

How to force Microsoft Database Project generate ALTER statement for primary key constraint instead of creating temp table?

I have following script for LoginLogo table:
CREATE TABLE [LoginLogo] (
[LoginLogoId] INT IDENTITY (1, 1) NOT NULL,
[LoginId] INT NOT NULL,
[LogoNm] NVARCHAR(255) NULL,
CONSTRAINT [PK_LoginLogo_LoginLogoId] PRIMARY KEY CLUSTERED ([LoginId] ASC),
CONSTRAINT [FK_LoginLogo_LoginId] FOREIGN KEY ([LoginId])
REFERENCES [Login] ([LoginId])
);
GO
CREATE NONCLUSTERED INDEX [IF_LoginLogo_LoginId]
ON [LoginLogo]([LoginId] ASC)
ON [INDX];
I need to change Primary Key Constraint, so I've just changed one line, please see below the change:
CONSTRAINT [PK_LoginLogo_LoginLogoId] PRIMARY KEY CLUSTERED ([LoginLogoId] ASC),
Database project perfectly build changed code, but when it generates database update statement it generates temp table instead of simple ALTER statement. See below generated script:
CREATE TABLE [tmp_ms_xx_LoginLogo] (
[LoginLogoId] INT IDENTITY (1, 1) NOT NULL,
[LoginId] INT NOT NULL,
[LogoNm] NVARCHAR (255) NULL,
CONSTRAINT [tmp_ms_xx_constraint_PK_LoginLogo_LoginLogoId1]
PRIMARY KEY CLUSTERED ([LoginLogoId] ASC)
);
IF EXISTS (SELECT TOP 1 1
FROM [apps].[LoginLogo])
BEGIN
SET IDENTITY_INSERT [apps].[tmp_ms_xx_LoginLogo] ON;
INSERT INTO [apps].[tmp_ms_xx_LoginLogo] ([LoginLogoId], [LoginId], [LogoNm])
SELECT [LoginLogoId],
[LoginId],
[LogoNm],
FROM [LoginLogo]
ORDER BY [LoginLogoId] ASC;
SET IDENTITY_INSERT [tmp_ms_xx_LoginLogo] OFF;
END
DROP TABLE [LoginLogo];
EXECUTE sp_rename N'[tmp_ms_xx_LoginLogo]', N'LoginLogo';
EXECUTE sp_rename N'[tmp_ms_xx_constraint_PK_LoginLogo_LoginLogoId1]',
N'PK_LoginLogo_LoginLogoId', N'OBJECT';
Is it possible to tell Database project to generate ALTER statement instead of creating temp table? How can I force Microsoft Database Project to do that?
Bearing in mind that if you change the clustered index of a table, the table will be rebuilt regardless of whether the script does ALTER TABLE or the SSDT-generated stuff with temp tables, the usual way to solve these problems is to do the ALTER ahead of time
Meaning, you need a script, often referred to as a pre-pre-deploy script (pre-deploy won't work, as it is run post-comparison) that makes the expensive change, so that when the comparison is run the change has already occurred, and hence doesn't get repeated by the dacpac deployment.
This script needs to be run as part of your deployment, before you do any of the sqlpackage stuff. You can specify the change as alter table in this script.
In this particular instance, where the table is going to be rebuilt either way, I can't see it making a great deal of difference to the overall deployment time.

Create a database schema-script in ssms

I have a fully functional database in sql server. Around 40 tables. I have to install this schema (only the schema, not the data) on multiple other sql server instances. SSMS offers a nice way to auto generate schemas using Tasks --> Generate Scripts. It kinda works, but I am not sure if I understand it correctly:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TableName]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[TableName](
[id] [uniqueidentifier] NOT NULL,
[history] [varchar](max) NOT NULL,
[isdeleted] [bit] NOT NULL,
CONSTRAINT [PK_RecGroupData] PRIMARY KEY CLUSTERED
(
[rid] 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]
END
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[DF_TableName_id]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_TableName_id] DEFAULT (newid()) FOR [id]
END
--Just showing one ALTER TABLE and IF NOT EXISTS. The others are generated in the same way.
What happens, if I execute the script, create a new script with the exact same content, but add a new column to it (--> id, history, isdeleted and timestamp)? Does it automatically add the new line? I think yes, of course, but I don't get, how it would know, if the column should be NOT NULL, VARCHAR, BIT, or something similar. It would just execute
ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_TableName_id] DEFAULT (newid()) FOR [id]
(id => new sample column)
But there isn't any information about the data type or any other modifiers.
Also, if I execute my script like this one a second time, it'll throw some errors:
Meldung 1781, Ebene 16, Status 1, Zeile 3
An die Spalte ist bereits ein DEFAULT-Wert gebunden.
Which translates to this:
Message 1781, level 16, status 1, line 3
A DEFAULT value is already bound to the column.
Why does this happen?
The error message is saying that there was a default value assigned to that column before.
Also:
ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_TableName_id] DEFAULT (newid()) FOR [id]
is not the syntax for adding new column - this is to add default value of NEWID() to the column [id].
To add a column you you should follow this steps (with an example inside).
Also how would the SQL Server know the setup settings for the new columns from your manually added lines? It would simply allow you to define them as you want and accept if the syntax is right or through an error if not during the script parse process (can be done by [ctrl] + [F5] in SSMS).

How can I change primary key on SQL Azure

I am going to change the primary key on SQL Azure. But it throws an error when using Microsoft SQL Server Management Studio to generate the scripts. Because every tables on SQL Azure must contains a primary key. And I can't drop it before create. What can I do if I must change it?
Script generated
IF EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[mytable]') AND name = N'PK_mytable')
ALTER TABLE [dbo].[mytable] DROP CONSTRAINT [PK_mytable]
GO
ALTER TABLE [dbo].[mytable] ADD CONSTRAINT [PK_mytable] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF)
GO
Error message
Msg 40054, Level 16, State 2, Line 3
Tables without a clustered index are not supported in this version of SQL Server. Please create a clustered index and try again.
Msg 3727, Level 16, State 0, Line 3
Could not drop constraint. See previous errors.
The statement has been terminated.
Msg 1779, Level 16, State 0, Line 3
Table 't_event_admin' already has a primary key defined on it.
Msg 1750, Level 16, State 0, Line 3
Could not create constraint. See previous errors.
I ran into this exact problem and contacted the Azure team on the forums. Basically it isn't possible. You'll need to create a new table and transfer the data to it.
What I did was create a transaction and within it do the following:
Renamed the old table to OLD_MyTable.
Create the new table with the correct Primary Key and call it MyTable.
Select the contents from OLD_MyTable
into MyTable.
Drop OLD_MyTable.
You may also need to call sp_rename on any constraints so they don't conflict.
See also: http://social.msdn.microsoft.com/Forums/en/ssdsgetstarted/thread/5cc4b302-fa42-4c62-956a-bbf79dbbd040
upgrade SQL V12 and heaps are supported on it. So you can drop the primary key and recreate it.
I appreciate that this may be late in the day for yourself, but it may help others.
I recently came across this issue and found the least painful solution was to download the database from Azure, restore it locally, update the primary key locally (as the key constraint is a SQL Azure specific issue), and then restore the database back into Azure.
This saved any issues in regards to renaming databases or transferring data between them.
You can try the following scripts. Change it to suit for your table def.
EXECUTE sp_rename N'[PK_MyTable]', N'[PK_MyTable_old]', 'OBJECT'
CREATE TABLE [dbo].[Temp_MyTable](
[id] [int] NOT NULL,
[text] [text] NOT NULL CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED (
[id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON))
INSERT INTO dbo.[Temp_MyTable] (Id, Text)
SELECT Id, Text FROM dbo.MyTable
drop table dbo.MyTable
EXECUTE sp_rename N'Temp_MyTable', N'MyTable', 'OBJECT'
This question is outdated because changing PK is already supported in latest version of SQL Azure. And you don't have to create temporary table.

Increasing performance on a logging table in SQL Server 2005

I have a "history" table where I log each request into a Web Handler on our web site. Here is the table definition:
/****** Object: Table [dbo].[HistoryRequest] Script Date: 10/09/2009 17:18:02 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[HistoryRequest](
[HistoryRequestID] [uniqueidentifier] NOT NULL,
[CampaignID] [int] NOT NULL,
[UrlReferrer] [nvarchar](512) NOT NULL,
[UserAgent] [nvarchar](512) NOT NULL,
[UserHostAddress] [nvarchar](15) NOT NULL,
[UserHostName] [nvarchar](512) NOT NULL,
[HttpBrowserCapabilities] [xml] NOT NULL,
[Created] [datetime] NOT NULL,
[CreatedBy] [nvarchar](100) NOT NULL,
[Updated] [datetime] NULL,
[UpdatedBy] [nvarchar](100) NULL,
CONSTRAINT [PK_HistoryRequest] PRIMARY KEY CLUSTERED
(
[HistoryRequestID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[HistoryRequest] WITH CHECK ADD CONSTRAINT [FK_HistoryRequest_Campaign] FOREIGN KEY([CampaignID])
REFERENCES [dbo].[Campaign] ([CampaignId])
GO
ALTER TABLE [dbo].[HistoryRequest] CHECK CONSTRAINT [FK_HistoryRequest_Campaign]
GO
37 seconds for 1050 rows on this statement:
SELECT *
FROM HistoryRequest AS hr
WHERE Created > '10/9/2009'
ORDER BY Created DESC
Does anyone have anysuggestions for speeding this up? I have a Clustered Index on the PK and a regular Index on the CREATED column. I tried a Unique Index and it barfed complaining there is a duplicate entry somewhere - which can be expected.
Any insights are welcome!
You are requesting all columns (*) over a non-covering index (created). On a large data set you are guaranteed to hit the Index Tipping Point where the clustered index scan is more efficient than an nonclustered index range seek and bookmark lookup.
Do you need * always? If yes, and if the typical access pattern is like this, then you must organize the table accordingly and make Created the leftmost clustered key.
If not, then consider changing your query to a coverable query, eg. select only HistoryRequestID and Created, which are covered by the non clustered index. If more fields are needed, add them as included columns to the non-clustered index, but take into account that this will add extra strorage space and IO log write time.
Hey, I've seen some odd behavior when pulling XML columns in large sets. Try putting your index on Created back, then specify the columns in your select statement; but omit the XML. See how that affects the return time for results.
For a log table, you probably don't need a uniqueidentifier column. You're not likely to query on it either, so it's not a good candidate for a clustered index. Your sample query is on "Created", yet there's no index on it. If you query frequently on ranges of "Created" values then it would be a good candidate for clustering even though it's not necessarily unique.
OTOH, the foreign key suggests frequent querying by Campaign, in which case having the clustering done by that column could make sense, and would also probably do a better job of scattering the inserted keys in the indexes - both the surrogate key and the timestamp would add records in sequential order, which is net more work over time for insertions because the node sectors are filled less randomly.
If it's just a log table, why does it have update audit columns? It would normally be write-only.
Rebuild indexes. Use WITH (NOLOCK) clause after the table names where appropriate, this probably applies if you want to run long(ish) running queries against table that are heavily used in a live environment (such as a log file). It basically means your query migth miss some of teh very latest records but you also aren't holding a lock open on the table - which creates additional overhead.

Creating a fulltext index on a view in SQL Server 2005

I am having troubles creating a fulltext index on a view in SQL Server 2005. Reviewing the documentation I have not found the problem. The error message I receive is: "'Id' is not a valid index to enforce a full-text search key. A full-text search key must be a unique, non-nullable, single-column index which is not offline, is not defined on a non-deterministic or imprecise nonpersisted computed column, and has maximum size of 900 bytes. Choose another index for the full-text key."
I have been able to verify every requirement in the errorstring except the "offline" requirement, where I don't really know what that means. I'm pretty darn sure its not offline though.
I have the script to create the target table, view, and index below. I do not really need a view in the sample below, it is simplified as I try to isolate the issue.
DROP VIEW [dbo].[ProductSearchView]
DROP TABLE [dbo].[Product2]
GO
SET NUMERIC_ROUNDABORT OFF;
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT,
QUOTED_IDENTIFIER, ANSI_NULLS ON;
GO
CREATE TABLE [dbo].[Product2](
[Id] [bigint] NOT NULL,
[Description] [nvarchar](max) NULL,
CONSTRAINT [PK_Product2] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE VIEW [dbo].[ProductSearchView] WITH SCHEMABINDING
AS
SELECT P.Id AS Id,
P.Description AS Field
FROM [dbo].Product2 AS P
GO
-- this index may be overkill given the PK is set...
CREATE UNIQUE CLUSTERED INDEX PK_ProductSearchView ON [dbo].[ProductSearchView](Id)
GO
-- This is the command that fails
CREATE FULLTEXT INDEX ON [dbo].[ProductSearchView](Id, Field)
KEY INDEX Id
ON FullText WITH CHANGE_TRACKING AUTO;
GO
You need to specify the name of the index instead of the column name when creating the fulltext index:
CREATE FULLTEXT INDEX ON [dbo].[ProductSearchView](Id, Field)
KEY INDEX PK_ProductSearchView
ON FullText WITH CHANGE_TRACKING AUTO;
GO
This will remedy the error you are getting, but it will give you another error because you are trying to include a non-character based column in your text search. You may want to choose another indexed character column to use in your full text catalog instead.