Result set differences in a SQL Server Compact database PC vs Mobile device - sql

Interesting problem: I have a SQL Server CE 3.5 database with some data in it. I run a query on the database, using a mobile device and obtain a result set.
This works fine 99% of the time, but on occasion I get records in the database where the query returns an empty result set.
If I take a copy of the same database file from my mobile device and connect to it with Query analyzer, then run the exact same query (as copied/pasted from the debugger), the query returns records. The query itself does a JOIN and GROUP BY on two tables by a referential identity key field.
Now if I make a clone the same records involved via a series of:
INSERT INTO MyTable (EntireFieldListExceptForIDKey)
SELECT
(EntireFieldListExceptForIDKey)
FROM
MyTable
WHERE
IDKey = Original
The query is now able to correctly assemble a result set on the cloned records on the mobile device.
Can anyone explain this, and possibly how to detect/overcome?

This is most likely due to a corrupt index, as both copying the file to your desktop and creating a new table will cause an Index rebuild.
It is recommended to regularly Compact your database to prevent this - also make sure you are using the latest runtime binaries.

Related

Azure SQL "select" query not showing all rows

I just used the SQLAzureMW (SQL Azure Migration Wizard Tool) to migrate my SQL Server database to Azure SQL. It went off without a hitch - all my tables are there, the website is running fine off it, etc.
Here's what's odd: if I execute a simple SELECT statement against my tables, I get only a few of the rows. I assumed they were missing, but my website is using some of those records as if they're there. So I queried with a WHERE clause and BAM - they showed up. How the... what the... why isn't my select showing me everything? This applies to many of the tables I've tested.
SQL Azure
On-Premise
I gave up on MS SQL Management Studio and am instead using SQL Server Object Explorer from Visual Studio 2012/2013. It functions properly and allows inline editing of data.
Consider this SELECT statement:
SELECT
SvcTimeID,
LoginName,
MeanSeconds,
MedianSeconds,
RequestCount,
StdDevSeconds,
SvcDate,
CAST (TS AS INT) AS TS
FROM dbo.SvcTime
WHERE SvcDate >= #SvcDate
Where the parameter is set:
cmd.Parameters["#SvcDate"].Value = DateTime.UtcNow - new TimeSpan(31, 0, 0, 0);
Execute that statement in an Azure Web Role - brought back, say 24 rows.
Now, insert two new rows; wait at least one minute; execute the statement again. Do the recently inserted rows appear? In my case, they did not. Note: the default value of SvcDate in the database is getutcdate().
Move the SQL Azure database from the web edition to the standard (S2) edition. Rows magically appear.
Here is my theory. The issue you had was not with MS SQL Management Studio but with SQL Azure itself where, under certain circumstances, the same query will return the original rows from a cache someplace and will miss the new rows in the database.
This has blown any remaining confidence I had with Azure.
I was scared at first, but I think this has an explanation:
If you inserted some rows in connection "A" and can't find them in other sessions, maybe you have a uncommited transaction. By default, in SQL Server on premise, your second connections would hung until transaction is commited or rolled back. (Isolation level read committed)
Somehow, using the same isolation level, Azure acts differently. I seems to work in some cases as a snapshot isolation. Because of that, you can read from the table, but results are not updated. Or maybe the lock are set in a different way.
To solve this, check sysprocesses for sessions with open_tran > 0 or just be careful commmiting trans. In the example, running commit in your session "A" should do it.
Good luck!

System.OutOfMemoryException when querying large SQL table

I've written a SQL query that looks like this:
SELECT * FROM MY_TABLE WHERE ID=123456789;
When I run it in the Query Analyzer in SQL Server Management Studio, the query never returns; instead, after about ten minutes, I get the following error: System.OutOfMemoryException
My server is Microsoft SQL Server (not sure what version).
SELECT * FROM MY_TABLE; -- return 44258086
SELECT * FROM MY_TABLE WHERE ID=123456789; -- return 5
The table has over forty million rows! However, I need to fetch five specific rows!
How can I work around this frustrating error?
Edit: The server suddenly started working fine for no discernable reason, but I'll leave this question open for anyone who wants to suggest troubleshooting steps for anyone else with this problem.
According to http://support.microsoft.com/kb/2874903:
This issue occurs because SSMS has insufficient memory to allocate for
large results.
Note SSMS is a 32-bit process. Therefore, it is limited to 2 GB of
memory.
The article suggests trying one of the following:
Output the results as text
Output the results to a file
Use sqlcmd
You may also want to check the server to see if it's in need of a service restart--perhaps it has gobbled up all the available memory?
Another suggestion would be to select a smaller subset of columns (if the table has many columns or includes large blob columns).
If you need specific data use an appropriate WHERE clause. Add more details if you are stuck with this.
Alternatively write a small application which operates using a cursor and does not try to load it completely into memory.

I'd like to merge data sets using an SQL query from different servers (one Sybase the other MS)

Is that possible? I'm using Aquadesk and I can't get it to work. The tables have a matching unique identifier and wondering if I can match them up in some way.
What you need - as I think - are "Federated Servers" (Databases) (you can look this up)
The basic idea behind that is, the you can create (catalog) a table in you local Database that is already residing on an other Database (or Server, or even an other DB System, but that depends in you SQL system and version) -> that is defintely a question for your DBAS
You get a table like 'MYSQL'.'PERSONS' that resides remotely (eg. 'BASE','PERSDATA'), so you can use them in a
`SELECT *
from 'LOCALNAME'.'USERS usr
JOIN 'MYSQL'.'PERSONS' pers
on usr.user_id=pers.id`
So jou can select and join over different Databases (and Servers)
I only used that whith IBM/UDB but it works realy fine, and has a fair performance (altough heavily depending on your statement)

Querying a SQL Server CE database offline using JOINs when using Microsoft Sync framework

I am getting this error when running my application, built using the sync framework, OFFLINE
The ntext and image data types cannot be used in WHERE, HAVING, GROUP
BY, ON, or IN clauses, except when these data types are used with the
LIKE or IS NULL predicates.
I have a database holding some tests, TestOptions. Another holding test collections called CreateScript. These tables are used to populate a list view with tests to be carried out.
Using the Sync framework these tables have been cloned locally as SQL Server CE tables.
The user selects the desired test and the result is stored in the results table.
When populating the list view a query is run using two joins incorporating all three of these tables to gather the data for tests.
select
TestType, TestName, LowerLimits, UpperLimits
from
CreateScriptTable
inner join
TestOptionsTable on CreateScriptTable.TestType = TestOptionsTable.TestName
LEFT JOIN
TestResultsTable on CreateScriptTable.TestType = TestResultsTable.TestName
WHERE
CreateScriptTable.InstrumentType= 'type1'
ORDER BY
[Index] ASC
This query works fine when the application is online. When the application is offline I get the exception above about the nText and image datatypes.
I also get the exception,
Large objects (ntext and image) cannot be used in ORDER BY clauses.
when running a similar query to the one above.
In my database there are no column with these datatypes. From reading around it seems that the varbinary(MAX) and nvarchar(MAX) datatypes are cast to image and nText respectively on the local SQL Server CE database. To fix this I changed the datatypes to nvarchar(4000) and varbinary(4000) but the problem still persists.
There is a hot fix available here but it pre-dates the version SQL Server CE that is on my machine. I have not tested it yet as I am wary of messing up my development environment and am very close to needing a full build to demo.
I also toyed with the idea of creating in memory DataTables for each table and querying those but this has not worked out either.
At the moment I am out of ideas and would really appreciate any help.
Use
ORDER BY CAST ([Index] as nvarchar(4000))

How do I create and synchronize a combined reporting-only db from two live dbs?

I need to quickly implement a read-only database containing data pulled from two identically structured live databases.
The live dbs are actually company dbs from a Dynamics accounting system so I'm happy for any Dynamics specific advice but this is mostly a SQL question. It's a fairly old version of Dynamics from before Great Plains was acquired by Microsoft. This is on SQL Server 2000.
We have reports and applications which access the Dynamics data. These apps are designed to look at one company db. Now we need to add another. It's appropriate that most of these reports and apps see combined data. They don't really care which company an order or invoice exists in. They only look at a small number of the tables.
It seems to me that the simplest solution is to create a reports only db with combined data. Preferably, we need an efficient way to update this db with changes several times a day.
I'm a developer, not a db expert but here's my plan:
Create the combined reporting db with the required tables initially with the same table structure as the live dbs.
All Dynamics tables seem to have an int identity column called DEX_ROW_ID. I'm not sure what it's used for, (it's not indexed) but that seems like the obvious generic way to uniquely identify rows. On the reporting db I will change it to a normal int (not an identity). I will create a unique index on DEX_ROW_ID in all dbs.
Dynamics does not have timestamps so I will add a timestamp column to tables in the live dbs and a corresponding binary(8) column in the reporting db. I'm assuming and hoping that Dynamics won't be upset by the additional index and column.
Add an int CompanyId column to the reporting db tables and add it to the end of any unique indexes. Most data will be naturally unique even without that. ie, order and invoice numbers etc will be different for the two live dbs. We may need to make some minor changes to the applications but I'm not expecting to do much other than point them to the new reporting db.
Assuming my reporting db is called Reports, the live dbs are Live1 and Live2, the timestamp column is called TS and all dbs are on the same server ... here's my first attempt at an update script for copying the changes in one table called MyTable in Live1 to the reporting db.
USE Reports
CREATE TABLE #Changes
(
ReportId int,
LiveId int
)
/* Collect in a temp table the ids or rows which have been deleted or changed
in the live db L.DEX_ROW_ID will be null if the row has been deleted */
INSERT INTO #Changes
SELECT R.DEX_ROW_ID, L.DEX_ROW_ID
FROM MyTable R LEFT OUTER JOIN Live1.dbo.MyTable L ON L.DEX_ROW_ID = R.DEX_ROW_ID
WHERE R.CompanyId = 1 AND L.DEX_ROW_ID IS NULL OR L.TS <> R.TS
/* Delete rows that have been deleted or changed on the live db
I wonder if using join syntax would run better than the subquery. */
DELETE FROM MyTable
WHERE CompanyId = 1 AND DEX_ROW_ID IN (SELECT ReportId FROM #Changes)
/* Recopy rows that have changed in the live db */
INSERT INTO MyTable
SELECT 1 AS CompanyId, * FROM Live1.dbo.MyTable L
WHERE L.DEX_ROW_ID IN (SELECT ReportId FROM #Changes WHERE LiveId IS NOT NULL)
/* Copy the rows that are new in the live db */
INSERT INTO MyTable
SELECT 1 AS CompanyId, * FROM Live1.dbo.MyTable
WHERE DEX_ROW_ID > (SELECT MAX(DEX_ROW_ID) FROM MyTable WHERE CompanyId = 1)
Then do the same for the Live2 db. Repeat for every table in Reports. I know I should use a parameter #CompanyId instead of the literal but I can't do that for the live db name some I might generate these dynamically with a C# program or something.
I'm looking for any advice, suggestions or critique on what I'm doing here. I know it won't be atomic. Things could be happening on the live db while this script runs. I think we can live with that. We'll probably do a full copy either nightly or weekly when nothing is happening on the live dbs.
We need to favor performance over elegance or perfection. Some initial testing has the first query with the TS comparisons running at about 30 seconds for the biggest table so I'm optimistic that this is going to work but I'd also like to know if I'm missing something obvious or not seeing the forest for the trees.
We don't really want to deal with log files on the reporting db. Can we just set that to simple recovery model and forget about logs?
Thanks
I think there are a couple open questions here.
Do you need these reports to be near-real-time? Or is this this sort of reporting that could live with daily updates? But assume you need up-to-the-minute data.
Have you considered querying the databases directly and merging the data per-report on the fly? You'll have to do a lot of reporting to duplicate the effort that's going to go into designing, creating, and supporting a real-time merged replicated database.
Thirty seconds is (IMHO) unacceptable for any single query against a production database. There could be any number of tuning-related reasons for taking this long, but it at least means you're going to need serious professional SQL Server optimization resources (i.e. people). And if this is a problem for the queries for reports, it doesn't bode well for the queries to maintain a separate database for reporting.
Tuck into the back of your mind the consideration that, if you need to consolidate to a single database, it's worth considering whether you should make it an OLAP database rather than a mirror. The mirror will be quicker and easier, but the OLAP would be far more flexible and powerful in the long term; and it might be well to go the whole way from the beginning.
The last thing I'd want to do is write a custom update script. Try these bulletproof methods first:
Let's hope your production databases are backed up. Restore those backups every night to the reporting server. You can automate restores with the RESTORE command, which will work with a file on a network server.
Use SQL Server replication to push data from the live servers to the backend.
Schedule a DTS package every night to import the entire production database.
This might seem like brute force. But since you're copying a 2000-era database, brute force cannot be a problem with today's hardware. As an added advantage, these methods can be supported by a sysadmin instead of a developer.
Method 1 has the added added advantage of serving as backup verification. :)