Search Results

Search found 5831 results on 234 pages for 'chuck final'.

Page 44/234 | < Previous Page | 40 41 42 43 44 45 46 47 48 49 50 51  | Next Page >

  • Generate a Constant expression from a function

    - by Lee
    For my Google Wave robot, on the onDocumentChanged event I want to apply a filter as follows: @Capability(filter = FILTER) @Override public void onDocumentChanged(DocumentChangedEvent event) { ... } I want the filter to be generated the first time the robot is run, which I'm trying to do as follows: private static final String FILTER = generateFilter(); private static final String generateFilter(){ ... } However, it complains FILTER isn't a constant expression when used within @Capability. generateFilter() will return the same string every time it is called, I'm only using it to create the string so that when I make changes, I don't need to worry about updating the filter. Now I could be going about this all wrong, so wondered if anyone knew what I'm doing wrong, or knew a better way in which I could generate a constant expression from the function.

    Read the article

  • SwingWorker exceptions lost even when using wrapper classes

    - by Ti Strga
    I've been struggling with the usability problem of SwingWorker eating any exceptions thrown in the background task, for example, described on this SO thread. That thread gives a nice description of the problem, but doesn't discuss recovering the original exception. The applet I've been handed needs to propagate the exception upwards. But I haven't been able to even catch it. I'm using the SimpleSwingWorker wrapper class from this blog entry specifically to try and address this issue. It's a fairly small class but I'll repost it at the end here just for reference. The calling code looks broadly like try { // lots of code here to prepare data, finishing with SpecialDataHelper helper = new SpecialDataHelper(...stuff...); helper.execute(); } catch (Throwable e) { // used "Throwable" here in desperation to try and get // anything at all to match, including unchecked exceptions // // no luck, this code is never ever used :-( } The wrappers: class SpecialDataHelper extends SimpleSwingWorker { public SpecialDataHelper (SpecialData sd) { this.stuff = etc etc etc; } public Void doInBackground() throws Exception { OurCodeThatThrowsACheckedException(this.stuff); return null; } protected void done() { // called only when successful // never reached if there's an error } } The feature of SimpleSwingWorker is that the actual SwingWorker's done()/get() methods are automatically called. This, in theory, rethrows any exceptions that happened in the background. In practice, nothing is ever caught, and I don't even know why. The SimpleSwingWorker class, for reference, and with nothing elided for brevity: import java.util.concurrent.ExecutionException; import javax.swing.SwingWorker; /** * A drop-in replacement for SwingWorker<Void,Void> but will not silently * swallow exceptions during background execution. * * Taken from http://jonathangiles.net/blog/?p=341 with thanks. */ public abstract class SimpleSwingWorker { private final SwingWorker<Void,Void> worker = new SwingWorker<Void,Void>() { @Override protected Void doInBackground() throws Exception { SimpleSwingWorker.this.doInBackground(); return null; } @Override protected void done() { // Exceptions are lost unless get() is called on the // originating thread. We do so here. try { get(); } catch (final InterruptedException ex) { throw new RuntimeException(ex); } catch (final ExecutionException ex) { throw new RuntimeException(ex.getCause()); } SimpleSwingWorker.this.done(); } }; public SimpleSwingWorker() {} protected abstract Void doInBackground() throws Exception; protected abstract void done(); public void execute() { worker.execute(); } }

    Read the article

  • Which type of data can be garbage collected when app is in background?

    - by Neoh
    Let's say I start from activity A - activity B. While in activity B I press home to exit. After a long time, gc may be called because other apps take higher priority. My question is, which of the following type of data will be garbage collected (I'm pretty sure static fields can be garbage collected any time but I'm not sure about these): i) fields that are declared final or static final ii) intent and its data that I passed from activity A to activity B iii) onSavedInstanceState when orientation is changed during the app running I ask this because I want to ensure that my app won't crash when I restore activity B from background after a long period.

    Read the article

  • Thread class closing from other Class (Activity) with protected void onStop() Android

    - by user1761337
    I have a Problem with Closing the Thread. I will Closing the Thread with onStop,onPause and onDestroy. This is my Source in the Activity Class: @Override protected void onStop(){ super.onStop(); finish(); } @Override protected void onPause() { super.onPause(); finish(); } @Override public void onDestroy() { this.mWakeLock.release(); super.onDestroy(); } And the Thread Class: public class GameThread extends Thread { private SurfaceHolder mSurfaceHolder; private Handler mHandler; private Context mContext; private Paint mLinePaint; private Paint blackPaint; //for consistent rendering private long sleepTime; //amount of time to sleep for (in milliseconds) private long delay=1000/30; //state of game (Running or Paused). int state = 1; public final static int RUNNING = 1; public final static int PAUSED = 2; public final static int STOPED = 3; GameSurface gEngine; public GameThread(SurfaceHolder surfaceHolder, Context context, Handler handler,GameSurface gEngineS){ //data about the screen mSurfaceHolder = surfaceHolder; mHandler = handler; mContext = context; gEngine=gEngineS; } //This is the most important part of the code. It is invoked when the call to start() is //made from the SurfaceView class. It loops continuously until the game is finished or //the application is suspended. private long beforeTime; @Override public void run() { //UPDATE while (state==RUNNING) { Log.d("State","Thread is runnig"); //time before update beforeTime = System.nanoTime(); //This is where we update the game engine gEngine.Update(); //DRAW Canvas c = null; try { //lock canvas so nothing else can use it c = mSurfaceHolder.lockCanvas(null); synchronized (mSurfaceHolder) { //clear the screen with the black painter. //reset the canvas c.drawColor(Color.BLACK); //This is where we draw the game engine. gEngine.doDraw(c); } } finally { // do this in a finally so that if an exception is thrown // during the above, we don't leave the Surface in an // inconsistent state if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } this.sleepTime = delay-((System.nanoTime()-beforeTime)/1000000L); try { //actual sleep code if(sleepTime>0){ this.sleep(sleepTime); } } catch (InterruptedException ex) { Logger.getLogger(GameThread.class.getName()).log(Level.SEVERE, null, ex); } while (state==PAUSED){ Log.d("State","Thread is pausing"); try { this.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }} How i can close the Thread from Activity Class??

    Read the article

  • How do i generate thumbnail image for use with img tag ? Java web application.

    - by Nitesh Panchal
    Hello, I am using the below given code, but it is not working properly. Can anybody tell me how do i generate thumbnail of the image? because i am creating a photo album and i want only thumbnail images to be downloaded at first, not the entire 400-500 kb images. File objFile = new File(strImageFullPath); File targetFile = new File(strImageFullPathWithoutExt + "_small" + strFileExtension); Image image = ImageIO.read(objFile); final int WIDTH = 150; final int HEIGHT = 150; Image thumbnailImage = image.getScaledInstance(WIDTH, HEIGHT, Image.SCALE_DEFAULT); BufferedImage objThumbnailBufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics gfx = objThumbnailBufferedImage.getGraphics(); gfx.drawImage(image, 0, 0, null); gfx.dispose(); ImageIO.write(objThumbnailBufferedImage, strFileExtension.substring(1), targetFile); Just assume that few variables like strImageFullPath,strImageFullPathWithoutExt etc they exist. Thanks in advance :)

    Read the article

  • parsing position files in ruby

    - by john
    I have a sample position file like below. 789754654 COLORA SOMETHING1 19370119FYY076 2342423234SS323423 742784897 COLORB SOMETHING2 20060722FYY076 2342342342SDFSD3423 I am interested in positions 54-61 (4th column). I want to change the date to be a different format. So final outcome will be: 789754654 COLORA SOMETHING1 01191937FYY076 2342423234SS323423 742784897 COLORB SOMETHING2 07222006FYY076 2342342342SDFSD3423 The columns are seperated by spaces not tabs. And the final file should have exact number of spaces as the original file....only thing changing should be the date format. How can I do this? I wrote a script but it will lose the original spaces and positioning will be messed up. file.each_line do |line| dob = line.split(" ") puts dob[3] #got the date. change its format 5.times { puts "**" } end Can anyone suggest a better strategy so that positioning in the original file remains the same?

    Read the article

  • Android: Referring to a string resource when defining a log name

    - by spookypeanut
    In my Android app, I want to use a single variable for the log name in multiple files. At the moment, I'm specifying it separately in each file, e.g. public final String LOG_NAME = "LogName"; Log.d(LOG_NAME, "Logged output); I've tried this: public final String LOG_NAME = (String) getText(R.string.app_name_nospaces); And while this works in generally most of my files, Eclipse complains about one of them: The method getText(int) is undefined for the type DatabaseManager I've made sure I'm definitely importing android.content.Context in that file. If I tell it exactly where to find getText: Multiple markers at this line - Cannot make a static reference to the non-static method getText(int) from the type Context - The method getText(int) is undefined for the type DatabaseManager I'm sure I've committed a glaringly obvious n00b error, but I just can't see it! Thanks for all help: if any other code snippets would help, let me know.

    Read the article

  • android listview loadmore button with xml parsing

    - by user1780331
    Hi i have to developed listview with load more button using xml parsing in android application. Here i have faced some problem. my xml feed is empty means how can hide the load more button on last page. i have used below code here. public class CustomizedListView extends Activity { // All static variables private String URL = "http://dev.mmm.com/xctesting/xcart444pro/retrieve.php?page=1"; // XML node keys static final String KEY_SONG = "Order"; static final String KEY_TITLE = "orderid"; static final String KEY_DATE = "date"; static final String KEY_ARTIST = "payment_method"; int current_page = 1; ListView lv; LazyAdapter adapter; ProgressDialog pDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView) findViewById(R.id.list); ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>(); XMLParser parser = new XMLParser(); String xml = parser.getXmlFromUrl(URL); // getting XML from URL Document doc = parser.getDomElement(xml); // getting DOM element NodeList nl = doc.getElementsByTagName(KEY_SONG); // looping through all song nodes <song> for (int i = 0; i < nl.getLength(); i++) { // creating new HashMap HashMap<String, String> map = new HashMap<String, String>(); Element e = (Element) nl.item(i); // adding each child node to HashMap key => value map.put(KEY_ID, parser.getValue(e, KEY_ID)); map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE)); map.put(KEY_ARTIST, parser.getValue(e, KEY_ARTIST)); songsList.add(map); } Button btnLoadMore = new Button(this); btnLoadMore.setText("Load More"); btnLoadMore.setBackgroundResource(R.drawable.lgnbttn); // Adding Load More button to lisview at bottom lv.addFooterView(btnLoadMore); // Getting adapter adapter = new LazyAdapter(this, songsList); lv.setAdapter(adapter); btnLoadMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // Starting a new async task new loadMoreListView().execute(); } }); } private class loadMoreListView extends AsyncTask<Void, Void, Void> { @Override protected void onPreExecute() { // Showing progress dialog before sending http request pDialog = new ProgressDialog( CustomizedListView.this); pDialog.setMessage("Please wait.."); //pDialog.setIndeterminateDrawable(getResources().getDrawable(R.drawable.my_progress_indeterminate)); pDialog.setIndeterminate(true); pDialog.setCancelable(false); pDialog.show(); pDialog.setContentView(R.layout.custom_dialog); } protected Void doInBackground(Void... unused) { current_page += 1; // Next page request URL = "http://dev.mmm.com/xctesting/xcart444pro/retrieve.php?page=" + current_page; ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>(); XMLParser parser = new XMLParser(); String xml = parser.getXmlFromUrl(URL); // getting XML from URL Document doc = parser.getDomElement(xml); // getting DOM element NodeList nl = doc.getElementsByTagName(KEY_SONG); NodeList nl = doc.getElementsByTagName(KEY_SONG); if (nl.getLength() == 0) { btnLoadMore.setVisibility(View.GONE); pDialog.dismiss(); } else // looping through all item nodes <item> for (int i = 0; i < nl.getLength(); i++) { // creating new HashMap HashMap<String, String> map = new HashMap<String, String>(); Element e = (Element) nl.item(i); // adding each child node to HashMap key => value map.put(KEY_ID, parser.getValue(e, KEY_ID)); map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE)); map.put(KEY_ARTIST, parser.getValue(e, KEY_ARTIST)); songsList.add(map); } // get listview current position - used to maintain scroll position int currentPosition = lv.getFirstVisiblePosition(); // Appending new data to menuItems ArrayList adapter = new LazyAdapter( CustomizedListView.this, songsList); lv.setAdapter(adapter); lv.setSelectionFromTop(currentPosition + 1, 0); } }); return (null); } protected void onPostExecute(Void unused) { // closing progress dialog pDialog.dismiss(); } } } EDIT: Here i have to run the app means the listview is displayed on perpage 4 items.my last page having 1 item.please refer this screenshot:http://screencast.com/t/fTl4FETd In last page i have to click the load more button means have to go next activity and successfully hide the button on empty page..please refer this screenshot:http://screencast.com/t/wyG5zdp3r i have to check the condition for empty page: if (nl.getLength() == 0) { btnLoadMore.setVisibility(View.GONE); pDialog.dismiss(); } How can i write the conditon fot last page?????pleas ehelp me Here i wish to need the o/p is hide the button on last page. Please help me.how can i check the condition.give me some code programmatically.

    Read the article

  • Affine Transforms with Demo App

    - by Dex
    I have a demo app here https://github.com/rdetert/image-transform-test After importing an image, you can pinch, zoom, rotate the image. What I want to do is save out a 640x480 image (landscape mode) that looks identical to the live preview. So if there are 100px bars of empty space on the sides, I need the same empty bars in the final output (scaled appropriately). This is proving to be more difficult than I thought it would be. I can't quite get it to come out right after days of working on it. The magic method that generates the final image is called -(void)generateFinalImage Good luck! ;)

    Read the article

  • How to make a recursive onClickListener for expanding and collapsing?

    - by hunterp
    In plain english, I have a textview, and when I click on it I want it to expand, and when I click on it again, I want it to compress. How can I do this? I've tried the below, but it warns on the final line about expander might not be initialized on holderFinal.text.setOnClickListener(expander); So now the code: final View.OnClickListener expander = new View.OnClickListener() { @Override public void onClick(View v) { holderFinal.text.setText(textData); holderFinal.text.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { holderFinal.text.setText(shortText); holderFinal.text.setOnClickListener(expander); } }); } };

    Read the article

  • Why is it possible to save entity but not delete if transactional annotation is set to readonly=true

    - by jakob
    Hello experts! My class is annotated with org.springframework.transaction.annotation.Transactional like this: @Transactional(readOnly = true) public class MyClass { I then have a dao class: @Override public void delete(final E entity) { getSession().delete(entity); } @Override public void save(final E entity) { getSession().saveOrUpdate(entity); } Then I have two methods in MyClass @Transactional(readOnly = false) public void doDelete(Entity entity){ daoImpl.delete(entity) } //@Transactional(readOnly = false) public void doSave(){ daoImpl.save(entity) } Saving and deleting works like a charm. But if I remove the @Transactional(readOnly = false) on doDelete method deletion stops working, Saving works with and without the method annotation. So my question is: WHY?

    Read the article

  • How to create a Link that supplies its own Markup?

    - by Aranian
    I'm trying to create a link that will hide or show a part of my page. The link should be reusable and display one of two images, depending on state. Adding the two subcomponents on every page where I use the link is kind of clunky so I wanted to create a component that behaves like a link while automatically adding its content. This is the Link component: public class ToggleVisibilityLink extends AjaxFallbackLink<Boolean> { public ToggleVisibilityLink(final String id, final IModel<Boolean> model) { super(id, model); setOutputMarkupId(true); add(new Image("collapseImage") { @Override public boolean isVisible() { return !getModelObject(); } }); add(new Image("expandImage") { @Override public boolean isVisible() { return getModelObject(); } }); } @Override public void onClick(final AjaxRequestTarget target) { setModelObject(!getModelObject()); if (target != null) { target.add(this); send(this.getParent(), Broadcast.EXACT, target); } } } And this is how I currently use it in HTML (this is added to the page or panel where I use the link): <a href="#" wicket:id="collapseExpandLink" class="collapseExpandLink"> <wicket:link> <img src="collapse.png" wicket:id="collapseImage" class="collapseExpandImage collapse"> </wicket:link> <wicket:link> <img src="expand.png" wicket:id="expandImage" class="collapseExpandImage expand"> </wicket:link> </a> And the corresponding Java call: add(new ToggleVisibilityLink("collapseExpandLink", new PropertyModel(this, "hidden"))); But I want to be able to skip the body inside the link as one would have to know about the internals of ToggleVisibilityLink. I experimented with IMarkupResourceStreamProvider, using Dynamic markup in Wicket as a starting point. By googling I found another example where the poster was only able to get that to work when using a Panel, and I was able to do that as well. But I'd really like to keep the link and not package it inside a Panel, as I would not be able to style the link in the markup. I'm also open to alternatives to encapsulate the link and its body.

    Read the article

  • How do I get the IPv4 subnetmask on interface with both v4 and v6 address?

    - by Per Fagrell
    I have an InterfaceAddress that returns an ipv4 address (4 octets). However the network prefix length seems to be for the ipv6 address associated with the interface (it's returning as 128). How do I find the correct network prefix length? Enumeration<NetworkInterface> NetworkInterface.getNetworkInterfaces() for (; interfaces.hasMoreElements();) { final List<InterfaceAddress>interfaceAddresses = interfaces.nextElement().getInterfaceAddresses(); for (final InterfaceAddress address : interfaceAddresses) { assert(address.getAddress().getAddress().length == 4); // [sic] assert(address.getNetworkPrefixLength() < 32); // <- Fails. Actually equals 128 } }

    Read the article

  • code setOnClickListener for multiple TextViews

    - by user2870583
    I have 40+ TextViews and I want to add click events on them, but I try to do it "shortly" : final GridLayout myGL; myGL = (GridLayout) v0725.findViewById( R.id.tab1 ); for( int i = 0; i < myGL.getChildCount(); i++ ) if ( getResources().getResourceEntryName(((TextView) myGL.getChildAt(i)).getId()).indexOf("v")==0 ) { ((TextView) myGL.getChildAt(i)).setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Log.v("edf", getResources().getResourceEntryName(((TextView) myGL.getChildAt(i)).getId())); } }); }; But Eclipse stops me on the Log.v line, because i should be final (but I can't) any tips?

    Read the article

  • Is Java class initialized by the thread which use it for the first time?

    - by oo_olo_oo
    Lets assume following classes definition: public class A { public final static String SOME_VALUE; static { SOME_VALUE = "some.value"; } } public class B { private final String value = A.SOME_VALUE; } Assuming that the class A hasn't been loaded yet, what does happen when object of the class B is instantiated by some thread T? The class A has to be loaded and instantiated first. But my question is: if it's done in context of the thread T, or rather in context of some other (special) "classloader" thread?

    Read the article

  • How do I achieve lossless JPEG joining without truncation of partial MCUs?

    - by Karan
    I am working on a project for which I need to join thousands of JPEG images losslessly (I'm not talking about the Lossless JPEG/JPEG 2000/JPEG-LS formats here). Aforementioned images have varying levels of chroma subsampling (1x1, 1x2, 2x1, 2x2), resulting in varying MCU sizes (8x8, 8x16, 16x8, 16x16 px). However, in any given set of images to be joined together, each image has identical characteristics. For now, let's assume I only have 2 images. Image #1 (I1) is 256x256px in size and #2 (I2) is 239x256px in size. 2x2 subsampling is used such that MCU size is 16x16px. I2 thus obviously has partial MCUs at the right edge, since its width is not evenly divisible by 16. (I've read that so-called 'partial' MCUs actually contain the data for a complete MCU, but the image dimensions instruct the renderer to only display the relevant pixels and ignore/hide the extra ones.) Looking around for tools that could help me accomplish this, I came across a modified version of JpegTran, that contains an experimental lossless crop 'n' drop (cut & paste) feature. All the other apps I encountered that support lossless JPEG editing seem to utilise IJG's (JpegTran) code, so this seemed to be the logical choice. Also, given the sheer number of images, I wanted something that could preferably be run from the command-line so that I could automate the process with a script. Unfortunately, while everything else worked fine, it seems JpegTran truncates the partial MCUs instead of retaining them. Thus in the example above, the final joined image contains all of I1, but only 224x256px of I2. Why 224? because 239 = 14x16+15, which means there are 14 full MCUs along the width, and 1 partial MCU (just 1px short of the complete 16px). The last 15px is what is getting blanked, leading to a 495x256px image with 15px of blank (grey) pixels at the right edge. See images below (shame that imgur re-compresses them): (left )+ (right) = As you can clearly see, the red portion (15px) of I2 has been truncated by JpegTran. If the MCUs were 8px in width, the lost portion would have been the right-most 7px of I2. Similarly, joining I3 (256x239px) *below * I1 would cause the loss of 7 or 15px, depending on the MCU height of course: (top) + (bottom) = If this is better suited to some other StackExchange (or even non-SE) site/forum where JPEG/image encoding experts hang out, do let me know. Can what I am attempting even be done, or is the so-called 'lossless' JPEG crop 'n' drop only valid for images with no partial MCUs? (Maybe that is why the feature is still in an "experimental state" more than a decade after being introduced...) Until I know for sure that it is impossible, I am not interested in suggestions for lossy joining. Avoiding any generational loss whatsoever is the sole reason why I'm breaking my head over this, else I'd have had this done and dusted ages ago. Also, I am not interested in suggestions related to switching image formats. I do not control the source of the images. If it can be done, how? Please keep in mind that any alternate apps suggested must ideally be capable of automation, given the requirements stated above. (But given how it's unlikely I'm even going to receive a useful answer given the constraints, I would be happy with any app suggestion just as long as it actually works. I can always look into an AutoIT/AHK script or something later to automate it.) I understand that an odd-sized final image might cause issues, so I am fully prepared to accept any solution, even if it results in blank (preferably black) padding pixels to the right/bottom. What I mean is, I don't care if I1 + I2 is 496x256px (1px padding) or even 512x256px (17px padding) in size, as long as the final image contains all the actual image data from both source images, and the entire process is lossless. Obviously the lesser the padding (if any), the better, but at this point any solution will do. A Windows-based solution would be perfect, but a Linux-based one would be entirely acceptable.

    Read the article

  • ASP.NET MVC 2 Released

    - by Latest Microsoft Blogs
    I’m happy to announce that the final release of ASP.NET MVC 2 is now available for VS 2008/Visual Web Developer 2008 Express with ASP.NET 3.5.  You can download and install it from the following locations: Download ASP.NET MVC 2 using the Microsoft Read More......(read more)

    Read the article

  • Now Customers Can Actually Locate Your Resources with URL Rewriter 2.0 RTW

    - by The Official Microsoft IIS Site
    Today, Microsoft announced the final release of IIS URL Rewriter 2.0 RTW . Now the first reason might be obvious why you would want to rewrite a URL – when you are at a cocktail party with loud music and tasty appetizers and a potential customer asks you where they can get more info on your snazzy new idea. And you proudly blurt out next to their ear over the roar of the bass, “Just go to h-t-t-p colon slash slash w-w-w dot my new idea dot com slash items dot a-s-p-x question mark cat ID equals new...(read more)

    Read the article

  • Silverlight 4 Released

    - by Latest Microsoft Blogs
    The final release of Silverlight 4 is now available. [In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu ] What is in the Silverlight 4 Release Silverlight 4 contains a ton of new Read More......(read more)

    Read the article

  • Improving Partitioned Table Join Performance

    - by Paul White
    The query optimizer does not always choose an optimal strategy when joining partitioned tables. This post looks at an example, showing how a manual rewrite of the query can almost double performance, while reducing the memory grant to almost nothing. Test Data The two tables in this example use a common partitioning partition scheme. The partition function uses 41 equal-size partitions: CREATE PARTITION FUNCTION PFT (integer) AS RANGE RIGHT FOR VALUES ( 125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000, 1125000, 1250000, 1375000, 1500000, 1625000, 1750000, 1875000, 2000000, 2125000, 2250000, 2375000, 2500000, 2625000, 2750000, 2875000, 3000000, 3125000, 3250000, 3375000, 3500000, 3625000, 3750000, 3875000, 4000000, 4125000, 4250000, 4375000, 4500000, 4625000, 4750000, 4875000, 5000000 ); GO CREATE PARTITION SCHEME PST AS PARTITION PFT ALL TO ([PRIMARY]); There two tables are: CREATE TABLE dbo.T1 ( TID integer NOT NULL IDENTITY(0,1), Column1 integer NOT NULL, Padding binary(100) NOT NULL DEFAULT 0x,   CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED (TID) ON PST (TID) );   CREATE TABLE dbo.T2 ( TID integer NOT NULL, Column1 integer NOT NULL, Padding binary(100) NOT NULL DEFAULT 0x,   CONSTRAINT PK_T2 PRIMARY KEY CLUSTERED (TID, Column1) ON PST (TID) ); The next script loads 5 million rows into T1 with a pseudo-random value between 1 and 5 for Column1. The table is partitioned on the IDENTITY column TID: INSERT dbo.T1 WITH (TABLOCKX) (Column1) SELECT (ABS(CHECKSUM(NEWID())) % 5) + 1 FROM dbo.Numbers AS N WHERE n BETWEEN 1 AND 5000000; In case you don’t already have an auxiliary table of numbers lying around, here’s a script to create one with 10 million rows: CREATE TABLE dbo.Numbers (n bigint PRIMARY KEY);   WITH L0 AS(SELECT 1 AS c UNION ALL SELECT 1), L1 AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B), L2 AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B), L3 AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B), L4 AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B), L5 AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B), Nums AS(SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM L5) INSERT dbo.Numbers WITH (TABLOCKX) SELECT TOP (10000000) n FROM Nums ORDER BY n OPTION (MAXDOP 1); Table T1 contains data like this: Next we load data into table T2. The relationship between the two tables is that table 2 contains ‘n’ rows for each row in table 1, where ‘n’ is determined by the value in Column1 of table T1. There is nothing particularly special about the data or distribution, by the way. INSERT dbo.T2 WITH (TABLOCKX) (TID, Column1) SELECT T.TID, N.n FROM dbo.T1 AS T JOIN dbo.Numbers AS N ON N.n >= 1 AND N.n <= T.Column1; Table T2 ends up containing about 15 million rows: The primary key for table T2 is a combination of TID and Column1. The data is partitioned according to the value in column TID alone. Partition Distribution The following query shows the number of rows in each partition of table T1: SELECT PartitionID = CA1.P, NumRows = COUNT_BIG(*) FROM dbo.T1 AS T CROSS APPLY (VALUES ($PARTITION.PFT(TID))) AS CA1 (P) GROUP BY CA1.P ORDER BY CA1.P; There are 40 partitions containing 125,000 rows (40 * 125k = 5m rows). The rightmost partition remains empty. The next query shows the distribution for table 2: SELECT PartitionID = CA1.P, NumRows = COUNT_BIG(*) FROM dbo.T2 AS T CROSS APPLY (VALUES ($PARTITION.PFT(TID))) AS CA1 (P) GROUP BY CA1.P ORDER BY CA1.P; There are roughly 375,000 rows in each partition (the rightmost partition is also empty): Ok, that’s the test data done. Test Query and Execution Plan The task is to count the rows resulting from joining tables 1 and 2 on the TID column: SET STATISTICS IO ON; DECLARE @s datetime2 = SYSUTCDATETIME();   SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID;   SELECT DATEDIFF(Millisecond, @s, SYSUTCDATETIME()); SET STATISTICS IO OFF; The optimizer chooses a plan using parallel hash join, and partial aggregation: The Plan Explorer plan tree view shows accurate cardinality estimates and an even distribution of rows across threads (click to enlarge the image): With a warm data cache, the STATISTICS IO output shows that no physical I/O was needed, and all 41 partitions were touched: Running the query without actual execution plan or STATISTICS IO information for maximum performance, the query returns in around 2600ms. Execution Plan Analysis The first step toward improving on the execution plan produced by the query optimizer is to understand how it works, at least in outline. The two parallel Clustered Index Scans use multiple threads to read rows from tables T1 and T2. Parallel scan uses a demand-based scheme where threads are given page(s) to scan from the table as needed. This arrangement has certain important advantages, but does result in an unpredictable distribution of rows amongst threads. The point is that multiple threads cooperate to scan the whole table, but it is impossible to predict which rows end up on which threads. For correct results from the parallel hash join, the execution plan has to ensure that rows from T1 and T2 that might join are processed on the same thread. For example, if a row from T1 with join key value ‘1234’ is placed in thread 5’s hash table, the execution plan must guarantee that any rows from T2 that also have join key value ‘1234’ probe thread 5’s hash table for matches. The way this guarantee is enforced in this parallel hash join plan is by repartitioning rows to threads after each parallel scan. The two repartitioning exchanges route rows to threads using a hash function over the hash join keys. The two repartitioning exchanges use the same hash function so rows from T1 and T2 with the same join key must end up on the same hash join thread. Expensive Exchanges This business of repartitioning rows between threads can be very expensive, especially if a large number of rows is involved. The execution plan selected by the optimizer moves 5 million rows through one repartitioning exchange and around 15 million across the other. As a first step toward removing these exchanges, consider the execution plan selected by the optimizer if we join just one partition from each table, disallowing parallelism: SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = 1 AND $PARTITION.PFT(T2.TID) = 1 OPTION (MAXDOP 1); The optimizer has chosen a (one-to-many) merge join instead of a hash join. The single-partition query completes in around 100ms. If everything scaled linearly, we would expect that extending this strategy to all 40 populated partitions would result in an execution time around 4000ms. Using parallelism could reduce that further, perhaps to be competitive with the parallel hash join chosen by the optimizer. This raises a question. If the most efficient way to join one partition from each of the tables is to use a merge join, why does the optimizer not choose a merge join for the full query? Forcing a Merge Join Let’s force the optimizer to use a merge join on the test query using a hint: SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID OPTION (MERGE JOIN); This is the execution plan selected by the optimizer: This plan results in the same number of logical reads reported previously, but instead of 2600ms the query takes 5000ms. The natural explanation for this drop in performance is that the merge join plan is only using a single thread, whereas the parallel hash join plan could use multiple threads. Parallel Merge Join We can get a parallel merge join plan using the same query hint as before, and adding trace flag 8649: SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID OPTION (MERGE JOIN, QUERYTRACEON 8649); The execution plan is: This looks promising. It uses a similar strategy to distribute work across threads as seen for the parallel hash join. In practice though, performance is disappointing. On a typical run, the parallel merge plan runs for around 8400ms; slower than the single-threaded merge join plan (5000ms) and much worse than the 2600ms for the parallel hash join. We seem to be going backwards! The logical reads for the parallel merge are still exactly the same as before, with no physical IOs. The cardinality estimates and thread distribution are also still very good (click to enlarge): A big clue to the reason for the poor performance is shown in the wait statistics (captured by Plan Explorer Pro): CXPACKET waits require careful interpretation, and are most often benign, but in this case excessive waiting occurs at the repartitioning exchanges. Unlike the parallel hash join, the repartitioning exchanges in this plan are order-preserving ‘merging’ exchanges (because merge join requires ordered inputs): Parallelism works best when threads can just grab any available unit of work and get on with processing it. Preserving order introduces inter-thread dependencies that can easily lead to significant waits occurring. In extreme cases, these dependencies can result in an intra-query deadlock, though the details of that will have to wait for another time to explore in detail. The potential for waits and deadlocks leads the query optimizer to cost parallel merge join relatively highly, especially as the degree of parallelism (DOP) increases. This high costing resulted in the optimizer choosing a serial merge join rather than parallel in this case. The test results certainly confirm its reasoning. Collocated Joins In SQL Server 2008 and later, the optimizer has another available strategy when joining tables that share a common partition scheme. This strategy is a collocated join, also known as as a per-partition join. It can be applied in both serial and parallel execution plans, though it is limited to 2-way joins in the current optimizer. Whether the optimizer chooses a collocated join or not depends on cost estimation. The primary benefits of a collocated join are that it eliminates an exchange and requires less memory, as we will see next. Costing and Plan Selection The query optimizer did consider a collocated join for our original query, but it was rejected on cost grounds. The parallel hash join with repartitioning exchanges appeared to be a cheaper option. There is no query hint to force a collocated join, so we have to mess with the costing framework to produce one for our test query. Pretending that IOs cost 50 times more than usual is enough to convince the optimizer to use collocated join with our test query: -- Pretend IOs are 50x cost temporarily DBCC SETIOWEIGHT(50);   -- Co-located hash join SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID OPTION (RECOMPILE);   -- Reset IO costing DBCC SETIOWEIGHT(1); Collocated Join Plan The estimated execution plan for the collocated join is: The Constant Scan contains one row for each partition of the shared partitioning scheme, from 1 to 41. The hash repartitioning exchanges seen previously are replaced by a single Distribute Streams exchange using Demand partitioning. Demand partitioning means that the next partition id is given to the next parallel thread that asks for one. My test machine has eight logical processors, and all are available for SQL Server to use. As a result, there are eight threads in the single parallel branch in this plan, each processing one partition from each table at a time. Once a thread finishes processing a partition, it grabs a new partition number from the Distribute Streams exchange…and so on until all partitions have been processed. It is important to understand that the parallel scans in this plan are different from the parallel hash join plan. Although the scans have the same parallelism icon, tables T1 and T2 are not being co-operatively scanned by multiple threads in the same way. Each thread reads a single partition of T1 and performs a hash match join with the same partition from table T2. The properties of the two Clustered Index Scans show a Seek Predicate (unusual for a scan!) limiting the rows to a single partition: The crucial point is that the join between T1 and T2 is on TID, and TID is the partitioning column for both tables. A thread that processes partition ‘n’ is guaranteed to see all rows that can possibly join on TID for that partition. In addition, no other thread will see rows from that partition, so this removes the need for repartitioning exchanges. CPU and Memory Efficiency Improvements The collocated join has removed two expensive repartitioning exchanges and added a single exchange processing 41 rows (one for each partition id). Remember, the parallel hash join plan exchanges had to process 5 million and 15 million rows. The amount of processor time spent on exchanges will be much lower in the collocated join plan. In addition, the collocated join plan has a maximum of 8 threads processing single partitions at any one time. The 41 partitions will all be processed eventually, but a new partition is not started until a thread asks for it. Threads can reuse hash table memory for the new partition. The parallel hash join plan also had 8 hash tables, but with all 5,000,000 build rows loaded at the same time. The collocated plan needs memory for only 8 * 125,000 = 1,000,000 rows at any one time. Collocated Hash Join Performance The collated join plan has disappointing performance in this case. The query runs for around 25,300ms despite the same IO statistics as usual. This is much the worst result so far, so what went wrong? It turns out that cardinality estimation for the single partition scans of table T1 is slightly low. The properties of the Clustered Index Scan of T1 (graphic immediately above) show the estimation was for 121,951 rows. This is a small shortfall compared with the 125,000 rows actually encountered, but it was enough to cause the hash join to spill to physical tempdb: A level 1 spill doesn’t sound too bad, until you realize that the spill to tempdb probably occurs for each of the 41 partitions. As a side note, the cardinality estimation error is a little surprising because the system tables accurately show there are 125,000 rows in every partition of T1. Unfortunately, the optimizer uses regular column and index statistics to derive cardinality estimates here rather than system table information (e.g. sys.partitions). Collocated Merge Join We will never know how well the collocated parallel hash join plan might have worked without the cardinality estimation error (and the resulting 41 spills to tempdb) but we do know: Merge join does not require a memory grant; and Merge join was the optimizer’s preferred join option for a single partition join Putting this all together, what we would really like to see is the same collocated join strategy, but using merge join instead of hash join. Unfortunately, the current query optimizer cannot produce a collocated merge join; it only knows how to do collocated hash join. So where does this leave us? CROSS APPLY sys.partitions We can try to write our own collocated join query. We can use sys.partitions to find the partition numbers, and CROSS APPLY to get a count per partition, with a final step to sum the partial counts. The following query implements this idea: SELECT row_count = SUM(Subtotals.cnt) FROM ( -- Partition numbers SELECT p.partition_number FROM sys.partitions AS p WHERE p.[object_id] = OBJECT_ID(N'T1', N'U') AND p.index_id = 1 ) AS P CROSS APPLY ( -- Count per collocated join SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals; The estimated plan is: The cardinality estimates aren’t all that good here, especially the estimate for the scan of the system table underlying the sys.partitions view. Nevertheless, the plan shape is heading toward where we would like to be. Each partition number from the system table results in a per-partition scan of T1 and T2, a one-to-many Merge Join, and a Stream Aggregate to compute the partial counts. The final Stream Aggregate just sums the partial counts. Execution time for this query is around 3,500ms, with the same IO statistics as always. This compares favourably with 5,000ms for the serial plan produced by the optimizer with the OPTION (MERGE JOIN) hint. This is another case of the sum of the parts being less than the whole – summing 41 partial counts from 41 single-partition merge joins is faster than a single merge join and count over all partitions. Even so, this single-threaded collocated merge join is not as quick as the original parallel hash join plan, which executed in 2,600ms. On the positive side, our collocated merge join uses only one logical processor and requires no memory grant. The parallel hash join plan used 16 threads and reserved 569 MB of memory:   Using a Temporary Table Our collocated merge join plan should benefit from parallelism. The reason parallelism is not being used is that the query references a system table. We can work around that by writing the partition numbers to a temporary table (or table variable): SET STATISTICS IO ON; DECLARE @s datetime2 = SYSUTCDATETIME();   CREATE TABLE #P ( partition_number integer PRIMARY KEY);   INSERT #P (partition_number) SELECT p.partition_number FROM sys.partitions AS p WHERE p.[object_id] = OBJECT_ID(N'T1', N'U') AND p.index_id = 1;   SELECT row_count = SUM(Subtotals.cnt) FROM #P AS p CROSS APPLY ( SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals;   DROP TABLE #P;   SELECT DATEDIFF(Millisecond, @s, SYSUTCDATETIME()); SET STATISTICS IO OFF; Using the temporary table adds a few logical reads, but the overall execution time is still around 3500ms, indistinguishable from the same query without the temporary table. The problem is that the query optimizer still doesn’t choose a parallel plan for this query, though the removal of the system table reference means that it could if it chose to: In fact the optimizer did enter the parallel plan phase of query optimization (running search 1 for a second time): Unfortunately, the parallel plan found seemed to be more expensive than the serial plan. This is a crazy result, caused by the optimizer’s cost model not reducing operator CPU costs on the inner side of a nested loops join. Don’t get me started on that, we’ll be here all night. In this plan, everything expensive happens on the inner side of a nested loops join. Without a CPU cost reduction to compensate for the added cost of exchange operators, candidate parallel plans always look more expensive to the optimizer than the equivalent serial plan. Parallel Collocated Merge Join We can produce the desired parallel plan using trace flag 8649 again: SELECT row_count = SUM(Subtotals.cnt) FROM #P AS p CROSS APPLY ( SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals OPTION (QUERYTRACEON 8649); The actual execution plan is: One difference between this plan and the collocated hash join plan is that a Repartition Streams exchange operator is used instead of Distribute Streams. The effect is similar, though not quite identical. The Repartition uses round-robin partitioning, meaning the next partition id is pushed to the next thread in sequence. The Distribute Streams exchange seen earlier used Demand partitioning, meaning the next partition id is pulled across the exchange by the next thread that is ready for more work. There are subtle performance implications for each partitioning option, but going into that would again take us too far off the main point of this post. Performance The important thing is the performance of this parallel collocated merge join – just 1350ms on a typical run. The list below shows all the alternatives from this post (all timings include creation, population, and deletion of the temporary table where appropriate) from quickest to slowest: Collocated parallel merge join: 1350ms Parallel hash join: 2600ms Collocated serial merge join: 3500ms Serial merge join: 5000ms Parallel merge join: 8400ms Collated parallel hash join: 25,300ms (hash spill per partition) The parallel collocated merge join requires no memory grant (aside from a paltry 1.2MB used for exchange buffers). This plan uses 16 threads at DOP 8; but 8 of those are (rather pointlessly) allocated to the parallel scan of the temporary table. These are minor concerns, but it turns out there is a way to address them if it bothers you. Parallel Collocated Merge Join with Demand Partitioning This final tweak replaces the temporary table with a hard-coded list of partition ids (dynamic SQL could be used to generate this query from sys.partitions): SELECT row_count = SUM(Subtotals.cnt) FROM ( VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10), (11),(12),(13),(14),(15),(16),(17),(18),(19),(20), (21),(22),(23),(24),(25),(26),(27),(28),(29),(30), (31),(32),(33),(34),(35),(36),(37),(38),(39),(40),(41) ) AS P (partition_number) CROSS APPLY ( SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals OPTION (QUERYTRACEON 8649); The actual execution plan is: The parallel collocated hash join plan is reproduced below for comparison: The manual rewrite has another advantage that has not been mentioned so far: the partial counts (per partition) can be computed earlier than the partial counts (per thread) in the optimizer’s collocated join plan. The earlier aggregation is performed by the extra Stream Aggregate under the nested loops join. The performance of the parallel collocated merge join is unchanged at around 1350ms. Final Words It is a shame that the current query optimizer does not consider a collocated merge join (Connect item closed as Won’t Fix). The example used in this post showed an improvement in execution time from 2600ms to 1350ms using a modestly-sized data set and limited parallelism. In addition, the memory requirement for the query was almost completely eliminated  – down from 569MB to 1.2MB. The problem with the parallel hash join selected by the optimizer is that it attempts to process the full data set all at once (albeit using eight threads). It requires a large memory grant to hold all 5 million rows from table T1 across the eight hash tables, and does not take advantage of the divide-and-conquer opportunity offered by the common partitioning. The great thing about the collocated join strategies is that each parallel thread works on a single partition from both tables, reading rows, performing the join, and computing a per-partition subtotal, before moving on to a new partition. From a thread’s point of view… If you have trouble visualizing what is happening from just looking at the parallel collocated merge join execution plan, let’s look at it again, but from the point of view of just one thread operating between the two Parallelism (exchange) operators. Our thread picks up a single partition id from the Distribute Streams exchange, and starts a merge join using ordered rows from partition 1 of table T1 and partition 1 of table T2. By definition, this is all happening on a single thread. As rows join, they are added to a (per-partition) count in the Stream Aggregate immediately above the Merge Join. Eventually, either T1 (partition 1) or T2 (partition 1) runs out of rows and the merge join stops. The per-partition count from the aggregate passes on through the Nested Loops join to another Stream Aggregate, which is maintaining a per-thread subtotal. Our same thread now picks up a new partition id from the exchange (say it gets id 9 this time). The count in the per-partition aggregate is reset to zero, and the processing of partition 9 of both tables proceeds just as it did for partition 1, and on the same thread. Each thread picks up a single partition id and processes all the data for that partition, completely independently from other threads working on other partitions. One thread might eventually process partitions (1, 9, 17, 25, 33, 41) while another is concurrently processing partitions (2, 10, 18, 26, 34) and so on for the other six threads at DOP 8. The point is that all 8 threads can execute independently and concurrently, continuing to process new partitions until the wider job (of which the thread has no knowledge!) is done. This divide-and-conquer technique can be much more efficient than simply splitting the entire workload across eight threads all at once. Related Reading Understanding and Using Parallelism in SQL Server Parallel Execution Plans Suck © 2013 Paul White – All Rights Reserved Twitter: @SQL_Kiwi

    Read the article

  • ActAs and OnBehalfOf support in WIF

    - by cibrax
    I discussed a time ago how WIF supported a new WS-Trust 1.4 element, “ActAs”, and how that element could be used for authentication delegation.  The thing is that there is another feature in WS-Trust 1.4 that also becomes handy for this kind of scenario, and I did not mention in that last post, “OnBehalfOf”. Shiung Yong wrote an excellent summary about the difference of these two new features in this forum thread. He basically commented the following, “An ActAs RST element indicates that the requestor wants a token that contains claims about two distinct entities: the requestor, and an external entity represented by the token in the ActAs element. An OnBehalfOf RST element indicates that the requestor wants a token that contains claims only about one entity: the external entity represented by the token in the OnBehalfOf element. In short, ActAs feature is typically used in scenarios that require composite delegation, where the final recipient of the issued token can inspect the entire delegation chain and see not just the client, but all intermediaries to perform access control, auditing and other related activities based on the whole identity delegation chain. The ActAs feature is commonly used in multi-tiered systems to authenticate and pass information about identities between the tiers without having to pass this information at the application/business logic layer. OnBehalfOf feature is used in scenarios where only the identity of the original client is important and is effectively the same as identity impersonation feature available in the Windows OS today. When the OnBehalfOf is used the final recipient of the issued token can only see claims about the original client, and the information about intermediaries is not preserved. One common pattern where OnBehalfOf feature is used is the proxy pattern where the client cannot access the STS directly but is instead communicating through a proxy gateway. The proxy gateway authenticates the caller and puts information about him into the OnBehalfOf element of the RST message that it then sends to the real STS for processing. The resulting token is going to contain only claims related to the client of the proxy, making the proxy completely transparent and not visible to the receiver of the issued token.” Going back to WIF, “ActAs” and “OnBehalfOf” are both supported as extensions methods in the WCF client channel. public static class ChannelFactoryOperations {   public static T CreateChannelActingAs<T>(this ChannelFactory<T> factory,     SecurityToken actAs);     public static T CreateChannelOnBehalfOf<T>(this ChannelFactory<T> factory,     SecurityToken onBehalfOf); } Both methods receive the security token with the identity of the original caller.

    Read the article

  • NHibernate 2 Beginner's Guide Book

    - by Ricardo Peres
    Packt Publishing has recently released a new book on NHibernate: NHibernate 2 Beginner's Guide, by Aaron Cure. I am now reading the final version, which Packt Publishing was kind enough to provide me, and I will soon write about it. I can tell you for now that Fabio Maulo was one of the reviewers, which certainly raises the expectations. In the meanwhile, there's a free chapter you can download, which hopefully will get you interested in it; you can get it from here.

    Read the article

  • Leveraging Logical Standby Databases in Oracle 11g Data Guard

    Oracle Data Guard still offers support for the venerable logical standby database in Oracle Database 11g. This article, investigates how data warehouse and data mart environments can effectively leverage logical standby database features, but simultaneously provide a final destination when failover from a primary database is mandated during disaster recovery.

    Read the article

< Previous Page | 40 41 42 43 44 45 46 47 48 49 50 51  | Next Page >