SSMS Could not load file or assembly msmgdsrv, Version=9.0.0.0

Hi everyone,

Today I an into an error using SSMS while clicking on the button check for an MDX query, the error message was:
Could not load file or assembly ‘msmgdsrv, Version=9.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91’ or one of its dependencies. The system cannot find the file specified. (MDXQueryGenerator)

After some investigations I found out that the path for the dll needs to be changed. To change the path open the file “%ProgramFiles%Microsoft SQL Server100ToolsBinnVSShellCommon7IDESsms.exe.config” with a text editor and find the line . Change the attribute of href to the actual dll, on my system it was C:Program FilesMicrosoft Analysis ServicesAS OLEDB10msmgdsrv.dll. Restart SSMS and then it works.

I hope this helps

Florian

Source: Microsoft.com

How to have aggregated results in a flat table

You have some nice data to display into a pivot table, but you can’t rank or format them so you are stuck ? Don’t worry!

We are currently working on the pivot table to include theses features (among others!), until then, here is a workaround using the flat table. And even more, you will learn new awesome stuff using the DataTransform feature.

For instance, let’s take a simple example with a table which has 2 columns : [Car Name] and [Quantity]. You want to display the sum of [Quantity] over [Car Name]. Basically in pure SQL it’s : sum(quantity) .. group by [Car Name] but this reduces the row count from 1000 to 5 for instance (if you have 5 cars), thus, this is not useable in DataTransform where it can just add/remove columns, ‘group by’ is not available.

What if we create a new column which is the sum of Quantity for each [Car Name] first ? Do you now the SQL “over” function ? This allows you to use aggregations that are computed for each row.

sum([Quantity]) over(partition by [Car Name])

Image

The computed column looks like :

Image

We can see that each value is repeated for each [Car Name]. (13, 6, and 8).

This is not yet useful in a flat table because of those repeated values. Let’s find a way to take only the first one. Because you can’t just remove rows in datatransform, we need to find a way to remove them using a filter on the dashboard instead.

Let’s create a new column that will help us to identify the first one for each group. To do that, we use generate a simple auto-incremented value (1, 2, .. ) and we will be able to just take the sum(Quantity) where this column equals 1 (each group will have its own sequence from 1 to n).

row_number() over(partition by [Car Name] order by [Car Name])

Image

The preview looks like :

Image

We can distinguish 5 groups : Alfa Romeo, AMC Hornet, Aston Martin, Bentley, BMW, and for each rownumber = 1, the sum of quantity : 13, 6, 8, 11, 8 (the sum is computed on the preview values only, not on the overall. It will be when you will process the transform). Thus, we can create our flat table from that and use ranking, filtering, format and so on.

Image

Image

Et voilà ! Happy Dashboarding !

SSAS CellPermission error on Excel or SSMS

Hi

Today I ran into some issue while connecting to a SSAS cube using Excel, some of the measure where showing #Value! instead of the actual value.
After some investigation I found the message “#Error CellPermission (1, 1) The member ‘[CubeName]’ was not found in the cube when the string, [Measures].[MeasureName], was parsed.

When I browsed the cube using SSMS and the same user’s role I could see the message as well so I checked the security role and found the issue.

In your policy all Measure are accessible to this role so I edited the role (double click on it) then go to the “Cell Data” page

Role

Enable the read and the read-contingent permissions for the role and select the Measures (in this case all of the Measures)

Cube Role

I hope this helps.

Florian

Working with XML columns in SQL Server, a first approach

Need to work with xml column in SQL Server, and you don’t have a clue what’s XQuery is ?

Well, that was my situation, here’s some basic things you could use if you need to.

XQuery is a query and functional programming language that is designed to query and transform collections of structured and unstructured data, usually in the form of XML, text and with vendor specific extensions other data formats (JSON, binaries, …). (http://en.wikipedia.org/wiki/XQuery)

That said, let’s see what we can do with that in SQL Server. I’ll just present you the different functions available to work with.


query() : works against an xml column, returns xml

SELECT Properties.query('/Properties/Data')
FROM [Table] where ID = 2584

If you have a same node in different hierarchies (for instance Data in /Properties and in /Metadata), you can leave a blank between 2 slashes :

SELECT Properties.query('//Data')
FROM [Table]

query() : http://msdn.microsoft.com/fr-fr/library/ms191474.aspx


exist() : similar to the WHERE statement, but in a xml

Retrieve node /Properties/Data for all records :

... WHERE Properties.exist('/Properties/Data') = 1
... WHERE Properties.exist('/Properties[Data]') = 1 -- equivalent

To get only the nodes whose value is a given one (3214) :

... WHERE Properties.exist('/Properties/Data/Column[(ID=3214)]') = 1

To test the value of an attribute, for instance, here, the “xsi:type” :

<Data xsi:type="Pie">
<Data xsi:type="XY">

Use the prefix “@” in front of the attribute name :

... WHERE Properties.exist('/Properties/Data[@xsi:type="Pie"]') = 1

exist(): http://msdn.microsoft.com/fr-fr/library/ms189869.aspx


value() : select a value in your xml and returns a value cast into the datatype you want.

This function takes 2 params :

– xquery : an xquery that returns only one value, for that, use the syntax “(/path/value)[1]” otherwise you will end up with the error “‘value()’ requires a singleton (or empty sequence), found operand of type ‘xdt:untypedAtomic *'”

– the type you want to return, between quotes (internally, it uses CONVERT)

SELECT Properties.value('(/Properties)[1]', 'nvarchar(20)') ...
SELECT Properties.value('(/Properties/Column/ID)[1]', 'int') ...

value(): http://msdn.microsoft.com/fr-fr/library/ms178030.aspx


modify() : update an xml column.

It takes a string in param, that is not xquery, but XML DML (XML Data Modification Language).

This language is an extension of xquery adding some keywords such as ‘insert’ ‘delete’ ‘replace value of’, used to manipulate the xml.


modify : delete

To remove all <Useless>…<Useless> from its parent node :

update [Table]
set Properties.modify('delete /Properties/Useless')

If you want to remove the second occurence, use :

update [Table]
set Properties.modify('delete (/Properties/Useless)[2]')

Even if there is no match, SQL Server returns : (1337 row(s) affected)

To delete an attribute :

update [Table]
set Properties.modify('delete (/Properties/Useless/@myattr)[1]')
-- to delete all attributes :
set Properties.modify('delete (/Properties/Useless/@*)')

To delete all inner nodes :

update [Table]
set Properties.modify('delete (/Properties/Useless/*)')

To delete severals nodes in the same query :

update [Table]
set Properties.modify('delete ( /Properties/Useless/, /Properties/YouToo, /Properties/AndYou )')

modify : insert

To add it back (just one) :

update [Table]
set Properties.modify('insert &lt;Useless&gt;&lt;/Useless&gt; into (/Properties)[1]')

‘into’ could be prefixed by ‘as first’ or ‘as last’ according to where you want to add it into the child. (‘as last into’)
But you can insert your node, not inside the target, but after or before it : use ‘after or ‘before’ instead of ‘into’.
In short : {as first | as last} into | after | before

Again, you have to specify something that is a single node using (..)[1] otherwise you’ll get :
The target of ‘insert’ must be a single node, found ‘element(Properties,xdt:untyped) *’

If you want to insert a value into a node, you have to use the text{} function :

-- &lt;Score /&gt;
update [Table]
set Properties.modify('insert text{&quot;42&quot;} into (/Properties/Score)[1]')
-- &lt;Score&gt;42&lt;/Score&gt;

To add an attribute to a node, use ‘insert attribute {}’ :

-- &lt;Score /&gt;
update [Table]
set Properties.modify('insert attribute gameover {&quot;true&quot;} into (/Properties/Score)[1]')
-- &lt;Score gameover=&quot;true&quot; /&gt;

To change its value :

-- &lt;Score /&gt;
update [Table]
set Properties.modify('replace value of (/Properties/Time/@test)[1] with &quot;&quot;')
-- &lt;Score /&gt;

modify : replace value of … with …

This function takes 2 params, the first is the path where to replace, the second is the value, it makes sense.

The first param needs a single node (“(/…)[n]”) otherwise : The target of ‘replace’ must be at most one node, found ‘element(Useless,xdt:untyped) *’

The second param should be just a string. If you try some metadata like with <score></score>, you’ll get an error : The target of ‘replace value of’ must be a non-metadata attribute or an element with simple typed content, found ‘element(,xdt:untyped) ?’

-- &lt;Score&gt;573&lt;/Score&gt;
update [Table]
set Properties.modify('replace value of (/Properties/Score/text())[1] with &quot;42.0&quot;') 
-- &lt;Score&gt;42&lt;/Score&gt;

This will work if your node already has a value, otherwise, it won’t do a thing (for instance if you have <Score />).

For this case, use the insert text{} :

-- &lt;Score /&gt;
update [Table]
set Properties.modify('insert text{&quot;42&quot;} into (/Properties/Score)[1]')
-- &lt;Score&gt;42&lt;/Score&gt;

If you want to clear a node value, use “with “”)

-- &lt;Score&gt;42&lt;/Score&gt;
update [Table]
set Properties.modify('replace value of (/Properties/Score/text())[1] with &quot;&quot;') 
-- &lt;Score /&gt;

Now, let’s introduce more complex cases that uses functions or references others parts of the same xml.


Reference other part of the XML

Insert nodes which values are from another part of the xml :

-- &lt;Target /&gt;
set Properties.modify('insert /Properties/Source into (/Properties/Target)[1]') 
-- &lt;Target&gt;&lt;Source&gt;google&lt;/Source&gt;&lt;Target&gt;

You can see that the whole node had been put into the target. If you want the value only :

-- &lt;Target /&gt;
... set Properties.modify('insert /Properties/Source/text() into (/Properties/Target)[1]') 
-- &lt;Target&gt;google&lt;Target&gt;

You can count how many nodes match a xquery :

-- &lt;Target /&gt;
... set Properties.modify('insert text{ count(/Properties/Data/*) } into (/Properties/Target)[1]') 
-- &lt;Target&gt;7&lt;Target&gt;

Reference the record columns

You have a “Width” column in your table, you want to put it into the xml :

-- &lt;Target /&gt;
... set Properties.modify('insert ( &lt;Width&gt;{ sql:column(&quot;Width&quot;) } &lt;/Width&gt; ) into (/Properties/Target)[1]') 
-- &lt;Target&gt;&lt;Width&gt;573&lt;/Width&gt;&lt;Target&gt;

Moreover, there are functions available to modify your strings, for instance the well known ‘substring’. Let’s combine that with the text{} function to add a value (not a node) to our target.

-- &lt;Target /&gt;
... set Properties.modify('insert text{substring(sql:column(&quot;Name&quot;),1,3)} into (/Properties/Target)[1]') 
-- &lt;Target&gt;Joh&lt;Target&gt;

If statement

Finally, know that you can do small function directly inside your xml dml such as :

-- &lt;Target /&gt;
... set Properties.modify('insert(
if (count(/Properties/Data/*) &gt; 3)
then
	attribute complex {&quot;true&quot;}
else
	attribute complex {&quot;false&quot;}, 
	attribute type {upper-case(sql:column(&quot;Name&quot;))},
	text {/Properties/Title/text()}
) into (/Properties/Target)[1]') 
-- &lt;Target complex=&quot;false&quot; type=&quot;JOHN&quot;&gt;my title&lt;Target&gt;

FLWOR

What is that ? Well, it stands for : for, let, where, order by, and return.

For instance, if you want to query your xml and returns xml from it :

SELECT Properties.query('
	for $data in /Accounts/*
	return
		&lt;User&gt;
			&lt;ID&gt;{ data($data/Guid) }&lt;/ID&gt;
			&lt;Fullname&gt;{ data($data/Firstname), data($data/Lastname) }&lt;/Fullname&gt;
		&lt;/User&gt;
')
FROM [Table]

Severals things in this code :
– creates … for every nodes in /Accounts
– creates 3434 for each , based on the Guid node text : data(node) is equivalent to node/text()
– creates John Doe from the concatenation of the firstname ans lastname nodes text.

There is a ‘where’ clause, and an ‘order by’ too.

FLWOR Statement and Iteration : http://msdn.microsoft.com/en-us/library/ms190945.aspx


Now that you know the basics, read the documentation, there is no better place to know more. 😉

modify: http://msdn.microsoft.com/fr-fr/library/ms187093.aspx
XML Data Modification Language (XML DML) : http://msdn.microsoft.com/fr-fr/library/ms177454.aspx
insert: http://msdn.microsoft.com/fr-fr/library/ms175466.aspx
delete: http://msdn.microsoft.com/fr-fr/library/ms190254.aspx
replace value of: http://msdn.microsoft.com/fr-fr/library/ms190675.aspx


XQuery basics : http://msdn.microsoft.com/fr-fr/library/ms190262.aspx

Available functions to work against xml column : http://msdn.microsoft.com/fr-fr/library/ms189254.aspx
Functions on String Values (length, concat, convert, contains, substring..): http://msdn.microsoft.com/fr-fr/library/ms178064.aspx

Improving queries performances using Indexes on SQL Azure/Sql Server

When considering the creation of index we have to consider many parameters:

  1. How many column do I have to include in the index
  2. How to improve the disk space usage
  3. How to get the best query results

Sql server allows you to create indexes on multiple columns but also have the “Index with Included Columns” the two approaches are slightly different.

I tested the two possibilities on SQL Azure and check the performances

Let’s consider the following scenario:

  1. Person table with 10,000,000 rows (data randomly created but identical for all tests)
  2. The queries are based on the first and last name column and retrieves other columns values

For the testing I used the following query, which returns 26 rows out of the 10,000,000

SELECT DOB, Street,City, PostCode
FROM [TableName]
WHERE FirstName='Garrett' AND (LastName='Gilbert' OR LastName='Trujillo')

Looking at the query we see that the column FirstName and LastName must be part of the index as they are used as “keys”. The problem is how to retrieve the DOB, Street, City and PostCode as fast as possible.

I tested the following cases:

  1. No Index, used for reference
  2. Index on First and Last name
     CREATE NONCLUSTERED INDEX SimpleIndex
    ON dbo.TableName(FirstName,LastName)
  3. Index on all columns
     CREATE NONCLUSTERED INDEX IndexOnAllColumn
    ON dbo.TableName(FirstName,LastName,DOB, [Street], [City], [PostCode])
  4. Index on the First and Last name including the columns selected in the query
     CREATE NONCLUSTERED INDEX IndexWithColumn
    ON dbo.TableName(FirstName,LastName)
    INCLUDE (DOB, [Street], [City], [PostCode])

Running the queries for each case I obtained the following result

Test Table Size KB Index Size KB Query Time (ns)
Without Index 1996112 4633000
With Index 2417112 397120 16000
Index on all columns 2813968 817728 3000
Index with Include 2809368 813080 2000

As we can see the best result is obtained using the index with the include key word.

The space used is also smaller compared to the test case 3. It is understandable that the test case 3 will also be much slower when inserting/updating that as all columns are indexed.

You could also consider the column store method described on this post however the table presented contains a column with a uniqueidentifier type so it could not be used in this case.

You can find more information about the Indexes with Included Columns on Micorsoft’s website

Hope this helps

Florian

Paging with SQL Server 2012 and SQL Azure

With earlier version of SQL Server (up to 2008) to accomplish paging we were using the ROW_NUMBER.
E.g. when retrieving data from a table called Person

WITH Result AS(
SELECT Id,NameFirst,NameLast,
ROW_NUMBER() OVER (ORDER BY NameFirst DESC) AS R_Number
FROM dbo.Person)
SELECT Id,NameFirst,NameLast
FROM Result
WHERE R_Number > 10 AND R_Number <= 20

Since SQL Server 2012 we can use the keywords OFFSET and FETCH where OFFSET is the number of row to skip and FETCH the number of row to take
E.g. when retrieving from the same table

SELECT Id,NameFirst,NameLast
FROM dbo.Person
ORDER BY NameFirst DESC
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY

Hope this helps

Overcoming timeouts on SQL Azure tables with large amounts of data

If you have timeoed out (after 20 minutes or so) or If you ever received one an error when modifying a table that contains a large amount of data in SQL Azure then the following could be useful to you.

Sometime ago we were trying to create an index on a table that contained 80 million rows (give or take) and invariably our session would time out with errors such as:

The session has been terminated because of excessive transaction log space usage. Try modifying fewer rows in a single transaction.

The default in SSMS when generating scripts adds a ONLINE=OFF to the script so make we changed it to

CREATE NONCLUSTERED INDEX [IDX_MyIndex] ON [dbo].[TableName]
(
   [ColumnName] ASC
)WITH (ONLINE=ON) ON [PRIMARY]

And this time although it took 47 minutes it did the trick.  So I set out to read a bit more about it and found some intersting articles on the performance such as this one by  and this one by .

Although you take a higher hit on the performance its the best way to do quick (but sometimes much needed changes) on the fly.

Hope this helps someone…

How ColumnStore Indexes can help you improve your datawarehouse?

Hi everyone,

As you may have seen, SQL Server 2012 introduce a lot of new functionality and one of them is called CSI (ColumnStore Indexes)

What is it?

CSI is a brand new index type that can be used on a table within SQL Server.

This feature has been developed for BI, where the common needs are to aggregate large amount of data as fast as possible.

With this feature, CSI can become a good competitor to SSAS.

How does that work?

The Column Store Indexes are using Vertipaq Technology, shared with SSAS and PowerPivot.

I won’t explain how clustered indexes and non-clustered indexes work.

But I will explain how ColumnStore Indexes differs from those other two, name Row Store Indexes.

CSI

As we can see in this picture, traditional row store indexes are storing collections of rows into the pages, and CSI is storing collections of column values into pages.

Ok, but how this can help improve my queries performances?

This is mainly due to those points:

–          SQL Server will only retrieve necessary columns from Disk. It won’t retrieve values that he knows he don’t need, thus reducing IO.

–          CSI is using a compression algorithm that will eliminate redundancy, because a column has huge chances of having repeated data.

–          CSI caches in memory frequently asked columns, reducing even better the IO

Moreover, CSI has the benefits of being able to use Batch Mode or Row Mode.

CSI will can choose whether to use Batch mode or Row mode.

Note, that Batch mode is only available for CSI today.

Are there any limitations?

Before thinking of using CSI, you need to understand that this technology (today) can only be used on a read only table. If you need to update your table either DDL or data, you’ll need to drop the index, and recreate it after.

Moreover, CSI cannot be used with a table that contains certain types of data.

  • Binary / varbinary
  • ntext / text / image
  • varchar(max) / nvarchar(max)
  • uniqueidentifier
  • rowversion / timestamp
  • sql_variant
  • decimal / numeric (except with a precision greater than 18 digits)
  • datetimeoffset with a scale greater than 2
  • CLR Types (hierarchyid & spatial types)
  • Xml

Most of those types have in common the fact that they aren’t finite. CSI works with finite types.

Once you have only needed types, here are other limitations:

  • It can’t have more than 1024 columns
  • A table can only have 1 ColumnStore Index (it will generally have all the usefull columns)
  • Only nonclustered indexes available in CSI
  • Cannot be unique
  • Cannot be created on a view or indexed view
  • Cannot include a sparse column
  • Cannot act as a primary key or a foreign key
  • Cannot be changed using Alter Index statement (need to drop and recreate)
  • Cannot be created with the include keyword
  • Sorting is not allowed (no ASC / DESC when creating the index)
  • Does not use or keep statistics in the manner of a traditional index.
  • Cannot contain a column with FileStream attribute

How can I implement it?

To implement CSI, this is really easy. You just need to create the index and everything will be done for you.

The queries that used to run with row store indexes will continue to work correctly, nothing will need to be changed. Isn’t that great?

Moreover, if you want to query your table in a traditional way, you can say the query engine to ignore ColumnStore and perform a query the old way.

Here is how we define the index:

CREATE NONCLUSTERED COLUMNSTORE INDEX <ColumnStoreIndexName> ON <Table> (col1, col2, col3);

Benchmark ?

Here is a little benchmark I’ve made off a typical Fact table that contains 10 Million randomly generated rows like:

benchmark1

Because of the random nature, I have a lot of distinct Country / City (which are not linked to each other). Thus, getting the sum of the quantity for all countries / cities take:

benchmark2
Without CSI

benchmark3

With CSI

Hell yes, 13 seconds instead of 27 and 6826 logical reads instead of 232549 …

And from the CSI table without using the index:

benchmark4

We do retrieve our 27 seconds of processing and a huge amount of logical reads.

Conclusion

We’ve seen how great this feature is, and how restricted is usage are.

In one sentence, if you are storing data into table that are update very rarely and are doing Intense BI on those tables, CSI what you were looking for!

Otherwise, if you are updating those tables frequently, CSI might not be what you are looking for, since you’ll need to drop and recreate indexes very often.

Hope this helps

Gaël

Copy table content between SQL Servers

To copy the content of a table using INSERT sql statements from a server to another, in SQL Server Management Studio, you can do this using just some clicks. (_don’t_ copy/paste using ctrl+c/v from the select * view, you could lose data in your fields)

First, you right click on the database your original table belongs to (well, they could have done a shortcut directly on the table !) :

generatescripts

Then you select the table you want to copy the content (tables, stored procedures, data types..) from :

fromtables

From here, you can save the script into a file, in several parts, clipboard or query window.. as you want. The important thing to do is to go to the advanced options :

advanced

Here, you can change if you want to only generate a script containing the schema of the table and/or its content. By defaut, only the schema sql will be generated.

advanced2

A few Next and here it is, you have your script.

By default, it enables the identity insertion because the INSERT contains the identity column.

SET IDENTITY_INSERT [dbo].[Sample] ON
GO

and disables it back at the end of the INSERTs

SET IDENTITY_INSERT [dbo].[Sample] OFF
GO

Have fun with it !

How to deal with relationships between tables using Entity Framework : Include()

Let’s assume we have :

  • a User table
  • a Message table with a nullable link to the User table

Today I saw this code to get all the messages and the related user :

Dim foo = (From m In tDatabase.Messages
 Group Join u In tDatabase.Users On u.Id Equals m.UserId
 Into UserList = Group From u In UserList.DefaultIfEmpty()
 Order By m.CreatedDate Descending)

Then, in your code, for foo.First() you have access to

  • .m : the message
  • .u : the user

It seems a little over complicated for what it does right ? If you don’t have the DB relationship between the message and the user, it could be an option, but here, we have it (and I don’t see why anybody wouldn’t).

So I fixed this doing just :

Dim foo = (From m In tDatabase.Messages.Include("User")
Order By m.CreatedDate Descending)

EF has no issue dealing with the nullable foreign key and in my code, for foo.First(), I have now access to all the message property (on the root so, no more .m), and for the info of the user of the message, I just use the .User property of the message. It makes sense, right ?

For the info, the SQL generated code (globally, it’s only a LEFT OUTER JOIN) is the same (at 99%, some order by takes place) in both cases.

Let’s go further with the Include function.

If you want to access the Company of the user now (imagine we have a Company table, and a CompanyId in the User table), then you have 2 level of relationship, no a problem, you can do :

From m In tDatabase.Messages.Include("User.Company")

You can Include() as much as relationships as you want. And here, no need to .Include(“User”) because when you do .Include(“User.Company”), EF internally adds the .Include(“User”) (makes sense, you need the User relation to go deeper to the Company).

The worst part in the Include function, is that it takes string as param. So, when you rename your tables, don’t forget to check thoses Includes.

ClicData Blog Icons