At least in PostgreSQL it is much faster to do a left or right join on st_intersects instead and use
"where id is null"
to find those that "don't have a friend"
edit:
Ok, here comes an example tested in SQL Server 2014 express:
There is 2 polygons and 4 points. 2 of them is inside the one of the polygons and oine point on the border of the other polygon. By doing a right join we get back all points, but only those inside a polygon gets a polygon id. So we filter away all points that gets a polygon id and left is the points outside all polygons. In this case only one, point(0 3)
This is, at least in PostGIS a fast way of doing it because the spatial index is used on the intersects operation.
with polygons as
(
select 'p1' id , geometry::STGeomFromText('polygon ((1 1, 1 5, 5 5, 1 1))', 0) poly
union all
select 'p2' id , geometry::STGeomFromText('polygon ((0 0, 1 1, 0 1, 0 0))', 0) poly
)
,
points as
(
select 1 id, geometry::STGeomFromText('point (0 0)', 0) P
union all
select 2 id, geometry::STGeomFromText('point (3 4)', 0) P
union all
select 3 id, geometry::STGeomFromText('point (2 3)', 0) P
union all
select 4 id, geometry::STGeomFromText('point (0 3)', 0) P
)
select points.id, points.p.STAsText()
from polygons
right join
points
on polygons.poly.STIntersects(points.p) = 1
where polygons.id is NULL;