Needed this today. I remember seeing someone at a SQLSaturday (which for me this year, doesn't narrow it down much) with this idea, but couldn't figure out who it was, so I wound up implementing my own.
Say you have, like most of us, a table with an "id INT IDENTITY PRIMARY KEY," so your PK is the ID, but the table also has a date column. Nobody cares about the date. Until they do, months later. So now you have a busy table that you can't easily add an index on, and an ADHOC OMGWTFBBQ project comes in, where you need to query a date range, and no idea how to get there quickly. .
*raises hand* Yup, that'd be me. So I wrote this.
What it does: cycle down through a table, using the ID column. Start by decrementing the max ID from the table by 10 million. Does that go below the date you need? Yes? Okay, try 1 million. Yes? 100k. No? How about 200k? Yes. 110k? No. 120k? Yes. 111k? No. 112k? Yes. 111100? (and so on).
It'll pop down even a terabyte table pretty quickly, since it only does a handful of queries, and they're all against the PK. Granted, I could make it faster by doing a (min+max)/2, then (newmin+max)/2 etc, but this works. I've nicknamed it "Zeno's Arrow", although technically my code doesn't go halfsies - but it is fast and direct.
Also, (importantly!) it may not cope with missing rows (which could happen due to stuff like, for instance, a failed transaction). I don't have a good fix for that, yet. Maybe in V2
Hope this helps.
Showing posts with label tips. Show all posts
Showing posts with label tips. Show all posts
Thursday, April 16, 2015
Friday, April 5, 2013
[tips] using OPENROWSET to avoid "An INSERT EXEC statement cannot be nested."
Found this, looks like from Paul Ibison (replicationanswers.com). In this case I _did_ need it for replication, but this could be useful whenever you are run into the error "An INSERT EXEC statement cannot be nested.".
One note - depending on how the original piece of code works, you may or may not need the SET FMTONLY OFF;. (In this case I do). If you do, be aware that the code is run TWICE. For this, it works fine, but keep it in mind.
USE eif_workspace
GO
create table dbo.repmonitor (
[status] int null,
warning int null ,
subscriber sysname null ,
subscriber_db sysname null ,
publisher_db sysname null ,
publication sysname null ,
publication_type int null ,
subtype int null ,
latency int null ,
latencythreshold int null ,
agentnotrunning int null ,
agentnotrunningthreshold int null ,
timetoexpiration int null ,
expirationthreshold int null ,
last_distsync datetime null ,
distribution_agentname sysname null ,
mergeagentname sysname null ,
mergesubscriptionfriendlyname sysname null ,
mergeagentlocation sysname null ,
mergeconnectiontype int null ,
mergePerformance int null ,
mergerunspeed float null ,
mergerunduration int null ,
monitorranking int null ,
distributionagentjobid binary(30) null ,
mergeagentjobid binary(30) null ,
distributionagentid int null ,
distributionagentprofileid int null ,
mergeagentid int null ,
mergeagentprofileid int null ,
logreaderagentname sysname null
)
go
Insert Into aud.dbo.repmonitor
SELECT *
FROM OPENROWSET('SQLNCLI', 'Server=yourservername;Trusted_Connection=yes', 'set fmtonly off; exec distribution..sp_replmonitorhelpsubscription @Publisher=@@servername,@publication_type=0')
One note - depending on how the original piece of code works, you may or may not need the SET FMTONLY OFF;. (In this case I do). If you do, be aware that the code is run TWICE. For this, it works fine, but keep it in mind.
USE eif_workspace
GO
create table dbo.repmonitor (
[status] int null,
warning int null ,
subscriber sysname null ,
subscriber_db sysname null ,
publisher_db sysname null ,
publication sysname null ,
publication_type int null ,
subtype int null ,
latency int null ,
latencythreshold int null ,
agentnotrunning int null ,
agentnotrunningthreshold int null ,
timetoexpiration int null ,
expirationthreshold int null ,
last_distsync datetime null ,
distribution_agentname sysname null ,
mergeagentname sysname null ,
mergesubscriptionfriendlyname sysname null ,
mergeagentlocation sysname null ,
mergeconnectiontype int null ,
mergePerformance int null ,
mergerunspeed float null ,
mergerunduration int null ,
monitorranking int null ,
distributionagentjobid binary(30) null ,
mergeagentjobid binary(30) null ,
distributionagentid int null ,
distributionagentprofileid int null ,
mergeagentid int null ,
mergeagentprofileid int null ,
logreaderagentname sysname null
)
go
Insert Into aud.dbo.repmonitor
SELECT *
FROM OPENROWSET('SQLNCLI', 'Server=yourservername;Trusted_Connection=yes', 'set fmtonly off; exec distribution..sp_replmonitorhelpsubscription @Publisher=@@servername,@publication_type=0')
Wednesday, June 11, 2008
[Linked Servers] Trick to making cross-server queries faster
Learned this years ago, and it's one of those nice tricks to keep in your cap.
So, what collation are you running? Do you know? Do you always use the default? Do you use linked servers and need a little more performance?
If you do, then you're in luck. If you have a linked server between two servers running the same collation, enable "collation compatible" and your queries will run faster.
Why? As I remember, if you don't have it enabled, then your query is sent across without the WHERE clause. Once it comes back, it's evaluated, ensuring that collation is properly dealt with. If you have collation compatible = true, then it sends over the whole query, including the WHERE clause. So, fewer results returned, lower I/O on the far-side, and no processing required locally.
One thing, though - make sure you're on the same collation. On 2005, the default is still the same (IIRC), but what it's called has changed.
So, what collation are you running? Do you know? Do you always use the default? Do you use linked servers and need a little more performance?
If you do, then you're in luck. If you have a linked server between two servers running the same collation, enable "collation compatible" and your queries will run faster.
Why? As I remember, if you don't have it enabled, then your query is sent across without the WHERE clause. Once it comes back, it's evaluated, ensuring that collation is properly dealt with. If you have collation compatible = true, then it sends over the whole query, including the WHERE clause. So, fewer results returned, lower I/O on the far-side, and no processing required locally.
One thing, though - make sure you're on the same collation. On 2005, the default is still the same (IIRC), but what it's called has changed.
Subscribe to:
Posts (Atom)